楼层的奇怪行为()

McN*_*ber 2 c++ math double

我开发了一个c ++应用程序(Windows 7,64 Bit,VS 2008),其中使用了以下公式(所有变量都是double类型):

mValue = floor(mValue/mStepping)*mStepping;
Run Code Online (Sandbox Code Playgroud)

我们的想法是将数字缩短到给定的小数位数.我认为有更好的方法可以做到这一点,但这不是问题(但如果你有更好的选择,请带上它!).

mValue来自用户输入,因此在大多数情况下,小数位数已经可以.但在某些情况下,输出与输入不同.

例如,mStepping的值为0.1(应该舍入到一个小数位).现在,如果mValue的值为14.6,那么一切正常.如果mValue为14.7,则结果为14.6.

那么,为什么地板(14.7/0.1)*0.1 = 14.6?

我测试了其他值,其中约20%与0.1不同.我进一步挖掘并发现,14.7/0.1具有与147.0不同的二进制编码:

14.7/0.1 = ff ff ff ff ff 5f 62 40
147.0    = 00 00 00 00 00 60 62 40
Run Code Online (Sandbox Code Playgroud)

据我所知,相同的数字可以不同的方式编码为double.但是为什么floor()以不同的方式处理它们?我能做些什么呢?

Joe*_*oey 6

通常的问题:并非所有精确的小数部分都可以用二进制表示.在你的情况下,它0.114.7为好.除以0.1,你实际上没有达到147,而是低于它的微小数量:

14.699999999999999289457264239899814128875732421875

乘以0.1:

0.1000000000000000055511151231257827021181583404541

你到达:

146.999999999999971578290569595992565155029296875

我想你现在开始看到这个问题吧?这个数字的地板显然会给你146.

你能做些什么呢?如果需要精确的十进制结果,请使用表示小数部分的数字类型或bignum库.

哦,还有一个侧面说明:没有,同样的数字并不能有不同的double表述.只是你解释一个数字是什么以及它的行为方式与浮点数学有所不同.