如果我们在控制台应用程序上执行以下C#代码,我们将收到一条消息The sums are Not equal.
如果我们在取消注释该行后执行它System.Console.WriteLine(),我们将收到一条消息The sums are equal.
static void Main(string[] args)
{
float f = Sum(0.1f, 0.2f);
float g = Sum(0.1f, 0.2f);
//System.Console.WriteLine("f = " + f + " and g = " + g);
if (f == g)
{
System.Console.WriteLine("The sums are equal");
}
else
{
System.Console.WriteLine("The sums are Not equal");
}
}
static float Sum(float a, float b)
{
System.Console.WriteLine(a + b);
return a + b;
}
Run Code Online (Sandbox Code Playgroud)
这种行为的实际原因是什么?
我有一个用C#编写的应用程序,它也会调用一些C代码.C#代码获取一些双重作为输入,对其执行一些计算,将其传递给在其上执行自己计算的本机层,然后传递回C#层.
如果我在不同的机器上运行相同的exe/dll(所有这些都是英特尔的x64),我得到的最终结果是否可能在不同的机器上有所不同?
从时间戳(TDateTime)计算32位ID时,我得到一个奇怪的错误.在某些情况下,不同处理器的值不同.
该fTimeStamp字段是从DoubleSQLite数据库中的字段中读取的.下面的代码计算一个32位ID(lIntStamp)fTimeStamp,但在某些(罕见)情况下,即使源数据库文件完全相同(即文件中存储的Double相同),不同计算机上的值也不同.
...
fTimeStamp: TDateTime
...
var
lIntStamp: Int64;
begin
lIntStamp := Round(fTimeStamp * 864000); //86400=24*60*60*10=steps of 1/10th second
lIntStamp := lIntStamp and $FFFFFFFF;
...
end;
Run Code Online (Sandbox Code Playgroud)
TDateTime(Double)的精度是15位数,但代码中的舍入值仅使用11位数,因此应该有足够的信息正确舍入.
提一个值的例子:在特定的测试运行中,lIntStampWindows计算机上的值为74AE6699B,iPad上的值为74AE699A(=最后一位不同).
Round每个平台上的功能实现不同吗?
PS.我们的目标平台目前是Windows,MacOS和iOS.
编辑:
我根据评论做了一个小测试程序:
var d: Double;
id: int64 absolute d;
lDouble: Double;
begin
id := $40E4863E234B78FC;
lDouble := d*864000;
Label1.text := inttostr(Round(d*864000))+' '+floattostr(lDouble)+' '+inttostr(Round(lDouble));
end;
Run Code Online (Sandbox Code Playgroud)
Windows上的输出是:
36317325723 36317325722.5 36317325722
Run Code Online (Sandbox Code Playgroud)
在iPad上输出是:
36317325722 36317325722.5 36317325722
Run Code Online (Sandbox Code Playgroud)
区别在于第一个数字,它显示了中间计算的舍入,因此问题发生是因为x86具有比ARM(64位)更高的内部精度(80位).