2009-05-31 3 views
19

저는 Microsoft Visual C# 2008 Express에서 일하고 있습니다. C#에서 임의 번호 생성기가 임의로 나타나지 않는 이유는 무엇입니까?

나는이 코드 조각을 발견 :

public static int RandomNumber(int min, int max) 
    { 
     Random random = new Random(); 

     return random.Next(min, max); 
    } 

문제는 내가 그것을 100 회 이상 실행 한 것입니다, 그것은 항상 나에게 같은 대답을주고 때 내 분 = 0, 최대 = 1. 나는 매번 0을 얻는다. (나는 그것을 실행하기 위해 테스트 함수를 만들었습니다 - 실제로 - 나는 매번 0을 얻습니다). 내가 우연의 일치라고 믿는 데 어려움을 겪고 있습니다 ... 제가 이것을 시험하거나 시험하기 위해 할 수있는 다른 것이 있습니까? (나는 min = 0과 max = 10 그리고 처음 50 시간 동안 테스트를 재실행했다. 결과는 항상 "5"였고, 두번째 50hz 시간은 결과가 항상 "9"였다.

?? .. 난 항상 임의 화() 함수로 시작 VB에서 좀 더 지속적으로 임의 뭔가 ...

-Adeena

+16

"일관되게 무작위"가 정말 재밌다고 생각합니다. – jcollum

+0

나는 응용 프로그램의 목적에 따라 목소리를 고집하고 싶습니다. 의사 랜덤을 사용하면 응용 프로그램을 항상 해킹 할 수 있습니다. –

답변

47

min = 0 및 max = 1의 문제점은 min이 포함되며 max가 배타적이라는 것입니다. 그래서 조합에 대한 유일한 가능한 값은 다음의 과부하()가 0이 반환

+0

문제를 더욱 혼란스럽게 만들기 위해 설명서에는 maxValue가 더 커야한다는 내용이 나와 있습니다 minValue보다 크거나 같은 경우 따라서 random.Next (0,0)에 전달할 수 있으며 random 함수와 똑같이 작동합니다 .Next (0,1)는 지정된 입력 매개 변수와 일치하는 숫자가 없다고 생각하는 경우조차도 마찬가지입니다. – Kevin

-2

필요 그때 당신의 임의 함수를 실행) 임의 화를 (전화 나 또한 다음을 수행하십시오

Function RandomInt(ByVal lower As Integer, ByVal upper As Integer) As Integer 
    Return CInt(Int((upper - lower + 1) * Rnd() + lower)) 
End Function 

희망이 있습니다! :)

+0

왜 이것을 표시하지 않습니까? 나는 일관 되게이 임의의 숫자를 얻을 ... – Jason

+1

우리는 C# – TheSoftwareJedi

+1

논의하고 있기 때문에 당신은 진짜인가요? VB 질문에 대한 C# 답변을 몇 번이나 받았는지, 내가 뭘 잘못하고 있었는지 알아낼 수 있었는지 아십니까? 구문, 사람이 아니라 구문 ... jeezz ... – Jason

32
random = new Random(); 

이 (SEC)에 현재 시간 난수 발생기를 개시한다. 시스템 클럭이 변경되기 전에 함수를 여러 번 호출하면 난수 생성기가 동일한 값으로 시작되므로 동일한 값 시퀀스가 ​​반환됩니다.

+5

Random() 생성자에 대한 설명서는이 문제를 거의 그대로 설명합니다. http://msdn.microsoft.com/en-us/library/h343ddh9.aspx – las3rjock

7

이다

32 비트보다 maxValue를 이상의 정수 MINVALUE에 덜 서명; 즉 반환 값의 범위에는 minValue가 포함되지만 MaxValue는 포함되지 않습니다. minValue가 maxValue와 같으면 minValue가 리턴됩니다.

0이 반환 할 수있는 유일한 값입니다. 아마도 당신은 random.NextDouble()을 원할 것입니다. 0과 1 사이의 double을 반환합니다.

18

