我有一个用c语言解决数学问题的函数。
double task1_double() {
double a = 1000;
double b = 0.0001;
double result = (pow((a + b), 2) - (pow(a, 2) + 2 * a * b))/(pow(b, 2));
return result; }
float task1_float() {
float a = 1000;
float b = 0.0001f;
float result = (powf((a + b), 2) - (powf(a, 2) + 2 * a * b))/(powf(b, 2));
return result; }
当我使用double数据类型时,它返回1.001172,而使用float数据类型时,结果是6250000.000000。
谁能解释一下为什么会这样?提前感谢你的分子正好是
1000000.20000001 - 1000000.2 = 0.00000001
但是当你相减两个几乎相等的大数时,结果中的相对舍入误差可能会放大。这就是你所看到的。这是由于float
的数字大约有7位十进制的精度,而double
的数字大约有16位十进制的精度。
让我们一步一步来做:
exact float double
x = pow((a + b), 2) 1000000.20000001 1000000.25 1000000.200000009965
y = pow(a, 2) + 2 * a * b 1000000.2 1000000.1875 1000000.199999999953
x - y 0.00000001 0.0625 0.000000010011717677
对于两个数字相对于它们的大小而言如此小的差异,您通常会得到等于0.0的float
结果。但在这种情况下,1000000.20000001和1000000.2恰好位于舍入边界的两侧,导致前者四舍五入,后者四舍五入。所以他们的差异是6个数量级。
通过输出中间结果可以发现,这是由于float
的精度损失造成的。
#include <stdio.h>
#include <math.h>
double task1_double() {
double a = 1000;
double b = 0.0001;
double s1, s2, s3;
s1 = pow((a + b), 2);
s2 = pow(a, 2) + 2 * a * b;
s3 = pow(b, 2);
double result = (pow((a + b), 2) - (pow(a, 2) + 2 * a * b)) / (pow(b, 2));
printf("_double : %lf - %lf = %.15lfn", s1, s2, s1 - s2);
printf("_double : (%lf - %lf) / %.10lf = %lfn", s1, s2, s3, result);
return result;
}
float task1_float() {
float a = 1000;
float b = 0.0001f;
float s1, s2, s3;
s1 = powf((a + b), 2);
s2 = powf(a, 2) + 2 * a * b;
s3 = powf(b, 2);
float result = (powf((a + b), 2) - (powf(a, 2) + 2 * a * b)) / (powf(b, 2));
printf("_float : %lf - %lf = %.15lfn", s1, s2, s1 - s2);
printf("_float : (%lf - %lf) / %.10lf = %lfn", s1, s2, s3, result);
return result;
}
int main()
{
printf("%.10lfn%.10lfn", task1_double(), task1_float());
return 0;
}
输出:
_float : 1000000.250000 - 1000000.187500 = 0.062500000000000
_float : (1000000.250000 - 1000000.187500) / 0.0000000100 = 6250000.500000
_double : 1000000.200000 - 1000000.200000 = 0.000000010011718
_double : (1000000.200000 - 1000000.200000) / 0.0000000100 = 1.001172
1.0011717677
6250000.5000000000
可以看出:浮点数操作后,会出现一个小误差,但除以b的小值会使误差放大很多倍