我正在开发一款适用于Windows和Android的游戏,但它有一个我无法解决的问题。基本上我有一个带有一些按钮的4x5网格,这些按钮每秒填充一个必须为2,4或8的随机数。如果点击两个具有相同数字的按钮,则计算总和。这是一个firemonkey项目。
游戏运行正常,但您可以在下面的图片中看到问题。当我在我的Windows机器上运行游戏时,它会生成2,4或8.在android下它生成2,4, 7 和8.以这种方式创建随机数:
valueToOutput := Trunc(Exp(Ln(2) * (1+Random(3))));
该变量保存按钮中显示的数字。为什么我在windows和android中得到不同的结果?这是两个截图
我确信该函数是正确的,因为我已经绘制了它(exp(ln(2)*(1 + x))= http://prnt.sc/dmdc3u)并且当x是0,1或2时(=当随机数是0,1或2)。这可能是编译器的问题吗?
注意:我已经使用您在下面看到的解决方法解决了这个问题,但起初我使用了您可以在问题中看到的代码,我想了解发生了什么
valueToOutput := Trunc(Exp(Ln(2) * (1+Random(3))));
//this will always give 2, 4 or 8
if valueToOutput = 7 then
valueToOutput := valueToOutput + 1;
答案 0 :(得分:6)
对于相同的浮点控制状态,浮点计算对于相同的输入是可重复的。
有三个不同的输入,因此您的表达式应具有三个不同的可能输出。因此,唯一的解释是某些东西改变浮点控制状态,例如,程序执行期间的舍入模式,精度等。
如果浮点运算可以精确地执行计算,则不需要舍入为整数。但是如果你必须使用Round
而不是Trunc
至少四舍五入到最近。
也就是说,这绝对是执行随机选择2,4和8之一的离散任务的错误方法。这样做是这样的:
case Random(3) of
0:
Result := 2;
1:
Result := 4;
2:
Result := 8;
end;
另一种方法是将可能的输出放入一个数组中,然后选择它们:
Result := arr[Random(3)];
当有更多值可供选择时,这会变得更有吸引力。
一条黄金法则是,如果你可以避免使用浮点数那么做。浮点比整数算术更慢,更难以推理。仅在必要时使用它。
答案 1 :(得分:2)
将此作为答案发布,因为它不符合评论
我对androïd几乎一无所知,但我会在Windows上使用以下方法来缩小范围。可能,Androïd也存在类似的方法。
procdump -ma -e 1 Project1.exe
<强>代码强>
var
tmpRandom: Integer;
tmpLn: Extended;
tmpLnRandom: Extended;
tmpExp: Extended;
tmpTrunc: Int64;
procedure TForm1.btn1Click(Sender: TObject);
var
I: Int64;
begin
while true do
begin
tmpRandom := Random(3);
tmpLn := Ln(2);
tmpLnRandom := tmpLn * (1+tmpRandom);
tmpExp := Exp(tmpLnRandom);
tmpTrunc := Trunc(tmpExp);
I := tmpTrunc;
if (I and 1 = 1) then
raise Exception.CreateFmt('I = %0:d', [I]);
end;
end;
变量的示例布局
答案 2 :(得分:0)
我们没有看到整件事。例如,你说windows生成2,4或8,但我们在网格中看到16。你说Android生成7,但我们在网格中看到14。很明显,你在某个地方乘以2。我的分析是,因为2 * 4是8,安卓版本仅生成2,4和7,而不是8,因为正如大卫所说,你只有3个起始状态,所以必须只有三个结束状态。在这种情况下使用Trunc是一件麻烦事。我认为通过使用Round而不是Trunc来缓解事情,就像这样。
valueToOutput := Round(Exp(Ln(2) * (1+Random(3))));
如上所述,正如大卫所说,这不是正确的做法。