可以表示为浮点数的最大奇数
Largest odd integer that can be represented as a float
我想知道可以精确表示为浮点数的最大奇数是多少?以及为什么在这种情况下表示为浮点数的最大偶数之间存在差异。
我认为这与以 2 为底的指数 2^n-1 有关,但是我对 C 中的数据表示不够熟悉,看不出区别。
对于IEEE-754基本32位二进制浮点数,最大可表示的奇整数为224−1.
对于IEEE-754基本64位二进制浮点数,最大可表示的奇整数为253−1.
这是因为格式有 24 位和 53 位有效数字。 (有效数是浮点数的小数部分。)
有效位数中的位表示的值是按照浮点数的指数进行缩放的。为了表示奇数,浮点数必须在尾数中有一位表示20。对于 24 位有效数,如果最低位表示 20,则最高位表示 223。当所有位都为on时取最大值,使得值为20 + 21 + 22 + … 223,等于 224−1.
更一般地说,可表示的最大奇数通常是 scalbnf(1, FLT_MANT_DIG) - 1
。这也可以计算为 (2 - FLT_EPSILON) / FLT_EPSILON
。 (这里假设正常情况下 FLT_RADIX
是偶数,FLT_MANT_DIG <= FLT_MAX_EXP
。注意,如果 FLT_MANT_DIG == FLT_MAX_EXP
,应使用后一个表达式,FLT_EPSILON
,因为前者溢出.)
异常情况,仅供参考:
- 如果
FLT_RADIX
是奇数并且 FLT_MANT_DIG <= FLT_MAX_EXP
,如果 FLT_MANT_DIG
是奇数并且 FLT_MAX - scalbnf(FLT_EPSILON, FLT_MAX_EXP+1)
否则最大可表示的奇数是 FLT_MAX
。
- 如果
FLT_RADIX
是偶数且FLT_MANT_DIG > FLT_MAX_EXP
,那么:如果FLT_MAX_EXP > 0
,最大可表示的奇数是floorf(FLT_MAX)
。否则,没有奇数是可表示的。
- 如果
FLT_RADIX
是奇数且FLT_MANT_DIG > FLT_MAX_EXP
,则: 如果FLT_MAX_EXP > 0
,最大可表示的奇数整数是floorf(FLT_MAX)
如果FLT_MANT_DIG - FLT_MAX_EXP
是奇数或floorf(FLT_MAX)-1
否则。否则,没有奇数是可表示的。
可表示为 32 位浮点数的最大奇整数是 2^24 - 1。
更具体地说,一个 32 位浮点数可以精确表示以下整数:
- 2^24 以内的所有整数
- 2^25 以内的所有偶数
- 4 的所有倍数直到 2^26
- 8 的所有倍数直到 2^27
- 等等
换句话说,这里是可以精确表示的整数:
0
1
2
...
16777215
16777216 (= 2^24)
16777218
16777220
...
33554430
33554432 (= 2^25)
33554436
33554440
...
67108860
67108864 (= 2^26)
67108872
67108880
...
请注意,这对正整数和负整数都适用,例如,可以精确表示小至 -2^24 的所有负整数。
下面是一些 C++ 代码,对 2^24、2^25 和 2^26 左右的整数进行整数到浮点数的转换,以在实践中看到这一点。
#include <iostream>
#include <iomanip>
#include <vector>
int main()
{
int _2pow24 = 1 << 24;
int _2pow25 = 1 << 25;
int _2pow26 = 1 << 26;
std::cout << "2^24 = " << _2pow24 << std::endl;
std::cout << "2^25 = " << _2pow25 << std::endl;
std::cout << "2^26 = " << _2pow26 << std::endl;
std::vector<int> v;
for (int i = -4; i < 4; ++i) v.push_back(_2pow24 + i);
for (int i = -8; i < 8; ++i) v.push_back(_2pow25 + i);
for (int i = -16; i < 16; ++i) v.push_back(_2pow26 + i);
for (int i : v) {
std::cout << i << " -> "
<< std::fixed << std::setprecision(1)
<< static_cast<float>(i)
<< std::endl;
}
return 0;
}
输出:
2^24 = 16777216
2^25 = 33554432
2^26 = 67108864
16777212 -> 16777212.0
16777213 -> 16777213.0
16777214 -> 16777214.0
16777215 -> 16777215.0
16777216 -> 16777216.0
16777217 -> 16777216.0
16777218 -> 16777218.0
16777219 -> 16777220.0
33554424 -> 33554424.0
33554425 -> 33554424.0
33554426 -> 33554426.0
33554427 -> 33554428.0
33554428 -> 33554428.0
33554429 -> 33554428.0
33554430 -> 33554430.0
33554431 -> 33554432.0
33554432 -> 33554432.0
33554433 -> 33554432.0
33554434 -> 33554432.0
33554435 -> 33554436.0
33554436 -> 33554436.0
33554437 -> 33554436.0
33554438 -> 33554440.0
33554439 -> 33554440.0
67108848 -> 67108848.0
67108849 -> 67108848.0
67108850 -> 67108848.0
67108851 -> 67108852.0
67108852 -> 67108852.0
67108853 -> 67108852.0
67108854 -> 67108856.0
67108855 -> 67108856.0
67108856 -> 67108856.0
67108857 -> 67108856.0
67108858 -> 67108856.0
67108859 -> 67108860.0
67108860 -> 67108860.0
67108861 -> 67108860.0
67108862 -> 67108864.0
67108863 -> 67108864.0
67108864 -> 67108864.0
67108865 -> 67108864.0
67108866 -> 67108864.0
67108867 -> 67108864.0
67108868 -> 67108864.0
67108869 -> 67108872.0
67108870 -> 67108872.0
67108871 -> 67108872.0
67108872 -> 67108872.0
67108873 -> 67108872.0
67108874 -> 67108872.0
67108875 -> 67108872.0
67108876 -> 67108880.0
67108877 -> 67108880.0
67108878 -> 67108880.0
67108879 -> 67108880.0
我想知道可以精确表示为浮点数的最大奇数是多少?以及为什么在这种情况下表示为浮点数的最大偶数之间存在差异。
我认为这与以 2 为底的指数 2^n-1 有关,但是我对 C 中的数据表示不够熟悉,看不出区别。
对于IEEE-754基本32位二进制浮点数,最大可表示的奇整数为224−1.
对于IEEE-754基本64位二进制浮点数,最大可表示的奇整数为253−1.
这是因为格式有 24 位和 53 位有效数字。 (有效数是浮点数的小数部分。)
有效位数中的位表示的值是按照浮点数的指数进行缩放的。为了表示奇数,浮点数必须在尾数中有一位表示20。对于 24 位有效数,如果最低位表示 20,则最高位表示 223。当所有位都为on时取最大值,使得值为20 + 21 + 22 + … 223,等于 224−1.
更一般地说,可表示的最大奇数通常是 scalbnf(1, FLT_MANT_DIG) - 1
。这也可以计算为 (2 - FLT_EPSILON) / FLT_EPSILON
。 (这里假设正常情况下 FLT_RADIX
是偶数,FLT_MANT_DIG <= FLT_MAX_EXP
。注意,如果 FLT_MANT_DIG == FLT_MAX_EXP
,应使用后一个表达式,FLT_EPSILON
,因为前者溢出.)
异常情况,仅供参考:
- 如果
FLT_RADIX
是奇数并且FLT_MANT_DIG <= FLT_MAX_EXP
,如果FLT_MANT_DIG
是奇数并且FLT_MAX - scalbnf(FLT_EPSILON, FLT_MAX_EXP+1)
否则最大可表示的奇数是FLT_MAX
。 - 如果
FLT_RADIX
是偶数且FLT_MANT_DIG > FLT_MAX_EXP
,那么:如果FLT_MAX_EXP > 0
,最大可表示的奇数是floorf(FLT_MAX)
。否则,没有奇数是可表示的。 - 如果
FLT_RADIX
是奇数且FLT_MANT_DIG > FLT_MAX_EXP
,则: 如果FLT_MAX_EXP > 0
,最大可表示的奇数整数是floorf(FLT_MAX)
如果FLT_MANT_DIG - FLT_MAX_EXP
是奇数或floorf(FLT_MAX)-1
否则。否则,没有奇数是可表示的。
可表示为 32 位浮点数的最大奇整数是 2^24 - 1。
更具体地说,一个 32 位浮点数可以精确表示以下整数:
- 2^24 以内的所有整数
- 2^25 以内的所有偶数
- 4 的所有倍数直到 2^26
- 8 的所有倍数直到 2^27
- 等等
换句话说,这里是可以精确表示的整数:
0
1
2
...
16777215
16777216 (= 2^24)
16777218
16777220
...
33554430
33554432 (= 2^25)
33554436
33554440
...
67108860
67108864 (= 2^26)
67108872
67108880
...
请注意,这对正整数和负整数都适用,例如,可以精确表示小至 -2^24 的所有负整数。
下面是一些 C++ 代码,对 2^24、2^25 和 2^26 左右的整数进行整数到浮点数的转换,以在实践中看到这一点。
#include <iostream>
#include <iomanip>
#include <vector>
int main()
{
int _2pow24 = 1 << 24;
int _2pow25 = 1 << 25;
int _2pow26 = 1 << 26;
std::cout << "2^24 = " << _2pow24 << std::endl;
std::cout << "2^25 = " << _2pow25 << std::endl;
std::cout << "2^26 = " << _2pow26 << std::endl;
std::vector<int> v;
for (int i = -4; i < 4; ++i) v.push_back(_2pow24 + i);
for (int i = -8; i < 8; ++i) v.push_back(_2pow25 + i);
for (int i = -16; i < 16; ++i) v.push_back(_2pow26 + i);
for (int i : v) {
std::cout << i << " -> "
<< std::fixed << std::setprecision(1)
<< static_cast<float>(i)
<< std::endl;
}
return 0;
}
输出:
2^24 = 16777216
2^25 = 33554432
2^26 = 67108864
16777212 -> 16777212.0
16777213 -> 16777213.0
16777214 -> 16777214.0
16777215 -> 16777215.0
16777216 -> 16777216.0
16777217 -> 16777216.0
16777218 -> 16777218.0
16777219 -> 16777220.0
33554424 -> 33554424.0
33554425 -> 33554424.0
33554426 -> 33554426.0
33554427 -> 33554428.0
33554428 -> 33554428.0
33554429 -> 33554428.0
33554430 -> 33554430.0
33554431 -> 33554432.0
33554432 -> 33554432.0
33554433 -> 33554432.0
33554434 -> 33554432.0
33554435 -> 33554436.0
33554436 -> 33554436.0
33554437 -> 33554436.0
33554438 -> 33554440.0
33554439 -> 33554440.0
67108848 -> 67108848.0
67108849 -> 67108848.0
67108850 -> 67108848.0
67108851 -> 67108852.0
67108852 -> 67108852.0
67108853 -> 67108852.0
67108854 -> 67108856.0
67108855 -> 67108856.0
67108856 -> 67108856.0
67108857 -> 67108856.0
67108858 -> 67108856.0
67108859 -> 67108860.0
67108860 -> 67108860.0
67108861 -> 67108860.0
67108862 -> 67108864.0
67108863 -> 67108864.0
67108864 -> 67108864.0
67108865 -> 67108864.0
67108866 -> 67108864.0
67108867 -> 67108864.0
67108868 -> 67108864.0
67108869 -> 67108872.0
67108870 -> 67108872.0
67108871 -> 67108872.0
67108872 -> 67108872.0
67108873 -> 67108872.0
67108874 -> 67108872.0
67108875 -> 67108872.0
67108876 -> 67108880.0
67108877 -> 67108880.0
67108878 -> 67108880.0
67108879 -> 67108880.0