21
\$\begingroup\$

Input a decimal number and round it to an integer, randomly rounding up or down with a probability based on its fractional part, so the expected value of the output equals to the input value.

If input \$x\$ is an integer, the program should output it as is. If \$x\$ is not an integer, the program has a \$x-\left\lfloor x \right\rfloor\$ probability to output \$\left\lceil x \right\rceil\$, and a \$\lceil x\rceil-x\$ probability to output \$\left\lfloor x \right\rfloor\$.

In the above formula, \$\left\lfloor i\right\rfloor\$ means rounding \$i\$ down to the nearest integer; \$\left\lceil i\right\rceil\$ means rounding \$i\$ up to the nearest integer.

Examples

  • For input 2.4, it has 60% probability to output 2, and 40% probability to output 3.
  • For input 3.9, it has 10% probability to output 3, and 90% probability to output 4.
  • For input 0.5, it has 50% probability to output 0, and 50% probability to output 1.
  • For input -5.25, it has 75% probability to output -5, and 25% probability to output -6.
  • For input 8, it has 100% probability to output 8, and 0% probability to output 7 or 9.

Rules

  • To make the challenge easier, reasonable errors in probability are allowed.
    • For any input \$-100<x<100\$, the probability error should be less than \$0.01\%\$.
  • You may assume your language's built-in random number generator is perfectly balanced.
  • You may assume the input / output value fits your languages decimal number types, as long as this does not trivialize the challenge.
  • As usual, this is . So shortest code wins.
\$\endgroup\$
3
  • \$\begingroup\$ What range of x should the program possibly handle? \$\endgroup\$
    – xiver77
    Mar 16 at 12:02
  • \$\begingroup\$ @xiver77 Any reasonable range that at least support -100 ~ +100 with 4 decimal places (so it meets the requirement of probability error). Typically 32 bit IEEE 754 float type in most languages should be enough. \$\endgroup\$
    – tsh
    Mar 16 at 12:26
  • 4
    \$\begingroup\$ Note: This question is about code-golf. Never use any code on this page in any rational works. For example, floor(input + randomFloat0To1()) could have a small probability output 9 for input 8 due to floating point errors. This is allowed in this question. But you would not want this happen in your real word codes. \$\endgroup\$
    – tsh
    Mar 16 at 13:17

26 Answers 26

13
\$\begingroup\$

APL(Dyalog Unicode), 6 bytes SBCS

⌊?⍤≡+⊢

Try it on APLgolf!

Add a random number in \$(0,1)\$ and floor.

\$\endgroup\$
9
\$\begingroup\$

R, 20 bytes

\(n)(n+runif(1))%/%1

Attempt This Online!

\$\endgroup\$
9
\$\begingroup\$

MathGolf, 4 3 bytes

ƒ-ü

Port of @ovs' APL answer.
-1 byte thanks to @nextwayup's 05AB1E answer by using \$ceil(input-random)\$ instead of \$floor(input+random)\$.
Make sure to upvote both of them as well!

Try it online.

Explanation:

ƒ    # Random float in the range [0,1]
 -   # Subtract this from the (implicit) input-float
  ü  # Ceil it to an integer
     # (after which the entire stack is output implicitly)
\$\endgroup\$
1
  • 1
    \$\begingroup\$ I can't help but read the code as f***-you due to the f-u visual simplification xD Bonus points for the gag, even if not intended! \$\endgroup\$ Mar 19 at 11:49
5
\$\begingroup\$

05AB1E, 12 11 9 bytes

-2 bytes thanks to Kevin Cruijssen

4°LΩ4°/-î

Try it online!

Does 05AB1E really not have a function for random(0,1)? Anyway, here's an answer.

Explanation:

4°L             # create list of length 10000 (Ždt = 10000)
   Ω            # choose an integer from the list
    4°/        # divide it by 10000 to get a random decimal number
       -       # subtract the random number from the input
        î      # round up
