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)
问题是,从返回值中减去1getDeckSize()
显示您的牌组具有正确数量的元素(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()
也不是一种可靠的方法