C# 为什么(int)(33.46639*1000000)返回33466389?

C# 为什么(int)(33.46639*1000000)返回33466389?,c#,floating-point,floating-accuracy,multiplication,C#,Floating Point,Floating Accuracy,Multiplication,(int)(33.46639*1000000)返回33466389 为什么会发生这种情况?双精度不精确,因此内部33.46639实际上存储为33.466389 编辑:正如Richard所说,它是浮点数据(以二进制形式存储在一组有限的位中),所以它并不完全是…浮点数学并不完美。关于它 浮点运算被许多人认为是一门深奥的学科。这相当令人惊讶,因为浮点运算在计算机系统中无处不在。几乎每种语言都有浮点数据类型;从个人电脑到超级计算机都有浮点加速器;大多数编译器会不时被要求编译浮点算法;实际上,每个操作系统

(int)(33.46639*1000000)
返回
33466389


为什么会发生这种情况?

双精度不精确,因此内部33.46639实际上存储为33.466389


编辑:正如Richard所说,它是浮点数据(以二进制形式存储在一组有限的位中),所以它并不完全是…

浮点数学并不完美。关于它

浮点运算被许多人认为是一门深奥的学科。这相当令人惊讶,因为浮点运算在计算机系统中无处不在。几乎每种语言都有浮点数据类型;从个人电脑到超级计算机都有浮点加速器;大多数编译器会不时被要求编译浮点算法;实际上,每个操作系统都必须响应浮点异常,例如溢出。本文介绍了一个有关浮点运算的教程,这些方面对计算机系统的设计者有着直接的影响。它从浮点表示和舍入误差的背景开始,继续讨论IEEE浮点标准,并以计算机构建者如何更好地支持浮点的众多示例结束

将无限多个实数压缩成有限位数需要近似表示。尽管有无限多个整数,但在大多数程序中,整数计算的结果可以存储在32位中。相反,给定任何固定的位数,大多数实数计算将产生无法用那么多位数精确表示的量。因此,浮点计算的结果必须经常四舍五入,以适应其有限表示形式。这种舍入误差是浮点计算的特征


您得到不同结果的原因是您使用了“cast”

(int)(33.46639*1000000)返回33466389 ^^^^^
要将结果强制转换为“int”类型。。。将整数类型向上或向下四舍五入,然后将其相乘并转换为“int”。。。。不要依赖浮点数来获得足够的精度……Skeet在他的网站上发布了一篇精彩的介绍,如果你问为什么它没有变成
33466390
,那是因为
double
没有无限精度,而且数字不能用二进制精确表示


如果将
双精度
替换为
十进制
(int)(33.46639m*1000000)
),则它等于
33466390
,因为
十进制
是以10为基数计算的。

原因是33.46639将表示为略小于该数字的值

乘以1000000将得到33466389.9999999

然后,使用(int)输入casting将只返回整数部分(33466389)


如果您想要“正确”的数字,请在类型转换之前尝试round()。

因为33.46639不能用有限的二进制数字精确表示。33.46639*1000000的实际结果为33466389.99999962747097015380859375。演员阵容将其删减至33466389人。

1994年底是除夕夜。英特尔首席执行官安迪·格罗夫(Andy Grove)今年表现出色,奔腾处理器问世并大受欢迎。于是,他走进一家酒吧,点了一杯双份的Johnnie Walker Green Label

酒保端上来说:“一共20美元,先生。”

格罗夫把一张二十美元的钞票放在柜台上,看了一会儿,说:“不用找了。”


你预计会发生什么?@Slaks:3346639,又名,正确答案。@Gonzo牧师:你不是说“33466390”吗?如果你告诉我们你用的是什么语言,那会有帮助的。您可能正在使用一种将33.46639视为浮点类型而不是十进制类型的语言。@Peter,有人删除了c#标记,不知道为什么。或33.4668885或其他“足够接近”的语言,取决于硬件。嗯,以上都没有。在二垒。大多数这样的数字不能精确地以10为基数表示。(无论如何,不要使用无限重复的数字序列。类似于1/3必须以10为基数表示为0.33333[inf])@Richard:错。任何以2为基数的数字都可以精确地表示为以10为基数的非重复小数。(因为十是二的倍数)FWIW,它正好是
33.466389999999697365637985058128833770751953125
@Richard Berg:大多数实数不能用浮点表示。所有可以用小数点(二进制?)右侧的N位精确表示的数字都可以用小数点右侧的N位精确表示。转换本身没有任何损失。存在任意精度的库。我可以想象他会问“我的结果中的8是从哪里来的?”乘以1000000就像将小数点后6位移到右边,应该是“33466390”,但这不是他的答案。你的答案和我最初想的一样,直到我再次阅读这个问题。@Richard-将
float
double
值强制为
int
会丢弃小数部分,因此你会丢失信息。赛斯,这是正确的。我要说的是,截断是float/double的一个特殊特性(通过CLI规范)。正如Tommie所暗示的,这并不是C#cast运算符的固有特性。浮点运算确实无处不在且复杂,但这并不能回答问题(除非你计算链接到某个地方有答案的80页论文的链接)。@Henry-这一点在链接文章的标题中。每个程序员都应该知道这一点,如果他们不知道,他们应该阅读这篇文章。(好的,也许不是所有的80页…+1:链接到一篇80页的论文,在某个地方有答案是一个标准的anwser。这个问题以这样或那样的形式被问到 (int)(33.46639 * 1000000) returns 33466389 ^^^^^