Nice programing

난수 생성기는 하나의 난수 만 생성

nicepro 2020. 9. 29. 18:39
반응형

난수 생성기는 하나의 난수 만 생성


다음과 같은 기능이 있습니다.

//Function to get random number
public static int RandomNumber(int min, int max)
{
    Random random = new Random();
    return random.Next(min, max);
}

내가 부르는 방법 :

byte[] mac = new byte[6];
for (int x = 0; x < 6; ++x)
    mac[x] = (byte)(Misc.RandomNumber((int)0xFFFF, (int)0xFFFFFF) % 256);

런타임 중에 디버거로 해당 루프를 실행하면 다른 값이 표시됩니다 (원하는 값). 그러나 해당 코드 아래에 중단 점을 두 줄이면 "mac"배열의 모든 구성원이 동일한 값을 갖습니다.

왜 그럴까요?


할 때마다 new Random()시계를 사용하여 초기화됩니다. 즉, 타이트한 루프에서 동일한 값을 여러 번 얻습니다. 단일 Random인스턴스를 유지 Next하고 동일한 인스턴스 에서 계속 사용해야 합니다.

//Function to get a random number 
private static readonly Random random = new Random(); 
private static readonly object syncLock = new object(); 
public static int RandomNumber(int min, int max)
{
    lock(syncLock) { // synchronize
        return random.Next(min, max);
    }
}

편집 (댓글 참조) : lock여기에 왜 필요한 가요?

기본적으로 인스턴스 Next의 내부 상태를 변경합니다 Random. 여러 스레드에서 동시에이 작업을 수행하는 경우 "우리는 결과를 훨씬 더 무작위로 만들었습니다"라고 주장 있지만 실제로 수행하는 작업은 잠재적으로 내부 구현을 깨뜨리는 것이며 동일한 숫자를 얻기 시작할 수도 있습니다. 다른 스레드에서 수도 와 수도 있지 - 문제. 하지만 내부적으로 일어나는 일에 대한 보장은 더 큰 문제입니다. 스레드 안전성을 보장 Random하지 않기 때문 입니다. 따라서 두 가지 유효한 접근 방식이 있습니다.

  • 다른 스레드에서 동시에 액세스하지 않도록 동기화
  • Random스레드마다 다른 인스턴스 사용

어느 쪽이든 괜찮을 수 있습니다. 그러나 동시에 여러 호출자로부터 단일 인스턴스를 뮤텍스하는 것은 문제를 요구하는 것입니다.

lock이러한 방법의 첫 번째 (간단) 달성; 그러나 다른 접근 방식은 다음과 같습니다.

private static readonly ThreadLocal<Random> appRandom
     = new ThreadLocal<Random>(() => new Random());

그러면 스레드 단위이므로 동기화 할 필요가 없습니다.


애플리케이션 전체에서 쉽게 재사용 할 수 있도록 정적 클래스가 도움이 될 수 있습니다.

public static class StaticRandom
{
    private static int seed;

    private static ThreadLocal<Random> threadLocal = new ThreadLocal<Random>
        (() => new Random(Interlocked.Increment(ref seed)));

    static StaticRandom()
    {
        seed = Environment.TickCount;
    }

    public static Random Instance { get { return threadLocal.Value; } }
}

그런 다음 다음과 같은 코드와 함께 정적 임의 인스턴스를 사용할 수 있습니다.

StaticRandom.Instance.Next(1, 100);

Mark의 솔루션은 매번 동기화해야하므로 비용이 많이들 수 있습니다.

스레드 별 스토리지 패턴을 사용하여 동기화 필요성을 해결할 수 있습니다.


public class RandomNumber : IRandomNumber
{
    private static readonly Random Global = new Random();
    [ThreadStatic] private static Random _local;

    public int Next(int max)
    {
        var localBuffer = _local;
        if (localBuffer == null) 
        {
            int seed;
            lock(Global) seed = Global.Next();
            localBuffer = new Random(seed);
            _local = localBuffer;
        }
        return localBuffer.Next(max);
    }
}

