Details
Description
A DESCRIPTION OF THE REQUEST :
The online Math.random() documentation does not include an actual or computed maximum return value, only describing it as "less than 1.0".
JUSTIFICATION :
Knowing this value is important because when calculating a number between inclusive bounds, the standard formula for an (int) does not work:
offset + (int) ((upper-lower+1.0) * Math.random())
Removing the (int) cast from above results in a double that may exceed the upper bound by a fraction. Simply truncating this fraction throws the distribution completely off. Also removing the 1.0 causes makes the upper bound unreachable.
Changing the formula to
offset + (upper-lower) * Math.random() / MAX_RANDOM
(where MAX_RANDOM is the largest result) would normalize the range of the result of Math.Random() to 0.0 (inclusive) to 1.0 (inclusive).
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No change in any behavior.
---------- BEGIN SOURCE ----------
/*
* Contents
* heading imports, primary class, etc.
* Procedures non-method procedures
* randomBetween pseudo-random number between given bounds
*/
//******************************************************************// heading
/**
* Provides additional mathematics functionality;
* "extends" java.lang.Math library.
*
* @author Craig Simons
* @date 2014 Feb 19
*/
public class Mathematics {
//******************************************************************// procedures
//==================================================================// randomBetween
/**
* Provides a pseudo-random number between given
* <code>lower</code> and <code>upper</code> bounds, inclusive.
* The bounds can be specified in either order.
*
* @param lower the minimum allowed result
* @param upper the maximum allowed result
* @return A pseudo-random integer.
*/
//==================================================================//
public static long randomBetween( long lower, long upper ) {
//------------------------------------------------------------------//
return (
lower + ((long) (( 1.0 + Math.abs( upper - lower )) * Math.random() ))
);
}
/**
* Provides a pseudo-random number between given
* <code>lower</code> and <code>upper</code> bounds, inclusive.
* The bounds can be specified in either order.
* <p>
* The <code>Math.random()</code> method returns a <code>double</code>
* in the range 0.0 (inclusive) and 1.0 (exclusive).
*
* @param lower the minimum allowed result
* @param upper the maximum allowed result
* @return A pseudo-random integer.
* @see java.util.Math
*/
//==================================================================//
public static double randomBetween( double lower, double upper ) {
//------------------------------------------------------------------//
return (
lower + Math.abs( upper - lower ) * ( Math.random() / ( 1.0 - Double.MIN_VALUE ))
);
}
// ******************************************************** // fin
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
See supplied source code. I do not know if dividing by
( 1.0 - Double.MIN_VALUE )
will actually give a 1.0d without exceeding 1.0d.
The online Math.random() documentation does not include an actual or computed maximum return value, only describing it as "less than 1.0".
JUSTIFICATION :
Knowing this value is important because when calculating a number between inclusive bounds, the standard formula for an (int) does not work:
offset + (int) ((upper-lower+1.0) * Math.random())
Removing the (int) cast from above results in a double that may exceed the upper bound by a fraction. Simply truncating this fraction throws the distribution completely off. Also removing the 1.0 causes makes the upper bound unreachable.
Changing the formula to
offset + (upper-lower) * Math.random() / MAX_RANDOM
(where MAX_RANDOM is the largest result) would normalize the range of the result of Math.Random() to 0.0 (inclusive) to 1.0 (inclusive).
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No change in any behavior.
---------- BEGIN SOURCE ----------
/*
* Contents
* heading imports, primary class, etc.
* Procedures non-method procedures
* randomBetween pseudo-random number between given bounds
*/
//******************************************************************// heading
/**
* Provides additional mathematics functionality;
* "extends" java.lang.Math library.
*
* @author Craig Simons
* @date 2014 Feb 19
*/
public class Mathematics {
//******************************************************************// procedures
//==================================================================// randomBetween
/**
* Provides a pseudo-random number between given
* <code>lower</code> and <code>upper</code> bounds, inclusive.
* The bounds can be specified in either order.
*
* @param lower the minimum allowed result
* @param upper the maximum allowed result
* @return A pseudo-random integer.
*/
//==================================================================//
public static long randomBetween( long lower, long upper ) {
//------------------------------------------------------------------//
return (
lower + ((long) (( 1.0 + Math.abs( upper - lower )) * Math.random() ))
);
}
/**
* Provides a pseudo-random number between given
* <code>lower</code> and <code>upper</code> bounds, inclusive.
* The bounds can be specified in either order.
* <p>
* The <code>Math.random()</code> method returns a <code>double</code>
* in the range 0.0 (inclusive) and 1.0 (exclusive).
*
* @param lower the minimum allowed result
* @param upper the maximum allowed result
* @return A pseudo-random integer.
* @see java.util.Math
*/
//==================================================================//
public static double randomBetween( double lower, double upper ) {
//------------------------------------------------------------------//
return (
lower + Math.abs( upper - lower ) * ( Math.random() / ( 1.0 - Double.MIN_VALUE ))
);
}
// ******************************************************** // fin
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
See supplied source code. I do not know if dividing by
( 1.0 - Double.MIN_VALUE )
will actually give a 1.0d without exceeding 1.0d.