求助各位高手,关于c语言计算误差的问题
我只是在测试误差,代码如下:
#include <stdio.h>
void main()
{
int n = 100000000;
double sum = 0;
for( int i=0 ; i<n ; i++ )
sum = sum+0.0005;
printf("%lf\n",sum);
}
结果是50000.000013,为啥会有这么大的误差啊? C 误差
[解决办法]
你可以试试:
sum = sum + 0.00048828125 看看结果
[解决办法]
很简单啊,1/2^n这样的小数是没有误差的(精度位数范围内)
[解决办法]
你可以试试:
sum = sum + 0.00048828125 看看结果
竟然没有误差。。。是不是0.0005在计算机内部用二进制存储的时候是无限小数,就省略了后面啊。。。
有没有什么方法可以避免这种误差啊?我不是很怕麻烦,有建议请告诉我
是的,转换为2进制后,是无限小数,超出位数部分,被抛弃,1/2^n这样的小数,只要在位数范围内,就不会有误差
[解决办法]
转载的你看看
答:类似的问题经常见到有人问.我就来彻底回答:5.4+0.9怎么变成了6.300000000000001了?
5.4 (64位)
数学上表示:101.011 00110011 00110011 00110011 00110011 00110011 00110011 ............无限循环
计算机中IEEE表示:(2^2 * 1.X 形式)
0 10000000001 01 011 00110011 00110011 00110011 00110011 00110011 0011010(第一次不精确了,尾数1进入)
0.9 (64位)
数学上表示:0.111 00110011 00110011 00110011 00110011 00110011 00110011 00110011............无限循环
计算机中IEEE表示:(2^(-1) * 1.X 形式)
0 01111111110 11 001 10011001 10011001 10011001 10011001 10011001 10011010 (第二次不精确了,尾数1进入)
两者在计算中内部相加:
(1)0 10000000001 0101100110011001100110011001100110011001100110011010(5.4在计算机中IEEE表示)
(2)0 10000000001 0011100110011001100110011001100110011001100110011010
(这是幂对齐之后的0.9表示.由于0.9的指数是-1(即2^(-1)),为了相加,幂向2^2对齐.尾数第三次不精确了,尾数1进入)
相加的结果是:(IEEE754表示)
0 10000000001 1001001100110011001100110011001100110011001100110100
这个IEEE754表示什么数值?正是:6.300000000000001
[解决办法]
为什么 0.00048828125 没有 误差 呢? 看不懂
0.0004882815的二进制方式为0.00000000001即为1.0*2^(-11)
根据iee754的标准1位符号位,11位指数位,52位小数位。那么有如下
指数为x-1023=n,n=-11,那么x=1012,二进制为01111110100
那么合起来就是 0 01111110100 ....(52个0)即为3f40 0000 0000 0000
小数位为0所以当他们相加需要指数对齐时(右移小数)。不会丢失数据。
而其他数据相加时。右移对齐会丢失数据。所以不准确
另外你可以去测试下。
#include <stdio.h>
int main(void)
{
double a = 0.00048828125;
printf("%.13f\n",a);
printf("%x\n",*((unsigned int*)&a));
printf("%x\n",*((unsigned int*)&a+1));
return 0;
}
[解决办法]
用10进制小数不能精确表示某些三进制小数0.1(3)=0.33333333333……(10)
同理,用二进制小数也不能精确表示某些10进制小数。
float.h
...
#define DBL_DIG 15 /* # of decimal digits of precision */
#define DBL_EPSILON 2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON != 1.0 */
#define DBL_MANT_DIG 53 /* # of bits in mantissa */
#define DBL_MAX 1.7976931348623158e+308 /* max value */
#define DBL_MAX_10_EXP 308 /* max decimal exponent */
#define DBL_MAX_EXP 1024 /* max binary exponent */
#define DBL_MIN 2.2250738585072014e-308 /* min positive value */
#define DBL_MIN_10_EXP (-307) /* min decimal exponent */
#define DBL_MIN_EXP (-1021) /* min binary exponent */
#define _DBL_RADIX 2 /* exponent radix */
#define _DBL_ROUNDS 1 /* addition rounding: near */
#define FLT_DIG 6 /* # of decimal digits of precision */
#define FLT_EPSILON 1.192092896e-07F /* smallest such that 1.0+FLT_EPSILON != 1.0 */
#define FLT_GUARD 0
#define FLT_MANT_DIG 24 /* # of bits in mantissa */
#define FLT_MAX 3.402823466e+38F /* max value */
#define FLT_MAX_10_EXP 38 /* max decimal exponent */
#define FLT_MAX_EXP 128 /* max binary exponent */
#define FLT_MIN 1.175494351e-38F /* min positive value */
#define FLT_MIN_10_EXP (-37) /* min decimal exponent */
#define FLT_MIN_EXP (-125) /* min binary exponent */
#define FLT_NORMALIZE 0
#define FLT_RADIX 2 /* exponent radix */
#define FLT_ROUNDS 1 /* addition rounding: near */
...