Update: I want random floating point numbers from float.Minvalue to float.Maxvalue. I use these numbers in unit tests of some mathematical methods.
KrisTrip asked 2020-01-21T10:48:33Z
7 solutions
63 votes
The best method is that there is no crazy value, and the representable interval distribution relative to the floating-point number line (the deletion of "unity" is absolutely uneven relative to the continuous number line):
static float NextFloat(Random random) { double mantissa = (random.NextDouble() * 2.0) - 1.0; // choose -149 instead of -126 to also generate subnormal floats (*) double exponent = Math.Pow(2.0, random.Next(-126, 128)); return (float)(mantissa * exponent); }
(*)... Check for abnormal buoys here
Warning: positive infinity will also be generated! For safety, please select an index of 127.
Another method will give you some crazy values (uniform distribution of bit patterns), which may be useful for fuzzy testing:
static float NextFloat(Random random) { var buffer = new byte[4]; random.NextBytes(buffer); return BitConverter.ToSingle(buffer,0); }
This version is an improvement over previous versions in that it does not create "Crazy" values (infinity and no NaN) and is still fast (i.e. the representable intervals on floating-point lines are distributed):
public static float Generate(Random prng) { var sign = prng.Next(2); var exponent = prng.Next((1 << 8) - 1); // do not generate 0xFF (infinities and NaN) var mantissa = prng.Next(1 << 23); var bits = (sign << 31) + (exponent << 23) + mantissa; return IntBitsToFloat(bits); } private static float IntBitsToFloat(int bits) { unsafe { return *(float*) &bits; } }
Least useful methods:
static float NextFloat(Random random) { // Not a uniform distribution w.r.t. the binary floating-point number line // which makes sense given that NextDouble is uniform from 0.0 to 1.0. // Uniform w.r.t. a continuous number line. // // The range produced by this method is 6.8e38. // // Therefore if NextDouble produces values in the range of 0.0 to 0.1 // 10% of the time, we will only produce numbers less than 1e38 about // 10% of the time, which does not make sense. var result = (random.NextDouble() * (Single.MaxValue - (double)Single.MinValue)) + Single.MinValue; return (float)result; }
Floating point lines from: Intel Architecture Software Developer's manual, Volume 1: basic architecture. The Y-axis is logarithmic (based on 2) because there is no linear difference between consecutive binary floating-point numbers.
user7116 answered 2020-01-21T10:49:14Z
26 votes
Why not use float.MinValue and convert it to float.MaxValue? This will float you between 0 and 1.
If you want other forms of "best", you need to specify your requirements. Note that float.MinValue should not be used for sensitive transactions such as finance or security, and usually an existing instance should be reused throughout the application or in each thread (because float.MaxValue is not thread safe).
Edit: as suggested in the note, convert it to float.MinValue, and the range of float.MaxValue:
// Perform arithmetic in double type to avoid overflowing double range = (double) float.MaxValue - (double) float.MinValue; double sample = rng.NextDouble(); double scaled = (sample * range) + float.MinValue; float f = (float) scaled;
Editor: now that you have mentioned that this is for unit testing, I'm not sure it's the ideal method. You should probably test with specific values instead - make sure to test with samples in each relevant category - infinity, NaN, irregular numbers, very large numbers, zero, etc.
Jon Skeet answered 2020-01-21T10:49:48Z
5 votes
There is another version... (I think this version is good)
static float NextFloat(Random random) { (float)(float.MaxValue * 2.0 * (rand.NextDouble()-0.5)); } //inline version float myVal = (float)(float.MaxValue * 2.0 * (rand.NextDouble()-0.5));
I think this
- Is the second fastest (see benchmark)
- Uniform distribution
There is another version... (not very good, but still released)
static float NextFloat(Random random) { return float.MaxValue * ((rand.Next() / 1073741824.0f) - 1.0f); } //inline version float myVal = (float.MaxValue * ((rand.Next() / 1073741824.0f) - 1.0f));
I think this
- Is the fastest (see benchmark)
- Is evenly distributed, but because Next() is a 31 bit random value, it will return only 2 ^ 31 values. (50% of neighbor values will have the same value)
Test most functions on this page: (i7, release, without debugging, 2 ^ 28 cycles)
Sunsetquest1: min: 3.402823E+38 max: -3.402823E+38 time: 3096ms SimonMourier: min: 3.402823E+38 max: -3.402819E+38 time: 14473ms AnthonyPegram:min: 3.402823E+38 max: -3.402823E+38 time: 3191ms JonSkeet: min: 3.402823E+38 max: -3.402823E+38 time: 3186ms Sixlettervar: min: 1.701405E+38 max: -1.701410E+38 time: 19653ms Sunsetquest2: min: 3.402823E+38 max: -3.402823E+38 time: 2930ms
Sunsetquest answered 2020-01-21T10:50:43Z
3 votes
My method is slightly different from other methods
static float NextFloat(Random random) { double val = random.NextDouble(); // range 0.0 to 1.0 val -= 0.5; // expected range now -0.5 to +0.5 val *= 2; // expected range now -1.0 to +1.0 return float.MaxValue * (float)val; }
These comments illustrate what I'm doing. Gets the next double, converts it to a value between - 1 and 1, and multiplies it by float.MaxValue.
Anthony Pegram answered 2020-01-21T10:51:08Z
0 votes
Another solution is to do this:
static float NextFloat(Random random) { float f; do { byte[] bytes = new byte[4]; random.NextBytes(bytes); f = BitConverter.ToSingle(bytes, 0); } while (float.IsInfinity(f) || float.IsNaN(f)); return f; }
Simon Mourier answered 2020-01-21T10:51:28Z
0 votes
This is another method I came up with: suppose you want to get a floating point number between 5.5 and 7 (with 3 decimals).
float myFloat; int myInt; System.Random rnd = new System.Random(); void GenerateFloat() { myInt = rnd.Next(1, 2000); myFloat = (myInt / 1000) + 5.5f; }
In this way, you will always get a number greater than 5.5 and a number less than 7.
Qedized answered 2020-01-21T10:51:52Z
0 votes
I prefer to use the following code to generate a decimal number until the first decimal point. You can copy and paste the third line to add more numbers after the decimal point by appending the number to the string "combined". You can set the minimum and maximum values by changing 0 and 9 to preferred values.
Random r = new Random(); string beforePoint = r.Next(0, 9).ToString();//number before decimal point string afterPoint = r.Next(0,9).ToString();//1st decimal point //string secondDP = r.Next(0, 9).ToString();//2nd decimal point string combined = beforePoint+"."+afterPoint; decimalNumber= float.Parse(combined); Console.WriteLine(decimalNumber);
translate from https://stackoverflow.com:/questions/3365337/best-way-to-generate-a-random-float-in-c-sharp