mak*_*ako 4 c++ floating-point
#include <iostream>
#include <cmath>
#include <sstream>
using namespace std;
int main(){
stringstream ss;
double ad = 7.63918e-313;
ss << ad;
cout<<ss.str()<<endl;
//you will see that the above double is valid, and maps to the specified string
//but stod cannot map it back
stod("7.63918e-313");
//terminate called after throwing an instance of 'std::out_of_range'
}
Run Code Online (Sandbox Code Playgroud)
在此处运行:https://onlinegdb.com/Sy1MT1iQM
"7.63918e-313"将序列化一个double,但是stod不能反序列化它.这里发生了什么?可能的最小双倍大约是10 ^ -324.
stdlib中是否有一对函数能够可靠地从字符串化中来回映射双精度?不应该吗?
情节变粗.我们有两个奇怪的观察.
std::numeric_limits<double>::min() stod也无法解析.
std::numeric_limits<double>::min()不是最小的双倍.我们的双倍小,我发现我们可以通过简单地分割min来获得更小的双打,所以这不是我的双重异常或任何东西https://onlinegdb.com/rJvilljQz
我很担心.
double如果结果处于次正常范围内,则C++标准允许字符串转换为报告下溢,即使它是可表示的.
7.63918•10 -313在范围内double,但它处于低于正常范围.C++标准说stod调用strtod然后按照C标准来定义strtod.C标准表明strtod可能下溢,它表示"如果数学结果的大小如此之小,以至于数学结果无法表示,在指定类型的对象中没有非常的舍入误差,则结果下溢."这是尴尬的措辞,但它指的是遇到次正常值时发生的舍入误差.(次正常值会受到比正常值更大的相对误差,因此可以说它们的舍入误差非常大.)
因此,C++标准允许C++实现对次正规值进行下溢,即使它们是可表示的.
关于你的观察std::numeric_limits<double>::min()"无法解析"(我认为你的意思是它也报告下溢),这可能是由于你转换std::numeric_limits<double>::min()为包含十进制数字的字符串这一事实,并且十进制数字不是一个精确的表示std::numeric_limits<double>::min().如果它向下舍入,则略小于min(),因此它也处于低于正常范围.因此,尝试将该十进制数字转换回a double可以正确地报告它低于正常范围.
关于你的观察std::numeric_limits<double>::min()不是最小的double,这是正确的.std::numeric_limits<double>::min()由C++标准指定为最小正正常值.它下面可能有低于正常值.
对于IEEE-754 64位二进制浮点,正常范围为2 -1022到2 1024 -2 971.在此范围内,每个数字都用signficand(浮点表示的小数部分)表示,其前导1位后跟52个附加位,因此将此范围内的任何实数舍入到最接近的可表示值至多是前导位的位置值的2-53倍.
除此正常范围外,还存在从2 -1074到2 -1022 -2 -1074的低于正常范围.在此间隔中,浮点格式的指数部分已达到其最小值,不能再降低.为了在此间隔中表示越来越小的数字,有效数字将减少到正常最小值1以下.它以0开始,后跟52个附加位.在该间隔中,将实数四舍五入到最接近的可表示值时发生的误差可能大于前导位的位置值的2-53倍.由于指数不能再进一步降低,因此该区间中的数字随着它们变得越来越小而具有越来越多的前导0位.因此,使用这些数字所涉及的相对误差增加了.
无论出于何种原因,C++都表示实现可能会在此时间间隔内报告下溢.(IEEE-754标准以复杂的方式定义下溢,并允许实现一些选择.)