浮点数计算精度问题

浮点数计算精度问题_第1张图片 浮点数计算精度问题_第2张图片

对于上面这两张图很多人是不是会有疑问,为什么计算出来的结果与实际不符。

这就牵扯到了计算机语言中浮点数计算的精度问题。

数序引申计算机

数学是一门抽数学引申计算机象的语言,而计算机的功能就是将问题进行具体化实现。所以建立浮点数标准(IEE-754),其目的就是计算机的存储中的数据到数学中一对一映射。但实际上无论任何浮点数的标准,总会存在用有限集合去映射无线集合的问题,这也就导致了存在精度误差问题。

计算机误差的产生

举个例子就比如0.1,0.2对于数学(十进制)而言是一个有限小数,但如果用二进制去表示他就会出现无线序列,所以在计算机进行运算是就会存在误差。

这里说明一下计算误差并不是单单因为计算的数据不能精确表示,最本质的语言还是因为有效位数的限制

这里我们假设有效位数是三位计算15+3.14+2.77,精确计算得到20.91,四舍五入最后的20.9

浮点数计算精度问题_第3张图片浮点数计算精度问题_第4张图片

计算机计算最后得到20.8,这里就存在精度误差是由有效位数引起的。

有效位的位数取决于具体使用的浮点数标准,单精度浮点数(float)中,我们有 23 位有效位,8位浮点位,而在双精度浮点数(double)中,则有 52 位有效位,11 位浮点位。

计算误差的累计 

根据上面的例子有些人就会想误差就那么一点,不会太影响整体结果。那么接下我们再来看一个例子:计算15+0.1+0.1……+0.1中间包含100个0.1。(假设有效位数是两位)

精确计算得到115

计算机计算:

浮点数计算精度问题_第5张图片浮点数计算精度问题_第6张图片

………… 最后得到15,两者足足相差100,可见有些时候误差的巨大。

浮点数计算精度问题_第7张图片

 减少精度误差

使用定点误差:使用整数存储有效数字,在使用另一个整数存储字数,最后以这种思路实现各种基础运算。

kahan求和算

最后在给大家介绍一种补偿算法

function KahanSum(input: number[]) {
    double sum = 0.0;
    double c = 0.0;  // 存储被舍弃的精度数据

    for (let i = 1; i < input.length; i++)

    {
        double y = input[i] - c;  // 将 c 加到新的数值中
        double t = sum + y;       // 舍弃了精度的结果(注意这里必须sum比y大
        c = (t - sum) - y;     // (t - sum) 的到 y 没有被舍弃的高位部分,再 - y 就得到被舍弃的精                                               度 c
        sum = t;
    }
    return sum
}

我们通过计算15 + 3.14159 + 2.71828的例子来过一遍(假设保留3位有效数)

精确计算得到20.85987,四舍五入20.9

第一次循环

y=3.14159-0.0=3.14159
t=15+3.14159=18.14159=18.1
c=(18.1-15)-3.14159=-0.04159
sum=18.1

第二次循环

y= 2.71828-(-0.04159)=2.75987

t=18.1+2.75987=20.85987=20.9

c=(20.9-18.1)-2.75987=0.04013

sum=20.9//得到精确结果

但是Kahan 求和算法并不适用所有场景,我们要学习的是这种补偿误差的思想。

浮点数计算精度问题_第8张图片

你可能感兴趣的:(C语言进阶,机器学习,人工智能)