Best way to generate a random float in C#

C#RandomFloating Point

C# Problem Overview


What is the best way to generate a random float in C#?

Update: I want random floating point numbers from float.Minvalue to float.Maxvalue. I am using these numbers in unit testing of some mathematical methods.

C# Solutions


Solution 1 - C#

Best approach, no crazed values, distributed with respect to the representable intervals on the floating-point number line (removed "uniform" as with respect to a continuous number line it is decidedly non-uniform):

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 here for subnormal floats

Warning: generates positive infinity as well! Choose exponent of 127 to be on the safe side.

Another approach which will give you some crazed values (uniform distribution of bit patterns), potentially useful for fuzzing:

static float NextFloat(Random random)
{
    var buffer = new byte[4];
    random.NextBytes(buffer);
    return BitConverter.ToSingle(buffer,0);
}

An improvement over the previous version is this one, which does not create "crazed" values (neither infinities nor NaN) and is still fast (also distributed with respect to the representable intervals on the floating-point number line):

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 approach:

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 number line from: Intel Architecture Software Developer's Manual Volume 1: Basic Architecture. The Y-axis is logarithmic (base-2) because consecutive binary floating point numbers do not differ linearly.

Comparison of distributions, logarithmic Y-axis

Solution 2 - C#

Any reason not to use Random.NextDouble and then cast to float? That will give you a float between 0 and 1.

If you want a different form of "best" you'll need to specify your requirements. Note that Random shouldn't be used for sensitive matters such as finance or security - and you should generally reuse an existing instance throughout your application, or one per thread (as Random isn't thread-safe).

EDIT: As suggested in comments, to convert this to a range of float.MinValue, 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;

EDIT: Now you've mentioned that this is for unit testing, I'm not sure it's an ideal approach. You should probably test with concrete values instead - making sure you test with samples in each of the relevant categories - infinities, NaNs, denormal numbers, very large numbers, zero, etc.

Solution 3 - C#

One more version... (I think this one is pretty 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 2nd fastest (see benchmarks)
  • is evenly distributed

And One more version...(not as good but posting anyway)

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 benchmarks)
  • is evenly distributed however because Next() is a 31 bit random value it will only return 2^31 values. (50% of the neighbor values will have the same value)

Testing of most of the functions on this page: (i7, release, without debug, 2^28 loops)

 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

Solution 4 - C#

I took a slightly different approach than others

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;
}

The comments explain what I'm doing. Get the next double, convert that number to a value between -1 and 1 and then multiply that with float.MaxValue.

Solution 5 - C#

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;
}

Solution 6 - C#

Here is another way that I came up with: Let's say you want to get a float 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;
}

That way you will always get a bigger number than 5.5 and a smaller number than 7.

Solution 7 - C#

I prefer using the following code to generate a decimal number up to fist decimal point. you can copy paste the 3rd line to add more numbers after decimal point by appending that number in string "combined". You can set the minimum and maximum value by changing the 0 and 9 to your preferred value.

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);

I hope that it helped you.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKrisTripView Question on Stackoverflow
Solution 1 - C#user7116View Answer on Stackoverflow
Solution 2 - C#Jon SkeetView Answer on Stackoverflow
Solution 3 - C#SunsetQuestView Answer on Stackoverflow
Solution 4 - C#Anthony PegramView Answer on Stackoverflow
Solution 5 - C#Simon MourierView Answer on Stackoverflow
Solution 6 - C#QedizedView Answer on Stackoverflow
Solution 7 - C#Waheed SattarView Answer on Stackoverflow