\$\endgroup\$
7
  • \$\begingroup\$ ∞Ždt∍ outputs 1...10000; so it have 1/10000 probability output 7 for input 8. This is allowed by the question so you don't need to change anything. \$\endgroup\$
    – tsh
    Mar 16 at 13:04
  • \$\begingroup\$ Yeah i think i should be all right there. I was able to save a byte by using the built-in list creator, which i knew was there somewhere but forgot the command for it :P \$\endgroup\$
    – nextwayup
    Mar 16 at 13:11
  • 1
    \$\begingroup\$ 05AB1E indeed lacks a random float builtin, which is pretty annoying sometimes.. :/ But you can golf the ∞Ždt∍ to simply 4°L or тnL, and the second Ždt can be or тn as well. \$\endgroup\$ Mar 16 at 13:11
  • 1
    \$\begingroup\$ ...or тnDLΩs/-î or 4°DLΩs/-î. \$\endgroup\$ Mar 16 at 13:14
  • 1
    \$\begingroup\$ @KevinCruijssen thanks, as you can tell i'm still learning but I'm learning new methods every day ;) \$\endgroup\$
    – nextwayup
    Mar 16 at 13:18
5
\$\begingroup\$

Lua, 36 29 bytes

-7 thanks to @Sisyphus

print((...+math.random())//1)

Attempt This Online! Adds a random float between 0 and 1 to the input and then floors.

execute

Attempt This Online! (36 byte version)

insert furious clicking of the execute button

\$\endgroup\$
3
  • 1
    \$\begingroup\$ I think print((...+math.random())//1) works \$\endgroup\$
    – Sisyphus
    Mar 16 at 23:24
  • \$\begingroup\$ ur a pro at lua! surprisingly very people actually use it (apart from you of course) \$\endgroup\$
    – DialFrost
    Mar 16 at 23:40
  • \$\begingroup\$ @Sisyphus didn't know that // existed in Lua. Thanks! \$\endgroup\$
    – twentysix
    Mar 17 at 11:53
5
\$\begingroup\$

x86 machine code (32-bit), 18 9 bytes

0F C7 F1 39 D1 83 D0 00 C3

Saved 9 bytes. Thanks to Peter Cordes.

Disassembly

0:  0f c7 f1                rdrand ecx
3:  39 d1                   cmp    ecx,edx
5:  83 d0 00                adc    eax,0x0
8:  c3                      ret

Explanation

The function has the same behavior as randRound in the following C code.

#include <stdint.h>

static uint32_t rand_u32() {
    uint32_t r;
    __asm__ ("rdrand\t%0" : "=r"(r));
    return r;
}

__attribute__((regparm(3)))
int32_t randRound(uint32_t hi, uint32_t lo) {
    return hi + (rand_u32() < lo);
}

rdrand reads the hardware random number generator. The Intel manual states the validity of its result should be checked through the carry flag, but according to Peter Cordes, rdrand never fails on Ivy Bridge, so this code is always valid on Ivy Bridge, and mostly valid on other machines.

The single statement in randRound is all of the algorithm, but I have to explain how the data is represented.

Each fractional number is encoded in 64 bits. The high 32 bits is the integral part and the low 32 bits is the fractional part. The following list shows how each hex value is decoded to an actual value.

0000 0000 0000 0000 -> 0
7fff ffff 0000 0000 -> 0x7fff'ffff
8000 0000 0000 0000 -> -0x8000'0000
ffff ffff 0000 0000 -> -1
0000 0001 0000 0001 -> 1 + 1 / 0x1'0000'0000
ffff ffff 0000 0001 -> -1 + 1 / 0x1'0000'0000
ffff ffff ffff ffff -> -1 + 0xffff'ffff / 0x1'0000'0000

Such representation is common in fixed point arithmetic because the basic operations are very cheap. Here are some examples using 16/16-bit split, unlike the 32/32-bit split for the entry.

typedef uint32_t t_fix;

t_fix fix_add(t_fix x, t_fix y) {
    return x + y;
}

t_fix fix_sub(t_fix x, t_fix y) {
    return x - y;
}

t_fix fix_mul(t_fix x, t_fix y) {
    return (uint64_t)x * y >> 16;
}
\$\endgroup\$
4
  • \$\begingroup\$ Improvement: use eax instead of ax in the adc to not need an operand-size prefix. (The effect on the low half is the same.) \$\endgroup\$
    – m90
    Mar 17 at 16:49
  • \$\begingroup\$ @m90 I know that saves one byte, but the function makes sense to have a return value in the range [0, 0xffff]. Using eax would keep an extra 1 in the high bits if ax was 0xffff. I'm not sure if this makes sense (logically?). \$\endgroup\$
    – xiver77
    Mar 17 at 16:52
  • \$\begingroup\$ Standard x86 calling conventions allow high garbage in registers above narrow return values. e.g. an int16_t return value is strictly in AX, and callers must not assume anything about the high bits of EAX/RAX. Also, you don't need to use a jnc retry for rdrand; golf rules say your code has to work on at least one implementation, and Ivy Bridge (first-gen rdrand) can't exhaust is entropy pool so never fails except maybe on broken HW. (Even without that, you could probably justify using it blindly, but we don't have to.) BTW, you don't need asm goto, just put a 1: label inside. \$\endgroup\$ Mar 17 at 21:23
  • 1
    \$\begingroup\$ So you're using 32-bit binary fixed-point with a 16:16 split. The question talks about "decimal", but then in comments mentions binary floating point, so I guess they don't require actual decimal representation of the fractional part. This would probably be easier and smaller if you took 64-bit fixed-point (32:32 split), with the integer part in EAX (thus 32-bit mode only; 64-bit wouldn't split it). Just rdrand / cmp / adc, I think. Or possibly rdtsc if the low 32 bits is random enough on a single run. (But that would be easier to argue for int16, and still not good for repeated use). \$\endgroup\$ Mar 17 at 21:28
4
\$\begingroup\$

Python 3, 44 bytes

lambda i:(i+random())//1
from random import*

Try it online!

-4 bytes by porting ovs's APL answer

\$\endgroup\$
3
\$\begingroup\$

Ruby, 18 bytes

->n{(n+rand).to_i}

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Jelly, 7 bytes

+Ø%X÷¤Ḟ

A monadic Link that accepts a number and yields an integer.

Note: given an integer there is a one in \$2^{32}\$ chance of outputting an integer one greater than the input, this is within the \$0.01\%\$ specified.

Try it online!

How?

+Ø%X÷¤Ḟ - Link: number, N
     ¤  - nilad followed by link(s) as a nilad:
 Ø%     -   4294967296
   X    -   random integer from [1..4294967296]
    ÷   -   divide by 4294967296
+       - N add that
      Ḟ - floor
\$\endgroup\$
2
  • 1
    \$\begingroup\$ 1 in 256 is a massive 0.39%; you need to use a much bigger number. \$\endgroup\$
    – Neil
    Mar 16 at 19:55
  • \$\begingroup\$ >.< I remember thinking that and then thinking "Oh 0.01 -- one in a hundred", but of course not! Thanks for spotting that; I've upped it a little. \$\endgroup\$ Mar 16 at 20:04
3
+50
\$\begingroup\$

PARI/GP, 32 24 bytes

f(a)=(a+random()/2^31)\1

Attempt This Online!

-8, cheers to @alephalpha for the explanation on PARI/GP

\$\endgroup\$
3
  • 1
    \$\begingroup\$ That is because PARI/GP uses the same random seed every time.you start it. \$\endgroup\$
    – alephalpha
    Mar 17 at 1:04
  • \$\begingroup\$ By the way, the curly brace around 10000 is not necessary. random({N=2^31}) in the help message means that the argument N is optional, and its default value is 2^31. So you can do f(a)=(a+random()/2^31)\1. \$\endgroup\$
    – alephalpha
    Mar 17 at 1:06
  • \$\begingroup\$ @alephalpha ah makes sense, cheers for the explanation \$\endgroup\$
    – jezza_99
    Mar 17 at 1:11
3
\$\begingroup\$

TI-Basic, 4 bytes

int(Ans+rand

the input is Ans (last value entered)

enter image description here

\$\endgroup\$
2
\$\begingroup\$

Perl 5 -p, 22 bytes

$_=int$_+($_/abs)*rand

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Vyxal 2.4.1, 4 bytes

∆Ṙ+⌊

Try it Online!

When rewriting Vyxal, we forgot ∆Ṙ. It's not a feature, it's a bug.

Same as most other answers, adds a random float and floors.

This uses python's random.random which is a random 32-bit float in \$[0, 1)\$.

\$\endgroup\$
2
\$\begingroup\$

Julia 1.0, 17 bytes

!x=ceil(x-rand())

Try it online!

the same as other answers here

\$\endgroup\$
2
\$\begingroup\$

Math++, 23 bytes

?>a
_a+!_($rand/(a-_a))
\$\endgroup\$
2
\$\begingroup\$

Retina, 88 bytes

$
.
\.\d*
$&0000
(\.....).*
$1*_,10000*
L$@`(?<=(-?)(\d+)(_*),_+)((?!\3))?
$1$.($2*_$#4*

Try it online! Link includes test cases. Accurate to 0.01% as required Explanation:

$
.

Append a decimal point in case the input is an integer.

\.\d*
$&0000

Ensure that there are at least 4 digits after the decimal point.

(\.....).*
$1*_,10000*

Multiply the decimal part of the input by 10,000 and convert it to unary, and separately add another 10,000 in unary.

L$@`(?<=(-?)(\d+)(_*),_+)((?!\3))?

Randomly match one _ of the 10,000, then test whether the random value was less than the decimal fraction.

$1$.($2*_$#4*

Keep the sign and increment the magnitude if it was.

\$\endgroup\$
1
\$\begingroup\$

PowerShell, 39 bytes

[Math]::Floor($args[0]+(random -ma 1.))

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Haskell, 65 bytes

import System.Random
f x=do n<-randomIO::IO Float;print$floor$n+x

Try it online!

\$\endgroup\$
1
\$\begingroup\$

C (gcc), 53 44 bytes

i;f(float n){i=n+((n>0)-.5)*rand()/(5<<30);}

Try it online!

Saved a whopping 9 bytes thanks to att!!!

\$\endgroup\$
8
  • \$\begingroup\$ Is there some implementation that RAND_MAX is 32767 so you can save some bytes on 1L<<31? \$\endgroup\$
    – tsh
    Mar 17 at 2:48
  • \$\begingroup\$ 44 bytes \$\endgroup\$
    – att
    Mar 17 at 7:41
  • \$\begingroup\$ @att Oh, very clever - thanks! :D \$\endgroup\$
    – Noodle9
    Mar 17 at 9:20
  • \$\begingroup\$ @tsh No, RAND_MAX is 2147483647 on all modern computers. Maybe on some obscure embedded systems it'll be a short int but I wouldn't bet on it. \$\endgroup\$
    – Noodle9
    Mar 17 at 9:25
  • \$\begingroup\$ Finally, a use-case for Turbo C on DOS? :-) \$\endgroup\$
    – Cody Gray
    Mar 17 at 11:08
1
\$\begingroup\$

R, 26/31 bytes

For anything that has probability in it there has to be at least one attempt in R.

Here we have a function in 31 bytes:

f=function(x)floor(x+runif(1))

and the same thing taking stdin input in 26 bytes:

floor(scan(n=1)+runif(1))
\$\endgroup\$
1
  • \$\begingroup\$ Welcome to Code Golf & Coding Challenges! There was this, I think. Note that you don't have to include the f= since your function isn't recursive (anonymous function submissions are fine). I'd also recommend putting in a Try it Online or Attempt This Online link in your answer. \$\endgroup\$
    – Giuseppe
    Mar 22 at 0:01
1
\$\begingroup\$

Desmos, 21 bytes

f(n)=ceil(n-random())

Press the randomize button at the top left (The icon next to the plus sign) to run the code again.

The simulation code will run the randomization automatically and keep track of the frequency and distribution (more details in the graph).

Try It On Desmos!

Try It On Desmos! - Simulation

\$\endgroup\$
1
\$\begingroup\$

J, 9 7 bytes

-2 thanks to user ovs' comment:

<.@+?@0

Original:

(<.@+?)&0

Port of @ovs' APL answer

\$\endgroup\$
1
  • \$\begingroup\$ <.@+?@0 seems to work for 7. btw ovf is someone else ;) \$\endgroup\$
    – ovs
    Mar 19 at 0:53
0
\$\begingroup\$

Charcoal, 12 bytes

≧X²φI⌊⁺∕‽φφN

Try it online! Link is to verbose version of code. Explanation:

≧X²φ

Square the predefined value for 1,000, so that the error will be less than 0.01% as desired. (Unfortunately without this the error would be 0.1%.)

I⌊⁺∕‽φφN

Divide a random integer between 0 and 1,000,000 by 1,000,000, add it to the input, and floor the result.

\$\endgroup\$
0
\$\begingroup\$

Python 3, 57 bytes

lambda i:math.floor(i+random.random())
import random,math

Try it online!

\$\endgroup\$
0
0
\$\begingroup\$

Swift, 67 bytes

import Foundation
let f={(a:Double)in floor(a + .random(in:0..<1))}

Try it online!

\$\endgroup\$
0
\$\begingroup\$

JavaScript (V8), 45 29 bytes

n=>Math.ceil(n-Math.random())

Try it online!

I am an idiot, this is a much better way of doing it.

Here is my old solution:

n=>Math.random()>(n>0?n:-n)%1?~~n:n>0?-~n:~-n

Try it online!

A bit convoluted to make it work for negatives, but essentially it checks whether the result from Math.random() is greater than the absolute value of the input. If it is, return the input rounded towards zero, otherwise away from zero.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.