C# Random(Long)
Asked Answered
O

3

6

I'm trying to generate a number based on a seed in C#. The only problem is that the seed is too big to be an int32. Is there a way I can use a long as the seed?

And yes, the seed MUST be a long.

Outflank answered 17/3, 2013 at 16:14 Comment(16)
Why do you need a long seed for a pseudorandom number?Supremacist
@J0HN I'm calculating where slimes spawn in minecraft.Outflank
@Outflank - Even if you use the Long that you've obtained, how can you guarantee that the psuedorandom number generated matches that of the Java implementation?Cutshall
That's greek for me. Why do you think using long as seed will help you? +100500 for @Cutshall comment(sorry, SO allows only one upvote :))Lesleylesli
@Cutshall I'm not sure what you mean but here is the algorithm:long RandomParameter = seed + (long)(x * x * 0x4c1906) + (long)(x * 0x5ac0db) + (long)(z * z) * 0x4307a7L + (long)(z * 0x5f24f) ^ 0x3ad8025f; Random rnd = new Random(Convert.ToInt32(RandomParameter)); if (rnd.Next(10) == 0) return true; else return false;Outflank
Do you have the original RNG algorithm that Minecraft uses?Amadoamador
@MatthewWatson You mean before I ported it from Java? Random rnd = new Random(seed + (long) (xPosition * xPosition * 0x4c1906) + (long) (xPosition * 0x5ac0db) + (long) (zPosition * zPosition) * 0x4307a7L + (long) (zPosition * 0x5f24f) ^ 0x3ad8025f); return rnd.nextInt(10) == 0;Outflank
Typical chicken-and-egg problem. You now need a really good random number generator to produce a sufficiently random seed. Starting a not-so-good random number generator with a really good seed is a complete waste of effort. Use the System.Security.Cryptography.RNGCryptoServiceProvider class.Spearmint
@Outflank - The Java version of Random will not necessarily be the same as the C# version. Therefore, it's very unlikely you're going to get the same output given the same input.Cutshall
@HansPassant Mind linking to an example on how I'd use it?Outflank
@Cutshall I just checked, they have the same first parameter: the seed.Outflank
@Outflank Unfortunately that doesn't guarantee the output will be the same. The number generated from the Random class (either in C# or Java), is not actually truly random in the mathematical sense. They take the seed and from that seed they perform various functions to give you what seems like a random number. The problem you have here is that both will give you a "random" number but that number won't necessarily be the same, even if the seed is the same, because they calculate that number differently.Cutshall
@Cutshall That sucks, thanks for clarification though. I found somebody who wrote a Random function that acts like java's in python, I'll port it across now.Outflank
@Outflank - Yup, as long as the internal implementation of the Random function matches up, you should get the same output. In that case, you don't even need the Random class and so you can create your own method that takes a Long.Cutshall
You could look at the source for java.lang.Random and just convert it to C#; it's probably not too hard. The algorithm is here: docs.oracle.com/javase/6/docs/api/java/util/…Amadoamador
The MedallionRandom NuGet package contains a port of Java's random number generator, which accepts a 64-bit seed.Altercation
D
3

For anyone seeing this question today, .NET 6 and upwards provides Random.NextInt64, which has the following overloads:

  • NextInt64()

    • Returns a non-negative random integer.
  • NextInt64(Int64)

    • Returns a non-negative random integer that is less than the specified maximum.
  • NextInt64(Int64, Int64)

    • Returns a random integer that is within a specified range.
Dyane answered 10/9, 2022 at 22:54 Comment(1)
These methods generate random 64-bit numbers. The question is how do you initialize a Random instance using a 64-bit seed, which is unrelated.Mercantile
A
2

Here's a C# version of Java.Util.Random that I ported from the Java Specification.

The best thing to do is to write a Java program to generate a load of numbers and check that this C# version generates the same numbers.

public sealed class JavaRng
{
    public JavaRng(long seed)
    {
        _seed = (seed ^ LARGE_PRIME) & ((1L << 48) - 1);
    }

    public int NextInt(int n)
    {
        if (n <= 0)
            throw new ArgumentOutOfRangeException("n", n, "n must be positive");

        if ((n & -n) == n)  // i.e., n is a power of 2
            return (int)((n * (long)next(31)) >> 31);

        int bits, val;

        do
        {
            bits = next(31);
            val = bits % n;
        } while (bits - val + (n-1) < 0);
        return val;
    }

    private int next(int bits)
    {
        _seed = (_seed*LARGE_PRIME + SMALL_PRIME) & ((1L << 48) - 1);
        return (int) (((uint)_seed) >> (48 - bits));
    }

    private long _seed;

    private const long LARGE_PRIME = 0x5DEECE66DL;
    private const long SMALL_PRIME = 0xBL;
}
Amadoamador answered 17/3, 2013 at 16:55 Comment(0)
A
0

I'd go for the answer provided here by @Dyppl: Random number in long range, is this the way?

Put this function where it's accessible to the code that needs to generate the random number:

long LongRandom(long min, long max, Random rand) 
{
    byte[] buf = new byte[8];
    rand.NextBytes(buf);
    long longRand = BitConverter.ToInt64(buf, 0);
    return (Math.Abs(longRand % (max - min)) + min);
}

Then call the function like this:

long r = LongRandom(100000000000000000, 100000000000000050, new Random());
Ammonify answered 4/2, 2015 at 15:45 Comment(2)
Per comments in link (and testing myself), this method does not work: "Doesn't work properly. LongRandom(long.MinValue, long.MaxValue, new Random()), always returns -9223372036854775808. In any case, Math.Abs() destroys one bit, leaving you with 63 random bits. You can't provide a 64-bit random number if you only have 63 random bits."Ferri
These method generates a random 64-bit number. The question is how do you initialize a Random instance using a 64-bit seed, which is unrelated.Mercantile

© 2022 - 2024 — McMap. All rights reserved.