将 double 转换为 float 出错 - C#

Convert double to float goes wrong - C#

提问人:tamir1020 提问时间:1/11/2022 更新时间:1/14/2022 访问量:984

问:

我需要计算类型的边界rectangleF

由于某种原因,从到的铸造没有得到应有的精确评估doublefloat

这是此类计算的一个例子


float MinX = 0f, MaxX = 0f;
float MinY = 0f, MaxY = 0f;
float BoundsWidth = 0.2f;
float BoundsHeight = 0.1f;
double BoundsY = 2333638.6551984739;
double BoundsX = 895.0999755859375;

MinX = (float)BoundsX;
MinY = (float)BoundsY;

var MaxX_Defect = BoundsX + BoundsWidth;
var MaxY_Defect = BoundsY + BoundsHeight;
MaxX = (float)(MaxX_Defect);
MaxY = (float)(MaxY_Defect);

当我尝试计算最高值时,它的评估结果不是MaxY-MinY00.1f

我该如何解决这个问题?

C# 强制转换 浮点 精度

评论

0赞 stersym 1/11/2022
你试过 TryParse 吗?
0赞 Lasse V. Karlsen 1/11/2022
float精度不够。你可以试试这个: ,它将输出 0。float a = 2333638; float b = a + 0.1f; Console.WriteLine(b - a);
0赞 ChrisBD 1/11/2022
通过将 a 转换为 a,您可以降低精度doublefloat
0赞 Franz Gleichmann 1/11/2022
浮点数的精度有限。就这么简单。
0赞 Lasse V. Karlsen 1/11/2022
你可以用它来获得更多的精度,但精度也受到限制,所以如果你有一个足够大的数字,你会得到同样的问题。具体来说,如果你在我的其他评论中做我的例子,但切换到你将需要使用一个数字,比如有同样的问题。doubledoubledoubleb-adouble2333638000000000

答:

1赞 Eric Postpischil 1/13/2022 #1

该行将 .1 转换为 中最接近的值,结果为 0.100000001490116119384765625float BoundsHeight = 0.1f;floatBoundsHeight

该行同样转换为 ,设置为 2,333,638.6551984739489853382110595703125。double BoundsY = 2,333,638.6551984739;doubleBoundsY

该行将其转换为 ,设置为 2,333,638.75。float MinY = BoundsY;floatMinY

该行使用(我假设;我不熟悉 C# 语义),设置为 2,333,638.7551984754391014575958251953125。double MaxY_Defect = BoundsY + BoundsHeight;doubleMaxY_Defect

该行将其转换为 ,设置为 2,333,638.75。float MaxY = (float)(MaxY_Defect);floatMaxY

然后我们可以看到它并具有相同的值,所以当然是零。MinYMaxYMaxY-MinY

很简单,没有足够的精度来区分 2,333,638.6551984739489853382110595703125 和 2,333,638.7551984754391014575958251953125。在比例为 2,333,638 时,格式中相邻可表示数字之间的距离为 .25。这是因为该格式有 24 位的有效值(浮点表示的分数部分)。2,333,638 介于 221 和 222 之间,因此其浮点表示中的指数将有效数缩放为具有表示从 2 21 到 2−2 的值的位(从 21 到 −2,包括24 个位置)。因此,将有效数在其最低位上改变 1 会将表示的数字改变 2−2 = .25。floatfloat

因此,当 2,333,638.655...和 2,333,638.755...转换为 ,它们具有相同的结果 2,333,638.75。float

您不能用于区分在该量级下如此接近的坐标或大小。您可以使用或许可将坐标平移为更接近原点(因此它们的大小更小,将它们放在分辨率更精细的区域)。floatdoublefloat

只要最终结果很小,就可以使用 进行中间计算,但仍然使用 很好地表示最终结果。doublefloat

有关浮点运算的更多信息,我推荐 Muller、Brunie、de Dinechin、Jeannerod、Joldes、Lefèvre、Melquiond、Revol 和 Torres 的《浮点算术手册》。此处似乎提供了先前版本的 PDF。官方的 IEEE 754-2019 浮点运算标准可在此处获得。