我知道511除以512实际上等于0.998046875。我也知道浮子的精度是7位数。我的问题是,当我用C ++(GCC)进行数学运算时,得到的结果是0.998047,这是一个舍入值。我更愿意得到截断值0.998046,我该怎么做?
float a = 511.0f;
float b = 512.0f;
float c = a / b;
答案 0 :(得分:22)
嗯,这是一个问题。 511/512
的值为float
,是准确的。没有舍入。您可以通过要求超过七位数来检查:
#include <stdio.h>
int main(int argc, char *argv[])
{
float x = 511.0f, y = 512.0f;
printf("%.15f\n", x/y);
return 0;
}
输出:
0.998046875000000
float
不是十进制数,而是二进制数。如果将数字除以2的幂,例如512,则结果几乎总是精确的。发生的事情是float
的精度不仅仅是7位数,它实际上是精确的23 位。
请参阅What Every Computer Scientist Should Know About Floating-Point Arithmetic。
答案 1 :(得分:5)
我也知道浮点数的精度是7位数。
没有。最常见的浮点格式是二进制格式,精度为24位。它介于6到7位十进制数字之间,但如果您想了解舍入工作的方式,则无法用小数表示。
由于b是2的幂,c是完全可表示的。在十进制表示转换期间,将发生舍入。获取十进制表示的标准方法不提供使用截断而不是舍入的可能性。一种方法是要求多一个数字并忽略它。
但请注意,c完全可表示的事实是其值的属性。 SOme显然更简单(如0.1)没有二进制FP格式的精确表示。
答案 2 :(得分:1)
这个'四舍五入'的值最通过某种输出方法而不是实际存储的方式显示出来。检查调试器中的实际值。
使用iostream和stdio,您可以指定输出的精度。如果指定7位有效数字,将其转换为字符串,然后在显示之前截断字符串,您将获得输出而不进行舍入。
不能想到你想要这样做的一个原因,并且考虑到应用程序的后续解释,你最好使用双精度,尽管这很可能只是将问题转移到其他地方。
答案 3 :(得分:1)
你的问题并不是独一无二的,之前已经多次回答。这不是一个简单的主题,只是因为发布答案并不一定意味着他们的质量会很好。如果你浏览一下,你会发现真正好的东西。这将花费你更少的时间。
我打赌有人会对我进行评论而不回答。
_____编辑_____
理解浮点的基础是要意识到一切都以二进制数字显示。因为大多数人都难以理解这一点,所以他们试图从十进制数字的角度来看待它。
关于511/512的主题,您可以从值1.0开始。在浮点数,这可以表示为i.000000 ... * 2 ^ 0或隐含位设置(到1)乘以2 ^ 0即等于1.由于511/512小于1,您需要从下一个开始低功率-1给出i.000000 ... * 2 ^ -1即0.5。请注意,唯一改变的是指数。如果我们想用二进制表示511,我们得到9个--111111111或浮点与隐式位i.11111111 - 我们可以除以512并将指数放在-1给i.1111111100 ... * 2 ^ -1
这如何转化为0.998046875?
好吧,隐含位开始表示0.5(或2 ^ -1),第一个显式位0.25(2 ^ -2),下一个显式位0.125(2 ^ -3),0.0625,0.03125等等直到你代表第九位(第八位显式)。总结一下,得到0.998046875。从i.11111111我们发现这个数字代表精度的9位二进制数字,巧合的是9位小数。
如果您将511/512乘以512,您将获得i1111111100 ...... * 2 ^ 8。这里有九个精确的二进制数字,但只有三个十进制数字(511)。
考虑i.11111111111111111111111(i + 23个)* 2 ^ -1。我们将获得具有24个二进制和24个十进制数字精度的分数(2 ^(24-1)^ /(2 ^ 24))。给定适当的printf格式,将显示所有24位十进制数字。将它乘以2 ^ 24,你仍然有24位精度的二进制数字,但只有8位小数(对于16777215)。
现在考虑i.1111100 ...... * 2 ^ 2,它出现在7.875。 i11是整数部分,111是分数部分(111/1000或7/8)。 6位二进制数字的精度和4位小数。
在做浮点时思考小数对理解它是完全不利的。自由自在!
答案 4 :(得分:0)
如果您只对该值感兴趣,可以使用double然后将结果乘以10 ^ 6并将其置于最低位置。再次除以10 ^ 6,你将得到截断值。