두 가지 구현을 측정하면 상당한 차이를 확인할 수 있습니다.


여기 에서 내 대답 :

올바른 솔루션을 반복 하십시오 .

namespace mySpace
{
    public static class Util
    {
        private static rnd = new Random();
        public static int GetRandom()
        {
            return rnd.Next();
        }
    }
}

따라서 다음을 호출 할 수 있습니다.

var i = Util.GetRandom();

all throughout.

If you strictly need a true stateless static method to generate random numbers, you can rely on a Guid.

public static class Util
{
    public static int GetRandom()
    {
        return Guid.NewGuid().GetHashCode();
    }
}

It's going to be a wee bit slower, but can be much more random than Random.Next, at least from my experience.

But not:

new Random(Guid.NewGuid().GetHashCode()).Next();

The unnecessary object creation is going to make it slower especially under a loop.

And never:

new Random().Next();

Not only it's slower (inside a loop), its randomness is... well not really good according to me..


I would rather use the following class to generate random numbers:

byte[] random;
System.Security.Cryptography.RNGCryptoServiceProvider prov = new System.Security.Cryptography.RNGCryptoServiceProvider();
prov.GetBytes(random);

1) As Marc Gravell said, try to use ONE random-generator. It's always cool to add this to the constructor: System.Environment.TickCount.

2) One tip. Let's say you want to create 100 objects and suppose each of them should have its-own random-generator (handy if you calculate LOADS of random numbers in a very short period of time). If you would do this in a loop (generation of 100 objects), you could do this like that (to assure fully-randomness):

int inMyRandSeed;

for(int i=0;i<100;i++)
{
   inMyRandSeed = System.Environment.TickCount + i;
   .
   .
   .
   myNewObject = new MyNewObject(inMyRandSeed);  
   .
   .
   .
}

// Usage: Random m_rndGen = new Random(inMyRandSeed);

Cheers.


Every time you execute

Random random = new Random (15);

It does not matter if you execute it millions of times, you will always use the same seed.

If you use

Random random = new Random ();

You get different random number sequence, if a hacker guesses the seed and your algorithm is related to the security of your system - your algorithm is broken. I you execute mult. In this constructor the seed is specified by the system clock and if several instances are created in a very short period of time (milliseconds) it is possible that they may have the same seed.

If you need safe random numbers you must use the class

System.Security.Cryptography.RNGCryptoServiceProvider

public static int Next(int min, int max)
{
    if(min >= max)
    {
        throw new ArgumentException("Min value is greater or equals than Max value.");
    }
    byte[] intBytes = new byte[4];
    using(RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
    {
        rng.GetNonZeroBytes(intBytes);
    }
    return  min +  Math.Abs(BitConverter.ToInt32(intBytes, 0)) % (max - min + 1);
}

Usage:

int randomNumber = Next(1,100);

just declare the Random class variable like this:

    Random r = new Random();
    // ... Get three random numbers.
    //     Here you'll get numbers from 5 to 9
    Console.WriteLine(r.Next(5, 10));

if you want to get different random number each time from your list then use

r.Next(StartPoint,EndPoint) //Here end point will not be included

Each time by declaring Random r = new Random() once.


There are a lot of solutions, here one: if you want only number erase the letters and the method receives a random and the result length.

public String GenerateRandom(Random oRandom, int iLongitudPin)
{
    String sCharacters = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ123456789";
    int iLength = sCharacters.Length;
    char cCharacter;
    int iLongitudNuevaCadena = iLongitudPin; 
    String sRandomResult = "";
    for (int i = 0; i < iLongitudNuevaCadena; i++)
    {
        cCharacter = sCharacters[oRandom.Next(iLength)];
        sRandomResult += cCharacter.ToString();
    }
    return (sRandomResult);
}

참고URL : https://stackoverflow.com/questions/767999/random-number-generator-only-generating-one-random-number

반응형