C++ 整数在浮点中的精确表示

C++ 整数在浮点中的精确表示,c++,floating-point,precision,C++,Floating Point,Precision,我试图理解浮点格式的整数表示 由于IEEE浮点格式的尾数只有23位,因此我希望任何大于1的整数都是正确的,IEEE浮点格式的尾数位数是有限的。如果有23个尾数位,那么它可以精确地表示223个不同的整数值 但由于浮点分别存储两个指数的幂,因此它可以(受限于有限的指数范围)精确地表示这223个值乘以二的幂的任意一个值 33554432正好是225,所以它只需要一个尾数位就可以准确地表示它(加上一个表示乘以二的幂的二进制指数)。它的二进制表示形式是100000000000000000,它有26位,但只

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


由于IEEE浮点格式的尾数只有23位,因此我希望任何大于1的整数都是正确的,IEEE浮点格式的尾数位数是有限的。如果有23个尾数位,那么它可以精确地表示223个不同的整数值

但由于浮点分别存储两个指数的幂,因此它可以(受限于有限的指数范围)精确地表示这223个值乘以二的幂的任意一个值

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

您会发现其相邻的整数值
33554431
33554433
不能在32位
浮点中精确表示。(但它们可以用64位
双精度
表示)

更一般地说,
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);
}
它以类型
float
显示数字1、223、224和230的直接前导和后继。正如你所看到的,当数值越大,间隙越大,每2次方的间隙越大


您会得到类似的结果,但是使用较小的间隙,使用类型
double
longdouble

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

但由于浮点分别存储两个指数的幂,因此它可以(受限于有限的指数范围)精确地表示这223个值乘以二的幂的任意一个值

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

您会发现其相邻的整数值
33554431
33554433
不能在32位
浮点中精确表示。(但它们可以用64位
双精度
表示)

更一般地说,
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);
}
它以类型
float
显示数字1、223、224和230的直接前导和后继。正如你所看到的,当数值越大,间隙越大,每2次方的间隙越大


您将得到类似的结果,但间隙较小,键入
double
longdouble

当我运行代码时,第一行打印
3.35544e+07
。是否使用I/O操纵器更改输出格式?可能是因为!=运算符在比较之前将整数转换为浮点。这失去了足够的精度,使它们相等。对不起,愚蠢的错误。修正:)我添加了
coutw当我运行你的代码时,第一行打印
3.35544e+07
。是否使用I/O操纵器更改输出格式?可能是因为!=运算符在比较之前将整数转换为浮点。这失去了足够的精度,使它们相等。对不起,愚蠢的错误。修正:)我添加了
coutb根据你的解释,我添加了另一个我不知道的片段understand@David与其为了一个回答好的问题而移动门柱,不如问另一个问题。一个问题涉及的内容越多,它就越不一般,对未来的提问者也就越不有用。IEEE-754基本32位二进制浮点有24位有效位。23在有效位字段中编码,一个通过指数字段编码。从数学上讲,它们有24位有效位,这就是为什么从0到2^24的所有整数都可以精确表示的原因。太好了。谢谢你,基思。说得很好,解释得很好基于你的解释,我添加了另一个我不知道的片段understand@David与其为了一个回答好的问题而移动门柱,不如问另一个问题。一个问题涉及的内容越多,它就越不一般,对未来的提问者也就越不有用。IEEE-754基本32位二进制浮点有24位有效位。23在有效位字段中编码,一个通过指数字段编码。从数学上讲,它们有24位有效位,这就是为什么从0到2^24的所有整数都可以精确表示的原因。太好了。谢谢你,基思。说得很好,解释得很好
#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);
}