2011-04-29 50 views
23

我在使用的Java類的麻煩Random類,如果我這樣做:的Java隨機給予負數

Random rng = new Random(seed) // seed == 29 in this example 

String ss = ""; 
     for(int i = 0; i < 10; i++) 
     { 
      int s = rng.nextInt(); 
      ss += Integer.toString(s); 
      ss +="\n"; 
     } 

這就是我回來:

-1169335537 
-2076183625 
1478047223 
1914482305 
722089687 
2094672350 
-1234724057 
-1614953544 
-321574001 
1000360613 

從我讀這應該只是回到正面的數字開始?

這可能有點牽強附會,但它無法在Windows 7 64位上運行64位機器?

任何幫助都是非常棒的,需要在今天完成這項任務!

+0

只相信你在javadocs中閱讀的內容。和(當然)**閱讀javadocs **。 – 2011-04-29 04:07:36

+3

注意'Math.abs'不會在2中工作一次。 (提示:不要使用靜態可變對象) – 2011-04-29 09:53:55

回答

46

Java docs for nextInt()

所有2 可能INT值的生成(大致)相同的概率。

一種方法是使用下面的變換:

s = rng.nextInt() & Integer.MAX_VALUE; // zero out the sign bit 

這樣的事情需要(而不是使用絕對值或否定)的原因是,Integer.MIN_VALUE的絕對值太大,無法在變成了一個正整數。也就是說,由於溢出,Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUEInteger.MIN_VALUE == -Integer.MIN_VALUE。上面的轉換保留了大致均勻的分佈屬性:如果您編寫了一個產生和測試循環,它只丟掉了Integer.MIN_VALUE並返回了其他所有值的絕對值,那麼正整數將爲零的兩倍。通過將Integer.MIN_VALUE映射到零,這使得零的概率與正整數一致。

下面是另一種方法,這實際上可以是一點點更快(雖然我沒有基準它):

int s = rng.next(Integer.SIZE - 1); // Integer.SIZE == 32 

這將產生具有31隨機低階位(和0作爲整數保證非負值)。但是(如在由JJB的評論中指出),因爲next(int)Random一個protected方法,你就必須繼承Random揭露方法(或提供方法的合適的代理):

public class MyRandom extends Random { 
    public MyRandom() {} 
    public MyRandom(int seed) { super(seed); } 

    public int nextNonNegative() { 
     return next(Integer.SIZE - 1); 
    } 
} 

另一種方法是使用包裝4字節數組的ByteBuffer。然後,您可以生成一個隨機的四個字節(通過調用nextBytes(byte[])),將符號位置零,然後將該值作爲int讀取。我不認爲這提供了比上述任何優勢,但我認爲我只是把它扔在那裏。它基本上與我的第一個解決方案相同(用Integer.MAX_VALUE掩蓋)。

在這種應答的早期版本,我建議使用:

int s = rng.nextInt(Integer.MAX_VALUE); 

然而,根據the docs這將產生範圍爲0(含)的整數Integer.MAX_VALUE(獨家)。換句話說,它不會生成值Integer.MAX_VALUE。另外,事實證明next(int)總是會比nextInt(int)更快。

+1

然而,Random.next()是受保護的,所以你不能直接調用它。你可以繼承Random類,並且很容易地暴露nextPositiveInt(),它會返回下一個(31)。 – jjb 2014-10-28 20:30:38

+0

@jjb - 好點。我會更新答案以澄清。 – 2014-10-28 21:09:19

+1

'Integer.SIZE - 1'會稍微好一些。 – 2015-06-24 14:38:14

8

負數是允許的 - 也許您已閱讀過類似的隨機方法nextInt(int)其中確實將返回值限制爲零或更大。

+0

正如Ted所說的,'nextInt(Integer.MAXVALUE)'省略了'Integer.MAXVALUE',所以它有點像顯而易見的那樣好'Math.abs'獲得一個值錯誤('Integer.MAXVALUE')。 – 2015-06-24 14:36:22

0

每文檔http://download.oracle.com/javase/6/docs/api/java/util/Random.html#nextInt():

返回下一個僞,從這個隨機數生成器的序列中均勻分佈的int值。 nextInt的一般合約是一個int值僞隨機生成並返回。所有2^32個可能的int值都以(近似)相等的概率產生。

只需乘以-1,如果該值爲負

+2

乘以-1不是一個好主意。首先,它不起作用:「Integer.MIN_VALUE」的否定又是「Integer.MIN_VALUE」(由於溢出),所以你不能以這種方式去除所有的負數。即使它起作用,結果也是非均勻分佈:零將有任何正整數的一半概率。 – 2014-02-26 15:09:29

0
int s = rng.nextInt(seed); //seed 29 in this case 

這將具有結合的到。

+0

完美!不知道爲什麼這是downvoted! – smac89 2017-08-09 22:32:14

7

既然有正數或負數的一個平等的機會,爲什麼不只是:

Math.abs(rand.nextInt()) 

尼斯和容易!

+5

這不起作用。從[Math.abs(int)']文檔(https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#abs-int-):「請注意,如果參數等於「Integer.MIN_VALUE」的值,則表示最負的可表示的「int」值,結果是相同的值,這是負值。「 – 2016-05-29 04:56:26

+14

然後他們應該調用方法Math.absExceptIfTheArgumentIsEqualToIntegerMinValueInWhichCaseGoodBloodyLuckToYou(int); – kaifong 2016-07-08 12:26:39

0

如果您恰好使用可能具有負值的數字,則可以使用條件聲明自動將該值與負值相乘,從而將其轉化爲正值。您也可以使用相同的方法將正值轉換爲負值。

示例如下。

// Turn a negative value into its positive correspondent value. 
// If the value is already a positive value, nothing will happen to it. 
int a = -5; 
a = a < 0? a * -1 : a; 

// Turn a positive value into its negative correspondent value. 
// If the value is already a negative value, nothing will happen to it. 
int b = 5; 
b = b > 0? b * -1 : b; 
+0

不幸的是,這對於'Integer.MIN_VALUE'不起作用,因爲'Integer.MIN_VALUE == -Integer.MIN_VALUE'由於溢出。 – 2017-07-05 19:42:02

+0

要解決整數最小值問題或最大值問題,如果您不介意數字是一個數字,您可以這樣做,b = b <0? b == Integer.MIN_VALUE? (b + 1)* -1:b * -1:b; – 2017-07-14 02:46:51

+0

如果您需要準確的數字,您需要第二行來正確糾正溢出問題。上面的解決方案僅適用於使用隨機數的情況,不介意數字可以是一位數字。 – 2017-07-14 02:53:37