我在IEEE754乘法中失去了 2 的幂

I'm losing 2's powers in IEEE754 multiplication

本文关键字:的幂 失去 IEEE754 我在      更新时间:2023-10-16

我正在研究IEE754,我对这些代码行感到困惑

double a = 0.2;
double b = 100.0;
double c = a * b;

我知道0.2不能通过2的能力完美地表示,而100可以,但是我得到20的完美结果,结果c。

可视化组成这些值的2的功率(我正在使用一个简单的JS可视化器:http://bartaz.github.io/ieee754-visalization/),我看到0.2始于

2^-3 + 2^-4 + 2^-7...

和100

2^6 + 2^5 + 2^2

现在是我的问题:这是20,又称c

2^4 + 2^2
^^^

什么?2^4来自哪里?如果我将数学上的所有条款乘以100的所有条款,我将获得2^3的最大功能。

因此,假设可视化器是正确的:

  • 2^4来自哪里?
  • 如果从一开始不精确的情况下,将0.2乘以0.2乘以100的精度损失呢?为什么c确切的结果?

IEEE算术规则中没有任何东西可以防止往返最终的击中您想做的十进制计算的确切结果。

双文字100.0的确切值当然是100。

双文字0.2的确切值是0.200000000000000011102233024625156540423636316680908203125

他们的产品是20.000000000011102233024625156540423631668090820312500

四舍五入到20的舍入错误是1.1102233024625156540423631668090820312500E-15

由于四舍五入的误差大于将四舍五入到20的误差,因此双重乘法的正确循环结果为20.0。舍入错误是2^-50 + 2^-52,您的"丢失"功率为2。

我使用Java程序进行计算,因为方便的BigDecimal类可以准确地表示所有有限的双重数字,并且在它们上的某些算术结果(包括乘法)。Java双重算术遵循IEEE 754 64位二进制浮点数以圆头到最新的模式,这也是C双打的通常系统。

import java.math.BigDecimal;
public class Test {
  public static void main(String[] args) {
    double a = 0.2;
    double b = 100.0;
    double c = a * b;
    display(a);
    display(b);
    display(c);
    BigDecimal exactProduct = new BigDecimal(a).multiply(new BigDecimal(b));
    System.out.println(exactProduct);
    BigDecimal down = new BigDecimal(20.0);
    System.out.println(down);
    BigDecimal up = new BigDecimal(Math.nextUp(20.0));
    System.out.println(up);
    System.out.println("Round down error "+exactProduct.subtract(down));
    System.out.println("Round up error "+up.subtract(exactProduct));
  }
  private static void display(double in){
    System.out.println(new BigDecimal(in));
  }
}

输出:

0.200000000000000011102230246251565404236316680908203125
100
20
20.000000000000001110223024625156540423631668090820312500
20
20.000000000000003552713678800500929355621337890625
Round down error 1.110223024625156540423631668090820312500E-15
Round up error 2.442490654175344388931989669799804687500E-15