C# 浮动错误计算

C# 浮动错误计算,c#,C#,结果必须是806603.77,但为什么我得到806603.8 float a = 855000.00f; float b = 48396.23f; float res = a - b; Console.WriteLine(res); Console.ReadKey(); 因为float的精度有限(32位)。如果需要更高的精度,请使用double或decimal。Afloat(也称为系统。Single)的精度大约相当于七位十进制数字。您的res差异需要八个有效十进制数字。因此,预计浮点中没有足

结果必须是806603.77,但为什么我得到806603.8

float a = 855000.00f;
float b = 48396.23f;

float res = a - b;
Console.WriteLine(res);
Console.ReadKey();

因为
float
的精度有限(32位)。如果需要更高的精度,请使用
double
decimal

A
float
(也称为
系统。Single
)的精度大约相当于七位十进制数字。您的
res
差异需要八个有效十进制数字。因此,预计
浮点
中没有足够的精度

decimal a = 855000.00M;
decimal b = 48396.23M;

decimal res = a - b;
Console.WriteLine(res);
Console.ReadKey();
补充:

一些额外的信息:接近806000(806000),一个
浮点数
只剩下四位用于小数部分。因此,对于
res
它必须在两者之间进行选择

806603 + 12/16 == 806603.75000000, and
806603 + 13/16 == 806603.81250000
它选择第一个,因为它最接近理想结果。但调用
ToString()
时,这两个值都输出为
“806603.8”
(Console.WriteLine(float)确实调用)。常规
ToString
调用最多显示7位有效十进制数字。要显示两个浮点数是不同的,即使它们以标准格式打印相同的内容,请使用格式字符串
“R”
,例如

Console.WriteLine(res.ToString("R"));
您应该改为使用,因为has
32位
具有7位精度,这就是结果不同的原因,另一方面
decimal
具有
128位
28-29位精度

decimal a = 855000.00M;
decimal b = 48396.23M;

decimal res = a - b;
Console.WriteLine(res);
Console.ReadKey();

输出:
806603.77

请注意,盲目使用十进制是不够的

阅读Oded发布的链接:

然后才决定使用适当的数字类型

不要陷入这样的思维陷阱:仅仅使用十进制就可以得到精确的结果;不会总是这样的

考虑以下代码:

Decimal d1 = 1;
Decimal d2 = 101;
Decimal d3 = d1/d2;
Decimal d4 = d3*d2; // d4 = (d1/d2) * d2 = d1

if (d4 == d1)
{
    Console.WriteLine("Yay!");
}
else
{
    Console.WriteLine("Urk!");
}
如果十进制计算是精确的,代码应该打印“耶!”因为d1应该和d4相同,对吗

嗯,没有


还要注意,十进制计算比双精度计算慢数千倍。它们并不总是适用于非货币计算(例如,计算像素偏移或物理对象,如速度,或涉及超越数的任何对象等)。

如果您想要精确的结果,则应使用DecimalFloat和Double,因为它们容易出现舍入问题。使用@Sergio推荐的
Decimal
。您可以找到更多信息,不仅是结果不是您想要的,
b
甚至不会包含您初始化它时使用的数字的精确表示形式。在这种情况下,
double
就足够了。另一个有趣的事实是,由于
decimal.MaxValue
79228…
,因此,有效数字以低于此数字开头的数字的精度高于有效数字较高的数字的精度。要理解我的意思,请考虑<代码> 800米/3m *3m < /代码>与<代码> 500米/3m *3m < /代码>。首先要注意的是,800和500都不能被3平均分割,因此商将有一个无限尾
666…
,这是一个
系统。十进制
必须在某个点以
…667
终止。尽管如此,由于800超出了
79228…
限制,而500低于该限制,精度不同。我说的是阈值
79228…
,其中精度从29位有效数字更改为28位有效数字。