尝试使用以下代码在C中划分两个浮点数:
#include <stdio.h>
#include <math.h>
int main(){
float fpfd = 122.88e6;
float flo = 10e10;
float int_part, frac_part;
int_part = (int)(flo/fpfd);
frac_part = (flo/fpfd) - int_part;
printf("\nInt_Part = %f\n", int_part);
printf("Frac_Part = %f\n", frac_part);
return(0);
}
对于此代码,我使用命令:
>> gcc test_prog.c -o test_prog -lm
>> ./test_prog
然后我得到了这个输出:
Int_Part = 813.000000
Frac_Part = 0.802063
现在,这个Frac_part似乎不正确。我先在计算器上尝试了相同的等式,然后在Wolfram Alpha中尝试了相同的等式,他们都给了我:
Frac_Part = 0.802083
请注意,小数点后五位的数字不同。
这对大多数人来说似乎微不足道,但对于我所做的计算来说,这是至关重要的。
任何人都可以向我解释为什么C代码会出现此错误吗?
答案 0 :(得分:5)
当浮点运算的精度不足时,第一个最自然的步骤就是使用更高精度的浮点类型,例如:使用double
代替float
。 (正如其他答案中所指出的那样。)
其次,检查不同的浮点运算并考虑它们的精度。作为错误来源的突出的一个方法是上面的方法,通过简单地转换为int和减去将float分成整数部分和小数部分。这并不理想,因为当你从原始值中减去整数部分时,你正在进行算术,其中涉及的三个数字(两个输入和结果)具有非常不同的比例,这可能会导致精度损失。
我建议使用C <math.h>
函数modf
来将浮点数分成整数和小数部分。 http://www.techonthenet.com/c_language/standard_library_functions/math_h/modf.php
(更详细:当你执行像f - (int)f
这样的操作时,浮点加法过程将会看到添加了两个给定精度X的数字,并且它会自然地假设结果也将具有精度X.然后它将在该假设下执行实际计算,并最终在结束时重新评估结果的精度。因为初始预测结果不理想,所以一些低阶位将丢失。 )
答案 1 :(得分:3)
Float是浮点数的单精度,你应该尝试使用double,下面的代码给出了正确的结果:
#include <stdio.h>
#include <math.h>
int main(){
double fpfd = 122.88e6;
double flo = 10e10;
double int_part, frac_part;
int_part = (int)(flo/fpfd);
frac_part = (flo/fpfd) - int_part;
printf("\nInt_Part = %f\n", int_part);
printf("Frac_Part = %f\n", frac_part);
return(0);
}
正如我所说,float是单精度浮点数,它们小于double(在大多数架构中,sizeof(float) < sizeof(double)
)。
使用double
代替float
,您将有更多位来存储尾数和数字的指数部分(请参阅wikipedia)。
答案 2 :(得分:2)
float
只有6~9位有效数字,对于大多数实际使用来说,它不够精确。将所有float
变量更改为double
(提供15~17位有效数字)可得出输出:
Int_Part = 813.000000
Frac_Part = 0.802083