首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C语言 >

,关于c语言计算误差的有关问题

2013-07-11 
求助各位高手,关于c语言计算误差的问题我只是在测试误差,代码如下:#include stdio.hvoid main(){int n

求助各位高手,关于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 看看结果
[解决办法]

引用:
0.00048828125 膜拜啊。 这都知道!!!


Quote: 引用:

你可以试试:
sum = sum + 0.00048828125 看看结果


很简单啊,1/2^n这样的小数是没有误差的(精度位数范围内)
[解决办法]
引用:
Quote: 引用:

你可以试试:
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 */
...

热点排行