2

This is what I want to achieve:

public double NextMin (double min)
{
    //Returns a double that is greater than or equal to "min". 
}

public double NextMax (double max)
{
    //Returns a double that is lesser than "max".
}

I tried range expanding but it returns lots of "Infinity" due to overflow:

// Range expanding for min
random.NextDouble() * (double.MaxValue - min) + min;

// Range expanding for max 
random.NextDouble() * (max - double.MinValue) + double.MinValue;

Clarification: I need the return ranges to be as great as possible, which means they should include both negatives and positives.

Cœur
  • 37,241
  • 25
  • 195
  • 267
starikcetin
  • 1,391
  • 1
  • 16
  • 24
  • 1
    Why do you want to do this? Is this an X-Y Problem? – Enigmativity Aug 04 '16 at 03:39
  • @Enigmativity I will generate a procedural universe, and I need some random vector samplings. These methods are needed in my algorithm. – starikcetin Aug 04 '16 at 03:40
  • Take a look here http://stackoverflow.com/questions/3365337/best-way-to-generate-a-random-float-in-c-sharp – Blorgbeard Aug 04 '16 at 03:40
  • 1
    If you assume `double.MaxValue == 10.0` and `double.MinValue == -10.0` then `double.MaxValue - double.MinValue == 20.0`, but that's larger than the allowed range for a `double` (under this assumption). Hence the reason you're getting infinity issues. – Enigmativity Aug 04 '16 at 04:25

4 Answers4

4

I believe this works for the general case (provided min is less than max).

private Random rng = new Random();

private double GetRandomDouble(double min, double max)
{
    var half_min = min / 2.0;
    var half_max = max / 2.0;
    var average = half_min + half_max;
    var factor = max - average;

    return (2.0 * rng.NextDouble() - 1.0) * factor + average;
}

Calling Console.WriteLine(GetRandomDouble(double.MinValue, double.MaxValue)); then correctly produces values between double.MinValue and double.MaxValue.

Then you just flesh out the two methods you desire, like this:

public double NextMin(double min)
{
    return GetRandomDouble(min, double.MaxValue);
}

public double NextMax(double max)
{
    return GetRandomDouble(double.MinValue, max);
}
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • It does indeed. But I generated 10000 random numbers between the range `(double.MinValue, double.MaxValue)` and they all had their exponents either 308, 307 or 306. What is the problem with exponents? – starikcetin Aug 04 '16 at 05:03
  • 3
    @S.TarıkÇetin - There's no problem with the exponent. That's mathematically correct. 90% of random numbers between `0.0` & `1.0` are greater than `0.1` & `0.1 * double.MaxValue` is `1.79769313486232E+307` so you should expect 90% of random numbers between `0.0` & `double.maxValue` to be greater than `1.79769313486232E+307`. – Enigmativity Aug 04 '16 at 05:07
  • So this is one of those moments when maths doesn't make any sense... I guess selecting mantissa and exponent seperately is the way to go for this situation. – starikcetin Aug 04 '16 at 05:10
  • 1
    @S.TarıkÇetin - Well then you don't have a uniform distribution. If you want a uniform distribution then you stick with this answer. Otherwise you're going for some sort of non-uniform distribution, like a bell curve. I think this is a case where the maths makes sense, but it's not intuitive because our human minds can't cope with numbers with 308 digits. – Enigmativity Aug 04 '16 at 05:15
  • 1
    @S.TarıkÇetin The math gives you a uniformly distributed random value across the given range, as you asked. Maybe you had something different in mind, but that's not math's fault. – dxiv Aug 04 '16 at 05:16
  • @dxiv - I've added a comment to your question to explain why yours doesn't work. – Enigmativity Aug 04 '16 at 05:19
  • @dxiv _(It was a joke.)_ – starikcetin Aug 04 '16 at 05:19
-1
private Random rng = new Random();

private double GetRandomDouble(double min, double max)
{
    // Get the base value, scale first and then shift.
    return rng.NextDouble()*(max - min) + min;
}

EDIT: I'm a bit bemused as to why this is working for me and not for others. I just ran this code is VS 2015.3 and not once in three runs did it detect an infinite value:

