我想在特定计算机上找到尾数位数和单位舍入。我了解这些是什么,只是不知道如何找到它们-尽管我知道它们可能因计算机而异。
我需要这个数字来执行数值分析的某些方面,比如分析错误。
我目前在想的是,我可以编写一个小的 c++ 程序来缓慢递增一个数字,直到发生溢出,但我不确定要使用什么类型的数字。
我在正确的轨道上吗?究竟如何计算这个?
我想在特定计算机上找到尾数位数和单位舍入。我了解这些是什么,只是不知道如何找到它们-尽管我知道它们可能因计算机而异。
我需要这个数字来执行数值分析的某些方面,比如分析错误。
我目前在想的是,我可以编写一个小的 c++ 程序来缓慢递增一个数字,直到发生溢出,但我不确定要使用什么类型的数字。
我在正确的轨道上吗?究竟如何计算这个?
我认为您使用的任何语言都会指定浮点数的存储方式。我知道 Java 通过使用特定的 IEEE 标准(我认为是 754)来做到这一点。
如果未指定,我认为您可以通过将 0.5 添加到 1 来进行自己的检查,以查看实际数字是否发生变化。如果是,则将 0.25 添加到 1,将 0.125 添加到 1,依此类推,直到数字不变,例如:
float a = 1;
float b = 0.5;
int bits = 0;
while (a + b != a) {
bits = bits + 1;
b = b / 2;
}
如果你只有 3 个尾数位,那么 1 + 1/16 将等于 1。
然后你已经用尽了你的尾数位。
您实际上可能需要基数为 2 而不是 1,因为 IEEE754 在开头使用隐含的“1+”。
编辑:
似乎上述方法可能存在一些问题,因为它为显然具有 4 字节浮点数的系统提供了 63 位。
这是否与中间结果有关(我对此表示怀疑,因为具有显式强制转换 [ while (((float)(a + b) != (float)(a))
] 的相同代码有类似的问题)还是(我相信更有可能)单位值可以通过调整a
更接近小数的位来表示的可能性b
指数,我还不知道。
目前,最好依靠我上面提到的语言信息,例如 IEEE754 的使用(如果该信息可用)。
我会把有问题的代码留给谨慎的玩家。也许有更多浮点知识的人然后我可以留下一个注释来解释它为什么会奇怪(没有猜想,请:-)。
编辑2:
这段代码通过确保中间体存储在浮点数中来修复它。事实证明 Jonathan Leffler 是对的——这是中间结果。
#include <stdio.h>
#include <float.h>
int main(void) {
float a = 1;
float b = 0.5;
float c = a + b;
int bits = 1;
while (c != a) {
bits = bits + 1;
b = b / 2;
c = a + b;
}
printf("%d\n",FLT_MANT_DIG);
printf("%d\n",bits);
return 0;
}
此代码输出 (24,24) 以显示计算值与头文件中的值匹配。
虽然它是用 C 编写的,但它应该适用于任何语言(特别是一种信息在标题中不可用或由于它在语言文档中指定的语言)。我只在 C 中进行了测试,因为 Eclipse 需要很长时间才能在我的 Ubuntu 机器上启动 :-)。
对于 C 和扩展 C++,信息位于<float.h>
或<cfloat>
标头中。
对于 C99,信息在标准的第 5.2.4.2.2 节中:
FLT_RADIX
FLT_MANT_DIG
FLT_DIG
FLT_EPSILON
FLT_MIN_EXP
FLT_MIN
FLT_MIN_10_EXP
FLT_MAX_EXP
FLT_MAX
FLT_MAX_10_EXP
DBL_RADIX
对于大多数这些(否或LDBL_RADIX
)的 DBL 和 LDBL 变体也是如此。该标准建议了适合 IEEE 754 的值(IEEE 754 标准的旧版本,1999 年生效;我相信,2008 年发布了一个新版本)。
您可能想查看<limits>
您的 C++ 库:
#include <iostream>
#include <limits>
#include <typeinfo>
template <typename T>
void printDetailsFor() {
std::cout
<< "Printing details for " << typeid(T).name() << ":\n"
<< "\tradix: " << std::numeric_limits<T>::radix << "\n"
<< "\tradix digits: " << std::numeric_limits<T>::digits << "\n"
<< "\tepsilon: " << std::numeric_limits<T>::epsilon() << "\n"
<< std::endl;
}
int main() {
printDetailsFor<int>();
printDetailsFor<float>();
printDetailsFor<double>();
printDetailsFor<long double>();
return 0;
}
我认为你想要std::numeric_limits<T>::digits
的应该比尾数位数多一。我的机器打印出来:
Printing details for i:
radix: 2
radix digits: 31
epsilon: 0
Printing details for f:
radix: 2
radix digits: 24
epsilon: 1.19209e-07
Printing details for d:
radix: 2
radix digits: 53
epsilon: 2.22045e-16
Printing details for e:
radix: 2
radix digits: 64
epsilon: 1.0842e-19