gpt4 book ai didi

c# - 带有浮点文字与浮点变量的奇怪编译器行为

转载 作者:太空狗 更新时间:2023-10-29 20:08:53 25 4
gpt4 key购买 nike

我注意到 C# 编译器的 float 舍入/截断有一个有趣的行为。即,当 float 文字超出保证的可表示范围(7 位十进制数字)时,a) 将 float 结果显式转换为 float(语义上不必要的操作)和 b) 将中间计算结果存储在局部变量中都会更改输出。一个例子:

using System;

class Program
{
static void Main()
{
float f = 2.0499999f;
var a = f * 100f;
var b = (int) (f * 100f);
var c = (int) (float) (f * 100f);
var d = (int) a;
var e = (int) (float) a;
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);
Console.WriteLine(e);
}
}

输出是:

205
204
205
205
205

在我的电脑上的 JITted 调试构建中,b 的计算方式如下:

          var b = (int) (f * 100f);
0000005a fld dword ptr [ebp-3Ch]
0000005d fmul dword ptr ds:[035E1648h]
00000063 fstp qword ptr [ebp-5Ch]
00000066 movsd xmm0,mmword ptr [ebp-5Ch]
0000006b cvttsd2si eax,xmm0
0000006f mov dword ptr [ebp-44h],eax

而 d 的计算方式为

          var d = (int) a;
00000096 fld dword ptr [ebp-40h]
00000099 fstp qword ptr [ebp-5Ch]
0000009c movsd xmm0,mmword ptr [ebp-5Ch]
000000a1 cvttsd2si eax,xmm0
000000a5 mov dword ptr [ebp-4Ch],eax

最后,我的问题是:为什么输出的第二行与第四行不同?那个额外的 fmul 有这么大的不同吗?另请注意,如果 float f 中的最后一位(已经无法表示)数字被删除或什至减少,一切都会“原地踏步”。

最佳答案

您的问题可以简化为询问为什么这两个结果不同:

float f = 2.0499999f;
var a = f * 100f;
var b = (int)(f * 100f);
var d = (int)a;
Console.WriteLine(b);
Console.WriteLine(d);

如果您查看 .NET Reflector 中的代码,您会发现上面的代码实际上被编译为如下代码:

float f = 2.05f;
float a = f * 100f;
int b = (int) (f * 100f);
int d = (int) a;
Console.WriteLine(b);
Console.WriteLine(d);

浮点计算并不总是准确的。 2.05 * 100f 的结果并不完全等于 205,而是由于舍入误差而略小于 205。当这个中间结果被转换为整数时被截断。当存储为 float 时,它会四舍五入到最接近的可表示形式。这两种舍入方法给出了不同的结果。


关于您在写这篇文章时对我的回答的评论:

Console.WriteLine((int) (2.0499999f * 100f));
Console.WriteLine((int)(float)(2.0499999f * 100f));

计算完全在编译器中完成。上面的代码等同于:

Console.WriteLine(204);
Console.WriteLine(205);

关于c# - 带有浮点文字与浮点变量的奇怪编译器行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3088372/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com