Java 为什么Math.random忽略了最后一个元素?

Java 为什么Math.random忽略了最后一个元素?,java,Java,我正在创建一个简单的方法来模拟洗牌。我的想法是存储原始组的大小,并重复循环,只要大小不是负值 在循环过程中,我从列表中复制一个对象(卡),并将其放置在另一个列表中。从原始列表中删除,然后继续循环 while(size >= 0){ int random = (int) ((Math.random() * size) + 0); shuffledDeck.add(this.orderedDeck.get(random)); ordere

我正在创建一个简单的方法来模拟洗牌。我的想法是存储原始组的大小,并重复循环,只要大小不是负值

在循环过程中,我从列表中复制一个对象(卡),并将其放置在另一个列表中。从原始列表中删除,然后继续循环

while(size >= 0){
        int random = (int) ((Math.random() * size) + 0);    
        shuffledDeck.add(this.orderedDeck.get(random));
        orderedDeck.remove(random);
        size--;
    }
这个特殊甲板的尺寸是

int size=this.getDeckSize()-1//51(52张卡,从0到51)

我的问题是,在几次不同的尝试中,洗牌组中的最后一张牌始终与非洗牌组中的最后一张牌相同。这表明
random
永远不等于
size-1


我怎样才能使最后一张牌能够被洗牌呢

(换句话说,
random
为什么总是等于
size-1
?)

Math.random()
从不返回
1.0
,原因如下:

返回带正号的双精度值,大于或等于0.0且小于1.0

即使它确实返回
1.0
,它也会以极小的概率返回,并且您的代码会向下舍入任何其他值,因此您仍然无法统一地获得所需的结果

正如其他人所注意到的,代码中还有一些算术错误,但即使更正它们也不会产生正确分布的随机值

对于此任务,不应使用
Math.random()
,而应使用,该函数旨在正确返回所需范围内的统一值

正确处理随机数据源很棘手。根据经验,如果您发现自己在对随机值进行算术运算,则很可能是您做错了什么(例如生成了不一致的结果),您应该寻找一个现有函数,该函数提供您所寻找的随机性类型。

Math.random()
从不返回
1.0
,正如秘书长所解释的:

int size = this.getDeckSize()-1; //51 (52 cards, from 0 to 51)
返回带正号的双精度值,大于或等于0.0且小于1.0

即使它确实返回
1.0
,它也会以极小的概率返回,并且您的代码会向下舍入任何其他值,因此您仍然无法统一地获得所需的结果

正如其他人所注意到的,代码中还有一些算术错误,但即使更正它们也不会产生正确分布的随机值

对于此任务,不应使用
Math.random()
,而应使用,该函数旨在正确返回所需范围内的统一值

正确处理随机数据源很棘手。根据经验法则,如果你发现自己在对随机值进行算术运算,那么很可能你做错了什么(比如生成不一致的结果),你应该寻找一个现有的函数,它提供了你想要的随机性类型

int size = this.getDeckSize()-1; //51 (52 cards, from 0 to 51)
问题是,从返回值中减去1
getDeckSize()
显示您的牌组具有正确数量的元素(52张牌)。你不应该减去1


问题是,从返回值中减去1
getDeckSize()
显示您的牌组具有正确数量的元素(52张牌)。您不应该减去1。

看起来
size
已初始化为
orderedDeck.size()-1
。 由于
(int)(Math.random()*size)
返回范围
[0,size)
中的一个值,即,
size
本身从未包含在内, 最后一个元素永远不会被选中

您可以使用
size+1
作为上限,而不是
size
来修复:

while (size >= 0) {
  int random = (int) (Math.random() * (size + 1));
  shuffledDeck.add(orderedDeck.get(random));
  orderedDeck.remove(random);
  size--;
}
但请不要使用此技术创建无序列表。

目前的做法效率很低, 因为从列表中间删除元素效率很低。 它将是更好的,非常容易实现有效的排序使用。 例如:

Random random = new Random();
for (int i = list.size() - 1; i > 0; i--) {
  int j = random.nextInt(i);
  int tmp = list.get(i);
  list.set(i, list.get(j));
  list.set(j, tmp);
}

看起来
size
已初始化为
orderedDeck.size()-1
。 由于
(int)(Math.random()*size)
返回范围
[0,size)
中的一个值,即,
size
本身从未包含在内, 最后一个元素永远不会被选中

您可以使用
size+1
作为上限,而不是
size
来修复:

while (size >= 0) {
  int random = (int) (Math.random() * (size + 1));
  shuffledDeck.add(orderedDeck.get(random));
  orderedDeck.remove(random);
  size--;
}
但请不要使用此技术创建无序列表。

目前的做法效率很低, 因为从列表中间删除元素效率很低。 它将是更好的,非常容易实现有效的排序使用。 例如:

Random random = new Random();
for (int i = list.size() - 1; i > 0; i--) {
  int j = random.nextInt(i);
  int tmp = list.get(i);
  list.set(i, list.get(j));
  list.set(j, tmp);
}

你说你有52张牌,然后继续说大小是51张。大小应该是牌的数量,即52张。(
Math.random()
如果你担心的话,永远不会返回1.0)你考虑过
new random().nextInt(size)
?请编辑你的代码以显示一个。什么是
int random=(int)((Math.random)()*大小)+0);
for?为什么要加0?你说你有52张牌,然后继续说大小是51。大小应该是牌的数量,即52张。(
Math.random()
如果你担心的话,永远不会返回1.0)你考虑过
new random().nextInt(大小)
?请编辑您的代码以显示。什么是
int random=(int)((Math.random()*size)+0)
for?为什么要添加0?从RNG返回
1.0
不是问题,因为这会给出一个太大的索引。明确提到将
double
转换为
int
也可能有助于此答案。
数学。如果您增加
大小,随机
应该可以正常工作e> 按1,但是
nextInt
确实看起来更合适,更不容易出错。@code学徒甚至纠正算术错误
Math.random()
也不是一种可靠的方法