Path: csiph.com!eternal-september.org!feeder.eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: Bart, a tcc "issue" Date: Sun, 10 Nov 2019 07:49:00 -0800 Organization: A noiseless patient Spider Lines: 64 Message-ID: <864kzbd95f.fsf@linuxsc.com> References: <86k189ejbd.fsf@linuxsc.com> <87sgmw3ajx.fsf@bsb.me.uk> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="451385503b6e65ada0ba6f97513c8763"; logging-data="29675"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX183WazJEUpd1Qm7jOysAY6yW0Af4tTUxP4=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:T2J4D0SIGMHUFUqi3tt1OrZwOf0= sha1:vPdfmdQZUhymqbi80+hcy0gTnCw= Xref: csiph.com comp.lang.c:147907 Ben Bacarisse writes: > Tim Rentsch writes: > > >> It's interesting -- three different people posted corrections or >> improvements to the uniform interval code, and all of the revisions >> have been a little bit off in one way or another. Care is needed to >> deal with edge cases correctly. >> >> int >> uniform_less_than( unsigned k ){ >> unsigned d, r; >> >> if( k-1 > RAND_MAX || k == 0 ) oops_someone_messed_up(); >> >> d = (RAND_MAX - (k-1)) / k + 1; >> do r = rand()/d; while( r >= k ); >> >> return r; >> } >> >> int >> uniform_on_closed_interval( int a, int b ){ >> if( a > b ) return uniform_on_closed_interval( b, a ); >> >> return a + uniform_less_than( b + 1u - a ); >> } >> >> A good test for a uniform closed-interval RNG is to check that >> it handles the interval 0..RAND_MAX, including both endpoints, >> correctly. > > Are you considering edge cases in the C standard? If so, one of those > has RAND_MAX == UINT_MAX. Ahem. Please review this version: int uniform_no_greater_than( unsigned k ){ unsigned r = 0; assert( k <= RAND_MAX ); if( k > 0 ){ unsigned d = k >= RAND_MAX ? 1 : (RAND_MAX - k) / (k+1) + 1; do r = rand()/d; while( r > k ); } return r; } int uniform_on_closed_interval( int a, int b ){ if( a > b ) return uniform_on_closed_interval( b, a ); if( a < 0 ? b > a+RAND_MAX : b-a > RAND_MAX ){ return interval_too_large(), a; } return a + uniform_no_greater_than( b - a ); } The version just previously posted has a problem if k is 0 in implementations where RAND_MAX == UINT_MAX.