diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-03-27 15:22:40 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-03-27 15:22:40 -0300 |
| commit | 37a1b72706b6e55e60b8d73bcbe269921976825e (patch) | |
| tree | 4584d132e9b9f963faba8ed8199ef470cb5cab47 | |
| parent | ef5d171cc89b19ac1fea905b99d819b5f97cba00 (diff) | |
| download | lua-37a1b72706b6e55e60b8d73bcbe269921976825e.tar.gz lua-37a1b72706b6e55e60b8d73bcbe269921976825e.tar.bz2 lua-37a1b72706b6e55e60b8d73bcbe269921976825e.zip | |
Small optimization in 'project' from math.random
When computing the Mersenne number, instead of spreading 1's a fixed
number of times (with shifts of 1, 2, 4, 8, 16, and 32), spread only
until the number becomes a Mersenne number.
| -rw-r--r-- | lmathlib.c | 30 |
1 files changed, 9 insertions, 21 deletions
| @@ -533,7 +533,7 @@ typedef struct { | |||
| 533 | ** Project the random integer 'ran' into the interval [0, n]. | 533 | ** Project the random integer 'ran' into the interval [0, n]. |
| 534 | ** Because 'ran' has 2^B possible values, the projection can only be | 534 | ** Because 'ran' has 2^B possible values, the projection can only be |
| 535 | ** uniform when the size of the interval is a power of 2 (exact | 535 | ** uniform when the size of the interval is a power of 2 (exact |
| 536 | ** division). Otherwise, to get a uniform projection into [0, n], we | 536 | ** division). So, to get a uniform projection into [0, n], we |
| 537 | ** first compute 'lim', the smallest Mersenne number not smaller than | 537 | ** first compute 'lim', the smallest Mersenne number not smaller than |
| 538 | ** 'n'. We then project 'ran' into the interval [0, lim]. If the result | 538 | ** 'n'. We then project 'ran' into the interval [0, lim]. If the result |
| 539 | ** is inside [0, n], we are done. Otherwise, we try with another 'ran', | 539 | ** is inside [0, n], we are done. Otherwise, we try with another 'ran', |
| @@ -541,26 +541,14 @@ typedef struct { | |||
| 541 | */ | 541 | */ |
| 542 | static lua_Unsigned project (lua_Unsigned ran, lua_Unsigned n, | 542 | static lua_Unsigned project (lua_Unsigned ran, lua_Unsigned n, |
| 543 | RanState *state) { | 543 | RanState *state) { |
| 544 | if ((n & (n + 1)) == 0) /* is 'n + 1' a power of 2? */ | 544 | lua_Unsigned lim = n; /* to compute the Mersenne number */ |
| 545 | return ran & n; /* no bias */ | 545 | int sh; /* how much to spread bits to the right in 'lim' */ |
| 546 | else { | 546 | /* spread '1' bits in 'lim' until it becomes a Mersenne number */ |
| 547 | lua_Unsigned lim = n; | 547 | for (sh = 1; (lim & (lim + 1)) != 0; sh *= 2) |
| 548 | /* compute the smallest (2^b - 1) not smaller than 'n' */ | 548 | lim |= (lim >> sh); /* spread '1's to the right */ |
| 549 | lim |= (lim >> 1); | 549 | while ((ran &= lim) > n) /* project 'ran' into [0..lim] and test */ |
| 550 | lim |= (lim >> 2); | 550 | ran = I2UInt(nextrand(state->s)); /* not inside [0..n]? try again */ |
| 551 | lim |= (lim >> 4); | 551 | return ran; |
| 552 | lim |= (lim >> 8); | ||
| 553 | lim |= (lim >> 16); | ||
| 554 | #if (LUA_MAXUNSIGNED >> 31) >= 3 | ||
| 555 | lim |= (lim >> 32); /* integer type has more than 32 bits */ | ||
| 556 | #endif | ||
| 557 | lua_assert((lim & (lim + 1)) == 0 /* 'lim + 1' is a power of 2, */ | ||
| 558 | && lim >= n /* not smaller than 'n', */ | ||
| 559 | && (lim >> 1) < n); /* and it is the smallest one */ | ||
| 560 | while ((ran &= lim) > n) /* project 'ran' into [0..lim] */ | ||
| 561 | ran = I2UInt(nextrand(state->s)); /* not inside [0..n]? try again */ | ||
| 562 | return ran; | ||
| 563 | } | ||
| 564 | } | 552 | } |
| 565 | 553 | ||
| 566 | 554 | ||
