2011-04-29 69 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