Next에 대한 래퍼 메서드를 만들지 마십시오. Random 클래스의 새로운 인스턴스를 만드는 사이클을 낭비합니다. 같은 것을 사용하십시오!

Random myRand = new Random(); 

for(int i = 0; i < 10; i++) 
{ 
    Console.WriteLine(myRand.Next(0, 10).ToString()); 
} 

이렇게하면 10 개의 임의 값을 얻을 수 있습니다.

랜덤은 의사 랜덤이며 (모든 구현이 그렇듯이), 동일한 시드로 인스턴스를 100 개 생성하면 동일한 결과가 100 개 발생합니다. 수업을 재사용하고 있는지 확인하십시오.

또한 MinValue는 포괄적이며 MaxValue는 독점이라는 점에 유의하십시오. 네가 원한다면, myRand를해라. 다음 (0, 2).

+0

10 회 이상하는 것은 테스트에 불과합니다 ... "최대"가 독점 적이라는 것을 깨닫지 못했습니다. – adeena

+1

때로는 조롱 할 수 있도록 임의의 래퍼 메서드 (또는 래퍼 클래스)를 원할 것입니다. – BlackWasp

+0

@adeena, BlackWasp : 어떤 이유에서든 과부하/감싸기가 필요한 경우 이동하십시오. 그래도 다른 무작위 값을 얻으려면 다음을 사용하고 같은 Random 클래스를 사용하십시오. 그렇게하면 같은 씨앗을 가진 랜덤을 많이 먹을 위험이 없습니다. – Eric

3

다른 답변에서 이미 언급 된 0-1 문제 외에도 0-10 범위를 찾고 동일한 결과를 연속으로 50 회 얻을 때 문제가 실제로 발생합니다.

new Random()은 타이머 (현재 초)에서 초기화 된 시드로 임의의 숫자를 반환하지만이 코드를 초당 50 번 호출합니다. MSDN은 다음과 같이 제안합니다. "성능을 향상 시키려면 새로운 임의 번호를 반복 생성하여 하나의 난수를 생성하는 대신 시간에 따라 많은 난수를 생성하는 임의의 하나를 만듭니다." 랜덤 생성기를 메서드 외부에서 생성하면 성능이 향상 될뿐만 아니라 "비 임의성"문제가 해결됩니다.

또한 "고품질"의 의사 난수가 필요한 경우 this post을 시스템 공급 장치보다 더 나은 의사 난수 생성기로 간주하십시오. 다른 언급으로, 임의의 초당 여러 번 건설되고

1

는 씨앗과 같은 두 번째 사용, 그래서 루프 외부에서 임의의 생성자를 넣어,이 같은 매개 변수로 전달할 것 :

public static int RandomNumber(Random random, int min, int max) 
{ 
    return random.Next(min, max); 
} 

다른 사람들이 언급했듯이 max는 배타적이므로 0이나 1을 원한다면 [최소, 최대] 또는 더 큰 최대 값으로 [0,2]를 사용하고 이진 AND를 사용해야합니다.

public static int RandomOneOrZero(Random random) 
{ 
    return random.Next(0, int.MaxValue) & 1; 
} 
+1

랜덤 개체는 정적 변수로 선언 될 수도 있으므로 매번 메서드에 전달할 필요가 없습니다. – Whatsit

+0

나는 RandomOneOrZero 메서드를 좋아한다. [0,2]를 사용하는 것보다 더 무작위 적이라는 것을 알고 있거나 다른 이유로 사용하고 계십니까? –

+0

@Matt : 어느 쪽이라도 같은 양의 무작위가있을 것입니다. 나는 그것을 머리 위로 털어 냈다. @Whatsit : 좋은 지적입니다. 그녀의 유스 케이스가 무엇인지 확신 할 수 없었기 때문에 그냥 추측했다. 정적 또는 인스턴스 변수가 더 적절할 것입니다. –

6

Random.Next은 정수를 반환하므로 항상 0이됩니다. 당신은 당신이 이런 식으로, 당신의 임의의 인스턴스를 재사용해야한다, 또한 0과 1 사이의 숫자를 반환하는, Random.NextDouble를 호출해야합니다