class Program
{
    static void Main(string[] args)
    {
        const int maxIterations = 100000;
        var infinityDetected = false;

        for (int i = 0; i < maxIterations; i++)
        {
            var d = GetRandomDouble(double.MinValue, double.MaxValue);

            if (double.IsInfinity(d))
            {
                infinityDetected = true;
                Console.WriteLine("Infinity detected");
                break;
            }

            Console.WriteLine(d);
        }

        if (!infinityDetected)
        {
            for (int i = 0; i < maxIterations; i++)
            {
                var d = GetRandomDouble(-1.0, double.MaxValue);

                if (double.IsInfinity(d))
                {
                    infinityDetected = true;
                    Console.WriteLine("Infinity detected");
                    break;
                }

                Console.WriteLine(d);
            }
        }

        if (!infinityDetected)
        {
            for (int i = 0; i < maxIterations; i++)
            {
                var d = GetRandomDouble(double.MinValue, 1.0);

                if (double.IsInfinity(d))
                {
                    Console.WriteLine("Infinity detected");
                    break;
                }

                Console.WriteLine(d);
            }
        }

        Console.ReadLine();
    }

    private static Random rng = new Random();

    private static double GetRandomDouble(double min, double max)
    {
        // Get the base value, scale first and then shift.
        return rng.NextDouble() * (max - min) + min;
    }
}
jmcilhinney
  • 50,448
  • 5
  • 26
  • 46
  • First chunk returns all Infinity. – starikcetin Aug 04 '16 at 03:46
  • @S.TarıkÇetin Although [Ideone](http://ideone.com/RY1K7S) doesn't output infinity. – Jonny Henly Aug 04 '16 at 03:56
  • 1
    I just ran a loop that called `GetRandomDouble(double.MinValue,double.MaxValue)` 100,000 times and not once did `double.IsInfinity` return `true` when passed the result. That said, the output doesn't look like a random spread so there's something amiss. – jmcilhinney Aug 04 '16 at 04:08
  • @jmcilhinney - I just ran this code and got `∞`. The OP is right. – Enigmativity Aug 04 '16 at 05:16
  • @Enigmativity, the OP might be right that they got infinity but I ran it and I didn't so I'm not sure what's different. As I said, I ran a loop that executed that method 100,000 times using the limits for `double` and had no issues at all. Based on your comments regarding distribution, I now realise that the output I saw was perfectly appropriate. As such, my code seems to work 100% as it should for me, but apparently not for others. I'm really not sure why that would be. – jmcilhinney Aug 04 '16 at 05:51
  • @jmcilhinney - I'd be interested to find out why. It really should have failed as the framework can't perform `double.MaxValue - double.MinValue`. I assume with the new code you posted you don't get "Infinity detected"? – Enigmativity Aug 04 '16 at 09:49
  • @Enigmativity, correct. It produced valid value every time. – jmcilhinney Aug 04 '16 at 12:05
-1

This should play more nicely with overflows.

// Range expanding for min
double.MaxValue - random.NextDouble() * (double.MaxValue - min);

// Range expanding for max 
double.MinValue + random.NextDouble() * (max - double.MinValue);

The second one is actually the same as the one you posted, and I don't see why that one wouldn't have worked.

dxiv
  • 16,984
  • 2
  • 27
  • 49
  • 1
    This would fail is `min` is less than `0.0` in the first method and `max` is greater than `0.0` in the second. Both would overflow. – Enigmativity Aug 04 '16 at 05:18
  • @Enigmativity Right, of course. Too late here to figure out how it could be done *without* losing 1-2 bits of precision as in your solution. +1 for that. – dxiv Aug 04 '16 at 05:23
  • I don't think you can avoid it. If the computation is `double.MaxValue - `double.MinValue` then you have to divide by `2.0` to make the result fit back inside a `double`. You have to lose precision. – Enigmativity Aug 04 '16 at 05:26
-2

Try this one:

random.NextDouble() * (double.MaxValue - min) + min;
random.NextDouble() * (double.MinValue + max) - max;
Steve Davis
  • 297
  • 1
  • 2
  • 8