Boost logo

Boost Users :

Subject: Re: [Boost-users] [Random] uniform_real, min/max at end of value range
From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2010-09-08 13:30:01


AMDG

Ruediger Berlich wrote:
> from what I can see, uniform_real(min,max) essentially does this:
>
> fp_type result = uniform_fp_between_0_and_1 * (max - min) + min; // (1)
>
> (1) will fail e.g. if the distance between min and max is >
> std::numeric_limits<fp_type>::max()
>
> While writing unit tests for my code I have come across exactly this
> situation. My application would not suffer much from reducing the allowed
> value range for my variables to < +/-0.5*std::numeric_limits<fp_type>::max()
> . However I feel that this would be a bit artificial.
>
> Hence I was wondering whether code like the following made more sense
> (although it is certainly not as efficient):
>
> /**********************************************************/
>
> fp_type uniform_real(const fp_type& min, const fp_type& max) {
> // Check that min and max have appropriate values
> assert(min<=max);
>
> if(min >= fp_type(0.) || max <= fp_type(0.)) { // (max-min) is valid
> return uniform_01() * (max - min) + min;
> } else { // Some values will fail (max-min)
> // We know: min<0., max>0.
> assert(min<0);
> assert(max>0);
>
> // Calculate a random number in the range [0,1[
> fp_type fraction = uniform_01();
>
> // Calculate the fraction of the distance of min from 0.
> volatile fp_type minFraction = -fraction*min;
> // Calculate the fraction of the distance of max from 0.
> volatile fp_type maxFraction = fraction*max; //
>
> // The start of the scale
> volatile fp_type result = min + minFraction;
>
> // Add maxFraction to the result.
> result += maxFraction;
>
> return result;
> }
> }
>

I'll have to think about whether this is can cause any odd
artifacts, but at a first glance it looks good.

> /**********************************************************/
>
> Essentially, in cases where (max-min) could be larger than the allowed value
> range, the distance to 0 of each max and min is individually multiplied with
> a fp random number in the range [0,1[ . The resulting values are then added
> seperately to min. There should be no situation where an attempt is made to
> create a value larger than the allowed value range ... unless the compiler
> optimizes this to "result=min+minFraction+maxFraction;" or worse. volatile
> might or might not prevent this, I am not sure (seems to work with g++
> 4.4.3, though).
>

Actually min+minFraction+maxFraction is parsed as
(min+minFraction)+maxFraction,
which is okay. What we need to do is make sure that the compiler
doesn't play
fast and loose with associativity and rewrite this as
min+(minFraction+maxFraction).
With gcc you can guarantee this with -fno-unsafe-math-optimizations
-fno-finite-math-only,
which are the default. MSVC has an option for this. I don't think that
volatile is likely to
help much. I know that MSVC ignores volatile for local variables that
don't escape
from the function.

> What is your view on this ? Are there different/better approaches in Boost
> that I could use ?
>

uniform_real should definitely be made bullet-proof if at all possible.

In Christ,
Steven Watanabe


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net