c++ - 浮点整数的精确表示
问题描述
我试图了解浮点格式的整数表示。
由于 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;
}
解决方案
确实,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 的幂次方加倍。
你会得到类似的结果,但差距更小,使用 typedouble
或long double
.
推荐阅读
- laravel - Ordering laravel form::select by already selected values
- openshift - OpenShift 4.x and HELM
- go - 两个节点可以直接交换消息吗?
- c# - Create an extension method derived from ToDictionary()
- javascript - Bind Vue to associative array
- javascript - Highligligh particular areas based on X-axis data
- node.js - How to run cron in serverless for every minute?
- c# - 当用户使用 ASP.NET Core Identity 登录网站时,他在访问该网站的所有浏览器中都已登录
- laravel - Laravel 验证仅接受来自 api 的预定义值
- wpf - 如何避免网格控件中的焦点单元格颜色