├── README.md ├── arbitrary_range.c ├── rd.c ├── some-more-tests.c └── urd.cxx /README.md: -------------------------------------------------------------------------------- 1 | # Generating random doubles # 2 | 3 | The first step was to figure out how to generate numbers in the range 4 | [0.0,1.0). Those experiments and the reasoning behind them is in 5 | comments and code in [rd.c](rd.c). 6 | 7 | A few months later I looked at gcc and llvm standard c++ libraries to 8 | see if their std::uniform_real_distribution actually solved this 9 | problem correctly. They haven't. The result of that is in 10 | [urd.cxx](urd.cxx). The bug report for llvm is 11 | [here](https://llvm.org/bugs/show_bug.cgi?id=23168), I haven't made a 12 | bug report for gcc. 13 | 14 | This triggered me to actually figure out how to extend this to 15 | arbitrary ranges. The first attempt is documented in comments and code 16 | in [arbitrary_range.c](arbitrary_range.c), but it only deals with 17 | positive numbers for now. The nice thing about it is that despite a 18 | completely different algorithm the generated numbers from 19 | arbitrary_range.c set the exact same bits as the numbers in rd.c which 20 | means that either my early assumptions were correct or that my brain 21 | farts are at least consistent. 22 | 23 | ## TODO ## 24 | 25 | - Tackle negative numbers. Naively it should just be like 26 | arbitrary_range, except that we find the biggest absolute value of 27 | (from,to), use that to find the step and count and do some sign 28 | flipping in the right place. But that's for another day. 29 | 30 | ## DISCLAIMER ## 31 | 32 | Please notice that I'm not claiming that anything above makes sense or 33 | that the tests are even close to being comprehensive. A programmer 34 | who tests his own edge cases is like an author writing his own book 35 | reviews. 36 | 37 | To be useful this would require vastly more testing and independent 38 | verificaiton from someone who actually understands set theory and ieee 39 | 754 floating point numbers. I can confidently say that I know neither, 40 | but as the industry standard on stackoverflow and the c++ libraries 41 | seems to indicate, neither do most other people. 42 | -------------------------------------------------------------------------------- /arbitrary_range.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Artur Grabowski 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* Below copyright is from openbsd:src/lib/libc/crypt/arc4random_uniform.c: */ 18 | /* 19 | * Copyright (c) 2008, Damien Miller 20 | * 21 | * Permission to use, copy, modify, and distribute this software for any 22 | * purpose with or without fee is hereby granted, provided that the above 23 | * copyright notice and this permission notice appear in all copies. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 26 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 27 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 28 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 29 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 30 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 31 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 32 | */ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | /* 42 | * Time to think about how to expand this to an arbitrary range. 43 | */ 44 | 45 | /* 46 | * Following two functions are copied from rd.c, see that file 47 | * for explanation. 48 | */ 49 | static uint64_t 50 | rX(uint64_t X) 51 | { 52 | uint64_t res; 53 | assert(X > 0 && X < 65); 54 | arc4random_buf(&res, sizeof(res)); 55 | if (X == 64) 56 | return res; 57 | return res & ((1ULL << X) - 1); 58 | } 59 | 60 | static double 61 | r0to1(void) 62 | { 63 | uint64_t r = rX(53); 64 | int e = ffsll(r); 65 | uint64_t m; 66 | if (e > 52 || e == 0) 67 | return 0.0; 68 | /* Shift out the bit we don't want set. */ 69 | m = (r >> e) << (e - 1); 70 | return ldexp(0x1p52 + m, -52 - e); 71 | } 72 | 73 | 74 | /* 75 | * We want our function to look something like this: 76 | * 77 | * double 78 | * random_double(double from, double to) 79 | * { 80 | * double ret = some magic. 81 | * assert(ret >= from && ret < to); 82 | * return ret; 83 | * } 84 | */ 85 | 86 | /* 87 | * Let's just start with the completely naive implementation that 88 | * seems to be industry standard (see urd.cxx). 89 | */ 90 | 91 | static double 92 | rd_naive(double from, double to) 93 | { 94 | return (to - from) * r0to1() + from; 95 | } 96 | 97 | /* 98 | * And a test showing why this doesn't work. 99 | */ 100 | 101 | static void 102 | test_rd_naive(void) 103 | { 104 | int buckets = 3; 105 | int attempts = 1000000; 106 | double from = 0x1p52, to = from + buckets - 1; 107 | int bucket[buckets]; 108 | int i; 109 | 110 | memset(bucket, 0, sizeof(bucket)); 111 | 112 | printf("f: %f, t: %f\n", from, to); 113 | 114 | for (i = 0; i < attempts; i++) { 115 | double r = rd_naive(from, to); 116 | unsigned int b = (int)(r - from); 117 | assert(r >= from && r <= to); 118 | assert(b < buckets); 119 | bucket[b]++; 120 | } 121 | int minbucket = attempts, maxbucket = 0; 122 | for (i = 0; i < buckets; i++) { 123 | if (bucket[i] < minbucket) 124 | minbucket = bucket[i]; 125 | if (bucket[i] > maxbucket) 126 | maxbucket = bucket[i]; 127 | printf("%d\n", bucket[i]); 128 | } 129 | double diff = (double)maxbucket/(double)minbucket - 1.0; 130 | if (diff > 0.001) { 131 | printf("rd_naive: very large diff (should be close to 0): %f\n", diff); 132 | } 133 | } 134 | 135 | /* 136 | * So what's going on here? Why doesn't math work? 137 | * 138 | * We have to understand that we're not actually dealing with numbers 139 | * here. We're mapping from one set to another. We have a set of 140 | * elements that our random number generator is generating and we're 141 | * mapping to a different set of elements that are all the numbers 142 | * [from, to) _that_a_double_can_represent_. This is the key point, 143 | * there are many numbers [from,to), in fact there are infinitely many 144 | * numbers, but the numbers are irrelevant, get numbers out of your 145 | * head. Actually, let's get numbers out of our head and rephrase 146 | * this: 147 | * 148 | * We have a stream of pigeons and we want to put those pigeons into 149 | * pigeonholes. A uniform distribution of pigeons in pigeonholes can 150 | * only be achieved if the number of unique pigeons is a multiple of 151 | * pigeonholes. In fact to make our life simple, let's just say that 152 | * we want the function mapping pigeons to pigeonholes to be 153 | * bijective. It's not strictly necessary, it's enough that the 154 | * function is surjective and . 157 | * 158 | * Since we can count the number of the possible pigeonholes in the 159 | * range [from, to) that a double can represent all we need is a 160 | * function that gives us a random pigeon with a number [0, count). So 161 | * we need a function that returns random number [0,x). This is of 162 | * course a solved problem, but I'll reimplement it here because I 163 | * want 64 bit numbers and the standard function I have in mind 164 | * `arc4random_uniform` only deals with 32 bit numbers. 165 | * 166 | * Below is a copy from openbsd:src/lib/libc/crypt/arc4random_uniform.c 167 | * adapted to 64 bit numbers. 168 | */ 169 | 170 | /* 171 | * Calculate a uniformly distributed random number less than upper_bound 172 | * avoiding "modulo bias". 173 | * 174 | * Uniformity is achieved by generating new random numbers until the one 175 | * returned is outside the range [0, 2**64 % upper_bound). This 176 | * guarantees the selected random number will be inside 177 | * [2**64 % upper_bound, 2**64) which maps back to [0, upper_bound) 178 | * after reduction modulo upper_bound. 179 | */ 180 | 181 | static uint64_t 182 | r_uniform(uint64_t upper_bound) 183 | { 184 | uint64_t r, min; 185 | 186 | if (upper_bound < 2) 187 | return 0; 188 | 189 | /* 2**64 % x == (2**64 - x) % x */ 190 | min = -upper_bound % upper_bound; 191 | /* 192 | * This could theoretically loop forever but each retry has 193 | * p > 0.5 (worst case, usually far better) of selecting a 194 | * number inside the range we need, so it should rarely need 195 | * to re-roll. 196 | */ 197 | for (;;) { 198 | r = rX(64); 199 | if (r >= min) 200 | break; 201 | } 202 | 203 | return r % upper_bound; 204 | } 205 | 206 | /* 207 | * Now we just need to count our pigeonholes. 208 | * 209 | * Let's limit ourselves to positive numbers for now. I want to 210 | * argue, just like in rd.c that the only way we can keep our sanity 211 | * is if the distance between the possible numbers we can generate, 212 | * errrm. I mean if the distance between the pigeonholes... I'm 213 | * streching this analogy too far. Let's try again. 214 | * 215 | * The only way to keep our sanity is if the distance between the 216 | * possible numbers we can generate is the distance between the 217 | * numbers in the highest possible range. So in the [0,1) range we 218 | * know that the biggest distance between numbers is in the [0.5,1) 219 | * range because those floating point numbers have the highest 220 | * exponent. 221 | * 222 | * The C standard gives us a tool for this exact purpose: nextafter. 223 | */ 224 | static uint64_t 225 | numbers_between(double from, double to) 226 | { 227 | assert(from >= 0 && to > 0 && from < to); /* positive numbers for now. */ 228 | double nxt = nextafter(to, from); /* next representable number from "to" in the direction of "from" */ 229 | double step = to - nxt; /* step between the numbers. */ 230 | double count = (to - from) / step; /* Leap of faith, I actually don't know if this will always be correct. */ 231 | uint64_t r = count; 232 | 233 | /* 234 | * The conversion to uint64_t should be accurate. Every 235 | * integer between 0 and 2^53 can be expressed in a double and 236 | * we can't get a higher count than 2^53 because that's the 237 | * count we get when to is at the end of a range. 238 | * 239 | * As far as I can see we can only get a higher count when we 240 | * extend this to negative ranges because then the count can 241 | * become 2^54 in the worst case. We'll cross that bridge when 242 | * we get there. 243 | */ 244 | assert((double)r == count); 245 | 246 | return r; 247 | } 248 | 249 | /* 250 | * Let's just verify that I'm not entirely full of shit: 251 | */ 252 | static void 253 | test_ranges(void) 254 | { 255 | uint64_t r; 256 | r = numbers_between(0x1p52, 0x1p52 + 3); 257 | assert(r == 3); 258 | r = numbers_between(0x1p55, 0x1p55 + 25); 259 | assert(r == 3); 260 | 261 | r = numbers_between(0, 0x1p52 + 1000); 262 | assert(r == (1LL << 52) + 1000); 263 | 264 | r = numbers_between(3, 0x1p52 + 1000); 265 | assert(r == (1LL << 52) + 997); 266 | 267 | r = numbers_between(0, 0x1p53 + 1000); 268 | assert(r == (1LL << 52) + 500); 269 | 270 | r = numbers_between(0, 0x1p53); 271 | assert(r == (1LL << 53)); 272 | 273 | r = numbers_between(0, 0x1p53 - 1); 274 | assert(r == (1LL << 53) - 1); 275 | 276 | r = numbers_between(0, 0x1p53 + 1); 277 | assert(r == (1LL << 53)); 278 | 279 | r = numbers_between(0, 0x1p53 + 2); 280 | assert(r == (1LL << 52) + 1); 281 | 282 | /* 283 | * This test below actually gives us separate verification 284 | * that my stumbling math in rd.c about the numbers in [0,1) 285 | * range was correct. 286 | */ 287 | r = numbers_between(0, 1); 288 | assert(r == (1LL << 53)); 289 | } 290 | 291 | /* 292 | * So the function that works for positive numbers should be 293 | * relatively trivial: 294 | */ 295 | static double 296 | rd_positive(double from, double to) 297 | { 298 | assert(from >= 0 && to > 0 && from < to); /* positive numbers for now. */ 299 | double nxt = nextafter(to, from); /* next representable number from "to" in the direction of "from" */ 300 | double step = to - nxt; /* step between the numbers. */ 301 | double count = (to - from) / step; /* Leap of faith, I actually don't know if this will always be correct. */ 302 | 303 | assert(count <= (1LL << 53)); 304 | return from + (double)(r_uniform((uint64_t)count)) * step; 305 | } 306 | 307 | /* 308 | * And a test that things at least appear to make sense. 309 | */ 310 | static void 311 | test_rd_positive_n(int buckets) 312 | { 313 | int attempts = 10000000; 314 | double from = 0x1p52, to = from + buckets; 315 | int bucket[buckets]; 316 | int i; 317 | 318 | memset(bucket, 0, sizeof(bucket)); 319 | 320 | printf("f: %f, t: %f\n", from, to); 321 | 322 | for (i = 0; i < attempts; i++) { 323 | double r = rd_positive(from, to); 324 | unsigned int b = (int)(r - from); 325 | if (r < from || r > to) 326 | printf("BAD: %f\n", r); 327 | assert(r >= from && r <= to); 328 | assert(b < buckets); 329 | bucket[b]++; 330 | } 331 | int minbucket = attempts, maxbucket = 0; 332 | for (i = 0; i < buckets; i++) { 333 | if (bucket[i] < minbucket) 334 | minbucket = bucket[i]; 335 | if (bucket[i] > maxbucket) 336 | maxbucket = bucket[i]; 337 | printf("%d, ", bucket[i]); 338 | } 339 | printf("\n"); 340 | double diff = (double)maxbucket/(double)minbucket - 1.0; 341 | if (diff > 0.05) { 342 | printf("rd_positive: very large diff (should be close to 0): %f (%d %d)\n", diff, maxbucket, minbucket); 343 | } 344 | } 345 | 346 | static void 347 | test_rd_positive(void) 348 | { 349 | test_rd_positive_n(2); 350 | test_rd_positive_n(3); 351 | test_rd_positive_n(4); 352 | test_rd_positive_n(17); 353 | test_rd_positive_n(42); 354 | } 355 | 356 | /* 357 | * And the last test, from rd.c, check that rd_positive(0,1) is equivalent to r0to1b. 358 | */ 359 | static void 360 | A(double r, double min, double max) 361 | { 362 | if (r < min) { 363 | printf("A: %f < %f\n", r, min); 364 | abort(); 365 | } 366 | if (r > max) { 367 | printf("A: %f > %f\n", r, max); 368 | abort(); 369 | } 370 | } 371 | 372 | struct r1_test { 373 | int mmset; 374 | uint64_t efreq[52]; 375 | uint64_t m_bits_set[52]; 376 | double min[52], max[52]; 377 | }; 378 | 379 | static void 380 | B(double r, struct r1_test *rt) 381 | { 382 | union { 383 | uint64_t u; 384 | double d; 385 | } foo; 386 | 387 | foo.d = r; 388 | 389 | uint64_t E, m; 390 | int e; 391 | 392 | E = (foo.u >> 52LL) & ((1LL << 11) - 1); 393 | e = E - 1023; 394 | if (e > -1) { 395 | printf("B(e): %d > -1\n", e); 396 | abort(); 397 | } 398 | if (e <= -52) { 399 | printf("B(e): %d <= -52\n", e); 400 | abort(); 401 | } 402 | int o = -e -1; 403 | assert(o >= 0 && o < 52); 404 | rt->efreq[o]++; 405 | m = foo.u & ((1LL << 52) - 1); 406 | rt->m_bits_set[o] |= m; 407 | uint64_t expected_bits = ((1LL << 52) - 1); 408 | expected_bits ^= (1LL << (-e - 1)) - 1; 409 | if (m & ~expected_bits) { 410 | printf("B(m): unexpected bits set: 0x%llx, expected 0x%llx, diff 0x%llx\n", 411 | m, expected_bits, m & ~expected_bits); 412 | abort(); 413 | } 414 | if (!rt->mmset) { 415 | int i; 416 | for (i = 0; i < 52; i++) { 417 | rt->min[i] = 2.0; 418 | rt->max[i] = -1.0; 419 | } 420 | rt->mmset = 1; 421 | } 422 | if (r < rt->min[o]) 423 | rt->min[o] = r; 424 | if (r > rt->max[o]) 425 | rt->max[o] = r; 426 | 427 | A(rt->min[o], ldexp(0x1p0, e), ldexp(0x1p0, e + 1)); 428 | A(rt->max[o], ldexp(0x1p0, e), ldexp(0x1p0, e + 1)); 429 | } 430 | static void 431 | check_1to2(double (*fn)(void), struct r1_test *rt) 432 | { 433 | double x = fn(); 434 | A(x, 0.0, 1.0); 435 | B(x, rt); 436 | } 437 | 438 | static double 439 | rd_positive0to1(void) 440 | { 441 | return rd_positive(0.0, 1.0); 442 | } 443 | 444 | static void 445 | test_rd_positive0to1(void) 446 | { 447 | struct r1_test r1b = { 0 }; 448 | uint64_t numruns = 1LL << 25; 449 | uint64_t i; 450 | 451 | for (i = 0; i < numruns; i++) { 452 | check_1to2(rd_positive0to1, &r1b); 453 | } 454 | for (i = 1; i < 52; i++) { 455 | uint64_t expected_bits = ((1LL << 52) - 1); 456 | expected_bits ^= (1LL << i) - 1; 457 | /* 458 | * Check that the bits we expect to be used in the 459 | * mantissa are actually used and not more. 460 | * 461 | * We only check if that particular exponent has been 462 | * used at least 25 times. Why 25? Because that shut 463 | * up the false positives for the numbers with too 464 | * small sample size most of the time. 465 | */ 466 | if (r1b.m_bits_set[i] != expected_bits && r1b.efreq[i] > 25) { 467 | printf("bits2[%llu]: 0x%llx, expected 0x%llx, diff: 0x%llx\n", 468 | i, r1b.m_bits_set[i], expected_bits, 469 | r1b.m_bits_set[i] ^ expected_bits); 470 | } 471 | } 472 | 473 | for (i = 0; i < 52; i++) { 474 | if (r1b.efreq[i] == 0) 475 | continue; 476 | uint64_t expected = numruns / (1LLU << (i + 1)); 477 | printf("freq2[%lld]: %llu, expected: %llu, deviation %.2f, range %f - %f\n", 478 | -i, r1b.efreq[i], expected, (double)r1b.efreq[i] / (double)expected, 479 | r1b.min[i], r1b.max[i]); 480 | } 481 | } 482 | 483 | /* 484 | * And this was a separate verification that my guesses about which 485 | * bits need to be set in r0to1 in rd.c were correct, because a 486 | * completely different method to generate doubles in [0,1) gave the 487 | * same results. 488 | */ 489 | 490 | int 491 | main(int argc, char **argv) 492 | { 493 | test_rd_naive(); 494 | test_ranges(); 495 | test_rd_positive(); 496 | test_rd_positive0to1(); 497 | return 0; 498 | } 499 | -------------------------------------------------------------------------------- /rd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Artur Grabowski 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | /* 25 | * I need to generate floating point doubles in the range [0,1) that 26 | * are uniformly distributed. The distribution isn't allowed to be 27 | * denser in any part of the range. 28 | * 29 | * The Stackoverflow questions I can find about the topic have 30 | * obviously flawed answers. `((double)rand()/(double)RAND_MAX)` will 31 | * neither give us a random number, nor will the distribution be 32 | * paricularly good. This is not even under discussion here. If you 33 | * think this is a good way to generate uniformly distributed random 34 | * doubles, either read on or just go away. 35 | */ 36 | 37 | /* 38 | * I have a good random source. That's not part of the problem. 39 | * Assume that my source of random bits is perfect and is a function 40 | * that returns a number in the range [0,2^X) and looks like this (for 41 | * X <= 64): 42 | */ 43 | static uint64_t 44 | rX(uint64_t X) 45 | { 46 | uint64_t res; 47 | assert(X > 0 && X < 65); 48 | arc4random_buf(&res, sizeof(res)); 49 | if (X == 64) 50 | return res; 51 | return res & ((1ULL << X) - 1); 52 | } 53 | 54 | /* 55 | * If your operating system does not provide `arc4random_buf` get 56 | * a better operating system or substitute this function for your 57 | * favourite randomness source. 58 | */ 59 | 60 | /* 61 | * Let's also just limit ourselves to IEEE 754 binary64 numbers known 62 | * as `double` in most C implementations. This code should be 63 | * relatively easily generalizable to any doubles that have a mantissa 64 | * with less than 64 bits or if you have more than that if you have an 65 | * integer type that is as big as your dobule. This is a proof of 66 | * concept, not a generic solution that will work everywhere every 67 | * time. 68 | */ 69 | 70 | /* 71 | * We know that we have a 52 bit mantissa and that makes the numbers 72 | * in the range [2^52,2^53) have integer precision . So a uniformly 73 | * distributed random double in that range is trivial to generate 74 | * without resorting to bit fiddling: 75 | */ 76 | double 77 | r52to53(void) 78 | { 79 | return ldexp(0x1p52 + rX(52), 0); 80 | } 81 | 82 | /* 83 | * We also don't lose anything if we cut this down to a [1,2) range: 84 | */ 85 | double 86 | r1to2(void) 87 | { 88 | return ldexp(0x1p52 + rX(52), 0) / 0x1p52; 89 | } 90 | 91 | /* 92 | * Another variant where we trust the compiler a bit less: 93 | */ 94 | double 95 | r1to2bis(void) 96 | { 97 | return ldexp(0x1p52 + rX(52), -52); 98 | } 99 | 100 | /* 101 | * The previous two functions can be shown to work correctly with a 102 | * little bit of bit fiddling (and standard violating) by only 103 | * randomizing the bits in the mantissa while keeping the exponent the 104 | * same: 105 | */ 106 | double 107 | r1to2check(void) 108 | { 109 | union { 110 | uint64_t u; 111 | double d; 112 | } a, b, c; 113 | uint64_t r = rX(52); 114 | 115 | /* 116 | * This assumes we're little-endian. Or actually i387 endian 117 | * because endianness for floating point isn't defined 118 | * anywhere. 119 | */ 120 | a.d = 0x1p0; 121 | a.u |= r; 122 | 123 | b.d = ldexp(0x1p52 + r, 0) / 0x1p52; 124 | c.d = ldexp(0x1p52 + r, -52); 125 | assert(a.d == b.d && a.u == b.u && a.d == c.d && b.u == c.u); 126 | assert(a.d >= 1.0 && a.d < 2.0); 127 | return a.d; 128 | } 129 | 130 | /* 131 | * It doesn't take much imagination to map this to any [2^X,2^(X+1)) 132 | * range: 133 | */ 134 | double 135 | r2range(int X) 136 | { 137 | assert(X >= -1023 && X <= 1025); 138 | return ldexp(r1to2bis(),X); 139 | } 140 | 141 | /* 142 | * Everything up to here is obvious and trivial. But it doesn't really 143 | * get us closer to a [0,1) range. I was just warming up my 144 | * understanding of IEEE floating point as a preparation for the main 145 | * event. 146 | * 147 | * Intuitively I can't trust `r1to2() - 1.0`. 148 | * 149 | * To get us a uniformly distributed number in the [0,1) range, we 150 | * have 1/2 chance to get a number in the [0.5,1.0) range, 1/4 151 | * [0.25,0.5), etc. 152 | * 153 | * There are 2^52 possible numbers in the [0.5,1.0) range and the 154 | * range has a 2^-1 probablity to be picked, this means that the 155 | * probability of any number in that range is 2^-53. Since we don't 156 | * want any number to be more likely to be picked, it means that the 157 | * probability for 0 should be 2^-53. 158 | * 159 | * This gives us a very simple way to pick our exponent. Generate a 52 160 | * bit number, find the lowest set bit (1 indexed) and zero minus that 161 | * bit is our exponent. If no bits are set, we special case and return 162 | * 0.0 (this has a 2^-53 probability). The probability of each bit 163 | * being set is 1/2, this means that bit 1 has 1/2 probability of 164 | * being picked, bit 2 1/4, etc. The ffsll function is just perfect 165 | * for this. Unfortunately POSIX only has ffs, but everyone (I care 166 | * about) implements ffsll. 167 | * 168 | * The only question that remains is the mantissa. On one hand it 169 | * shouldn't hurt to set the mantissa to completely random bits. We 170 | * would get the worst entropy for 0 and [0.5,1.0), every other range 171 | * would be less predictable. On the other hand, there's something 172 | * elegant about having all the pickable numbers to be at an equal 173 | * distance from each other. Intuitively, this should be as simple as 174 | * not setting the lower bits of the mantissa (or should they be all 175 | * 1? This has been verified in arbitrary_range.c and unless that 176 | * completely different algorithm is also wrong, they correct answer is 177 | * that they should all be 0). 178 | */ 179 | double 180 | r0to1(void) 181 | { 182 | int e; 183 | uint64_t m; 184 | 185 | e = ffsll(rX(52)); 186 | if (e == 0) 187 | return 0.0; 188 | m = rX(52 - e + 1) << (e - 1); 189 | return ldexp(0x1p52 + m, -52 - e); 190 | } 191 | 192 | /* 193 | * But wait a minute. Why are we using (up to) 104 random bits when we 194 | * only provide 53 bits of entropy. 195 | * 196 | * This can be improved. 197 | * 198 | * Generate a 53 bit number, the number of the first set bit is our 199 | * exponent, clear that bit and shift one bit (since it's known, while 200 | * the next bits aren't), use the rest of the generated number as the 201 | * mantissa. 202 | */ 203 | double 204 | r0to1b(void) 205 | { 206 | uint64_t r = rX(53); 207 | int e = ffsll(r); 208 | uint64_t m; 209 | if (e > 52 || e == 0) 210 | return 0.0; 211 | /* Shift out the bit we don't want set. */ 212 | m = (r >> e) << (e - 1); 213 | return ldexp(0x1p52 + m, -52 - e); 214 | } 215 | 216 | /* 217 | * Tests that our assumptions hold. 218 | */ 219 | static void 220 | A(double r, double min, double max) 221 | { 222 | if (r < min) { 223 | printf("A: %f < %f\n", r, min); 224 | abort(); 225 | } 226 | if (r > max) { 227 | printf("A: %f > %f\n", r, max); 228 | abort(); 229 | } 230 | } 231 | 232 | struct r1_test { 233 | int mmset; 234 | uint64_t efreq[52]; 235 | uint64_t m_bits_set[52]; 236 | double min[52], max[52]; 237 | }; 238 | 239 | static void 240 | B(double r, struct r1_test *rt) 241 | { 242 | union { 243 | uint64_t u; 244 | double d; 245 | } foo; 246 | 247 | foo.d = r; 248 | 249 | uint64_t E, m; 250 | int e; 251 | 252 | E = (foo.u >> 52LL) & ((1LL << 11) - 1); 253 | e = E - 1023; 254 | if (e > -1) { 255 | printf("B(e): %d > -1\n", e); 256 | abort(); 257 | } 258 | if (e <= -52) { 259 | printf("B(e): %d <= -52\n", e); 260 | abort(); 261 | } 262 | int o = -e -1; 263 | assert(o >= 0 && o < 52); 264 | rt->efreq[o]++; 265 | m = foo.u & ((1LL << 52) - 1); 266 | rt->m_bits_set[o] |= m; 267 | uint64_t expected_bits = ((1LL << 52) - 1); 268 | expected_bits ^= (1LL << (-e - 1)) - 1; 269 | if (m & ~expected_bits) { 270 | printf("B(m): unexpected bits set: 0x%llx, expected 0x%llx, diff 0x%llx\n", 271 | m, expected_bits, m & ~expected_bits); 272 | abort(); 273 | } 274 | if (!rt->mmset) { 275 | int i; 276 | for (i = 0; i < 52; i++) { 277 | rt->min[i] = 2.0; 278 | rt->max[i] = -1.0; 279 | } 280 | rt->mmset = 1; 281 | } 282 | if (r < rt->min[o]) 283 | rt->min[o] = r; 284 | if (r > rt->max[o]) 285 | rt->max[o] = r; 286 | 287 | A(rt->min[o], ldexp(0x1p0, e), ldexp(0x1p0, e + 1)); 288 | A(rt->max[o], ldexp(0x1p0, e), ldexp(0x1p0, e + 1)); 289 | } 290 | 291 | uint64_t rX_bits_set; 292 | 293 | static void 294 | check_simple(void) 295 | { 296 | rX_bits_set |= rX(52); 297 | 298 | r1to2check(); 299 | A(r1to2(), 1.0, 2.0); 300 | A(r1to2bis(), 1.0, 2.0); 301 | A(r2range(7), 127.0, 256.0); 302 | A(r2range(-1), 0.5, 1.0); 303 | } 304 | 305 | static void 306 | check_1to2(double (*fn)(void), struct r1_test *rt) 307 | { 308 | double x = fn(); 309 | A(x, 0.0, 1.0); 310 | B(x, rt); 311 | } 312 | 313 | int 314 | main(int argc, char **argv) 315 | { 316 | const uint64_t numruns = 1LL << 25; 317 | struct r1_test r1a = { 0 }; 318 | struct r1_test r1b = { 0 }; 319 | uint64_t i; 320 | 321 | for (i = 0; i < numruns / 10; i++) { 322 | check_simple(); 323 | } 324 | 325 | /* should work most of the time. */ 326 | assert(rX_bits_set == 0xfffffffffffffLLU); 327 | 328 | for (i = 0; i < numruns; i++) { 329 | check_1to2(r0to1, &r1a); 330 | } 331 | 332 | for (i = 0; i < numruns; i++) { 333 | check_1to2(r0to1b, &r1b); 334 | } 335 | 336 | for (i = 1; i < 52; i++) { 337 | uint64_t expected_bits = ((1LL << 52) - 1); 338 | expected_bits ^= (1LL << i) - 1; 339 | /* 340 | * Check that the bits we expect to be used in the 341 | * mantissa are actually used and not more. 342 | * 343 | * We only check if that particular exponent has been 344 | * used at least 25 times. Why 25? Because that shut 345 | * up the false positives for the numbers with too 346 | * small sample size most of the time. 347 | */ 348 | if (r1a.m_bits_set[i] != expected_bits && r1a.efreq[i] > 25) { 349 | printf("bits1[%llu]: 0x%llx, expected 0x%llx, diff: 0x%llx\n", 350 | i, r1a.m_bits_set[i], expected_bits, 351 | r1a.m_bits_set[i] ^ expected_bits); 352 | } 353 | if (r1b.m_bits_set[i] != expected_bits && r1b.efreq[i] > 25) { 354 | printf("bits2[%llu]: 0x%llx, expected 0x%llx, diff: 0x%llx\n", 355 | i, r1b.m_bits_set[i], expected_bits, 356 | r1b.m_bits_set[i] ^ expected_bits); 357 | } 358 | } 359 | 360 | for (i = 0; i < 52; i++) { 361 | if (r1a.efreq[i] == 0) 362 | continue; 363 | uint64_t expected = numruns / (1LLU << (i + 1)); 364 | printf("freq1[%lld]: %llu, expected: %llu, deviation %.2f, range %f - %f\n", 365 | -i, r1a.efreq[i], expected, (double)r1a.efreq[i] / (double)expected, 366 | r1a.min[i], r1a.max[i]); 367 | } 368 | 369 | for (i = 0; i < 52; i++) { 370 | if (r1b.efreq[i] == 0) 371 | continue; 372 | uint64_t expected = numruns / (1LLU << (i + 1)); 373 | printf("freq2[%lld]: %llu, expected: %llu, deviation %.2f, range %f - %f\n", 374 | -i, r1b.efreq[i], expected, (double)r1b.efreq[i] / (double)expected, 375 | r1b.min[i], r1b.max[i]); 376 | } 377 | return 0; 378 | } 379 | -------------------------------------------------------------------------------- /some-more-tests.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Artur Grabowski 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | /* 25 | * I need to convince myself of a few things. 26 | */ 27 | 28 | /* 29 | * Why I think that generating a number in [1,2) and then mapping it 30 | * to [0,1) by subtracting one doesn't actually work. 31 | */ 32 | void 33 | test_minus_one(void) 34 | { 35 | double less_than_two; 36 | double less_than_one; 37 | int i; 38 | 39 | 40 | /* 41 | * Here, we step through the first 10 numbers smaller than 2, 42 | * subtract 1.0 from them and compare that to the first 10 43 | * numbers smaller than 1. If mapping from [1,2) to [0,1) 44 | * worked by subtracting 1.0 there should be no diff. 45 | */ 46 | less_than_two = nextafter(2.0, 0.0); 47 | less_than_one = nextafter(1.0, 0.0); 48 | for (i = 0; i < 10; i++) { 49 | double diff = (less_than_two - 1.0) - less_than_one; 50 | printf("%a %a %a %a\n", less_than_two, less_than_two - 1.0, less_than_one, diff); 51 | less_than_two = nextafter(less_than_two, 0.0); 52 | less_than_one = nextafter(less_than_one, 0.0); 53 | } 54 | /* 55 | * The same thing, but this time here is how I think the 56 | * result will actually end up being. We'll end up not being 57 | * able to pick every other less_than_one number. 58 | */ 59 | less_than_two = nextafter(2.0, 0.0); 60 | less_than_one = nextafter(1.0, 0.0); 61 | for (i = 0; i < 10; i++) { 62 | less_than_one = nextafter(less_than_one, 0.0); 63 | double diff = (less_than_two - 1.0) - less_than_one; 64 | printf("%a %a %a %a\n", less_than_two, less_than_two - 1.0, less_than_one, diff); 65 | less_than_two = nextafter(less_than_two, 0.0); 66 | less_than_one = nextafter(less_than_one, 0.0); 67 | } 68 | } 69 | 70 | int 71 | main(int argc, char **argv) 72 | { 73 | test_minus_one(); 74 | } 75 | -------------------------------------------------------------------------------- /urd.cxx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Artur Grabowski 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | /* 24 | * Hey, I heard that C++11 has magic to get a uniform distribution of 25 | * floating point numbers, let's see how it performs. 26 | */ 27 | 28 | int 29 | main(int argc, char **argv) 30 | { 31 | std::default_random_engine gen; 32 | double from, step, to; 33 | int range = 3; 34 | 35 | switch (argc) { 36 | case 1: 37 | from = 1.0; 38 | break; 39 | default: 40 | case 3: 41 | range = atoi(argv[2]); 42 | case 2: 43 | from = atof(argv[1]); 44 | break; 45 | } 46 | 47 | /* 48 | * Calculate the nearest representable number after from. 49 | * add 1.0 to deal with from being 0 (shouldn't cause overflow 50 | * because at that range 1.0 means nothing). 51 | */ 52 | step = nextafter(from, (from + 1.0) * 2.0) - from; 53 | /* 54 | * uniform_real_distribution should return [from,to), but they 55 | * all return [from,to], so that's why 1 is subtracted from range. 56 | */ 57 | to = from + step * (range - 1); 58 | 59 | printf("%a %a %a %d\n", from, to, step, range); 60 | 61 | std::uniform_real_distribution dis(from, to); 62 | int bucket[range]; 63 | int i; 64 | 65 | for (i = 0; i < range; i++) { 66 | bucket[i] = 0; 67 | } 68 | 69 | for (i = 0; i < 100 * range; i++) { 70 | double r = dis(gen); 71 | unsigned int b = (int)((r - from)/step); 72 | if (b >= range) { 73 | printf("foo: %d %f\n", b, r); 74 | } 75 | assert(b < range); 76 | bucket[b]++; 77 | } 78 | 79 | for (i = 0; i < range; i++) { 80 | printf("%d\n", bucket[i]); 81 | } 82 | return 0; 83 | } 84 | --------------------------------------------------------------------------------