[ThreadStatic] 
static Random random; 
public static Random Random { 
    get { 
     if (random == null) random = new Random(); 
     return random; 
    } 
} 
public static int RandomInteger(int min, int max) 
{ 
    return Random.Next(min, max); 
} 
public static double RandomDouble() //Between 0 and 1 
{ 
    return Random.NextDouble(); 
} 

당신이 안전한 암호화 난수를하려면 RNGCryptoServiceProvider 클래스를 사용; this article

편집 참조 :이 특정 질문에 대한 답이기 때문에 경계가 있어야한다, 스레드 안전

+2

-1이 코드는 위험 할 정도로 잘못되었습니다. 랜덤은 스레드로부터 안전하지 않으며 잠금 또는 스레드 인스턴스를 제공하지 않고 공유 인스턴스에 액세스합니다. –

+0

수정 됨; 조언을 주셔서 감사합니다 – SLaks

+0

쿨, -1 제거되었습니다. –

1

이 어떤 답변에 대한 추가 사항입니다 (0, 2) (0, 1).

그러나 정적 래퍼 메서드를 사용하려는 경우 Random은 스레드로부터 안전하지 않으므로 자체 동기화 메커니즘을 제공하거나 스레드 인스턴스를 제공해야한다는 것을 기억해야합니다.

public static class ThreadSafeRandom 
{ 
    private static readonly Random seed = new Random(); 

    [ThreadStatic] 
    private static Random random; 

    public static int Next(int min, int max) 
    { 
     if (random == null) 
     { 
      lock (seed) 
      { 
       random = new Random(seed.Next()); 
      } 
     } 

     return random.Next(min, max); 
    } 

    // etc. for other members 
} 
+0

Environment.TickCount (기본 시드)는 시드에 충분합니다. 별도의 시드 인스턴스를 만들 필요가 없습니다. – SLaks

+1

@SLaks - Environment.TickCount를 사용하는 경우 스레드 당 인스턴스마다 동일한 시드를 얻을 가능성이 높습니다. 이로 인해 동일한 시퀀스의 의사 임의 값이 생성됩니다. 나는 이것이 당신이 원하는 것이라고 의심합니다. 그들에게 명시 적으로 다른 씨앗을 주면이 행동 패턴이 발생하지 않게됩니다. –

0

여러 포스터 랜덤()는 시스템 클록 및 기타의 제 2 전류에 기초하여 시드를 사용하는 것을 언급 한 다음은 각 스레드 당 발생기를 시드 한 발전기를 사용하는 대부분 비 차단 구현은 같은 초에 생성 된 무작위의 인스턴스는 동일한 시드를 갖습니다. 이것은 잘못되었습니다. 무작위의 매개 변수없는 생성자의 시드는 부팅 시간 이후의 틱 수 또는 밀리 초 수를 기반으로합니다. 이 값은 대부분의 시스템에서 약 15 밀리 초마다 업데이트되지만 하드웨어 및 시스템 설정에 따라 달라질 수 있습니다.

0

난 그냥 현재 날짜 시간 (밀리 초)의 마지막 두 자리를 복용하여 난수를 생성하는 매우 간단하지만 효과적인 방법을 발견 :

int seed = Convert.ToInt32(DateTime.Now.Millisecond.ToString().Substring(1, 2)); 
    int cnr = new Random(seed).Next(100); 

그것은 원유입니다,하지만 작품! :-)

물론 100 회마다 동일한 수를 통계적으로 생성합니다. 또는 세 자리 숫자를 모두 사용하거나 초 정도의 다른 datetime 값과 연결할 수 있습니다.

1

"random.Next (min, max)"라인을 잘못 이해하고 있습니다."min"은 무작위로 생성 될 수있는 가장 낮은 숫자 대신 사용됩니다. "max"는 생성이 허용되지 않는 가장 낮은 번호 대신에 그려지는 가장 큰 번호의 자리에 있지 않습니다. 그래서 라인이 random.Next (0, 1) 일 때 기본적으로 0 만 그릴 수 있습니다.

관련 문제