首页 > 解决方案 > 浮点整数的精确表示

问题描述

我试图了解浮点格式的整数表示。

由于 IEEE 浮点格式只有 23 位尾数,我希望任何大于 1<<22 的整数都只是一个近似表示。这不是我在 g++ 中观察到的

下面的两个 cout 都打印相同的值 33554432。

由于尾数部分是负责精度的部分,我们如何能够表示(存储)需要超过 23 位才能准确存储的确切数字。

void floating_point_precision(){
  cout<< setprecision(10);
  float fp = (1<<25);
  cout<< fp <<endl;
  cout<< (1<<25) <<endl;
}

作为基于以下答案的后续行动,为什么即使 fp,i 的打印不同,以下代码也不执行“不等于”。

void floating_point_precision(){
  cout<< setprecision(10);
  float fp = ((1<<25)+1);
  cout<< fp <<endl;
  int i = ((1<<25)+1)  ;
  cout<< i <<endl;
  if(i != fp)
    cout<< "Not equal" <<endl;
}

标签: c++floating-pointprecision

解决方案


确实,IEEE 浮点只有有限数量的尾数位。如果有 23 个尾数位,那么它可以精确地表示 2 23个不同的整数值。

但由于浮点数单独存储一个二次幂指数,它可以(受有限的指数范围限制)精确地表示这 2 23个值中的任何一个乘以二次幂

33554432正好是 2 25,所以它只需要一个尾数位就可以准确地表示它(加上一个表示乘以 2 的幂的二进制指数)。它的二进制表示是10000000000000000000000000,它有 26 位但只有 1 个有效位。(嗯,实际上它们都很重要,但你明白了。)

你会发现它的相邻整数值33554431不能33554433 32-bit 精确表示float。(但它们可以用 64 位表示double。)

更一般地,类型的连续可表示值之间的float差异随着值的大小而变化。在我的系统上(大多数系统使用 IEEE 格式,但标准不要求),这个程序:

#include <iostream>
#include <iomanip>
#include <cmath>

void show(float f) {
    std::cout << std::nextafterf(f, 0.0) << "\n"
              << f << "\n"
              << std::nextafterf(f, f*2) << "\n";
    putchar('\n');
}

int main(void) {
    std::cout << std::setprecision(24);

    show(1);
    show(1<<23);
    show(1<<24);
    show(1<<30);
}

产生这个输出:

0.999999940395355224609375
1
1.00000011920928955078125

8388607.5
8388608
8388609

16777215
16777216
16777218

1073741760
1073741824
1073741952

float它显示了数字 1、2 23、2 24和 2 30类型中的直接前任和后继。如您所见,对于较大的数字,差距会变得更大,差距会在每 2 的幂次方加倍。

你会得到类似的结果,但差距更小,使用 typedoublelong double.


推荐阅读