Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么boost::lexical_cast即使转换了值也会抛出异常?_C++_Boost - Fatal编程技术网

C++ 为什么boost::lexical_cast即使转换了值也会抛出异常?

C++ 为什么boost::lexical_cast即使转换了值也会抛出异常?,c++,boost,C++,Boost,我手上有一个令人费解的错误。我确信这段代码在早期版本的boost中运行良好,现在(boost 1.72.0)它抛出了一个异常: string problemStr = "1.03964e-312"; double problemChild = boost::lexical_cast<double>(problemStr); boost::wrapexcept<boost::bad_lexical_cast>: bad lexical cast:

我手上有一个令人费解的错误。我确信这段代码在早期版本的boost中运行良好,现在(boost 1.72.0)它抛出了一个异常:

string problemStr = "1.03964e-312";
double problemChild = boost::lexical_cast<double>(problemStr);
  boost::wrapexcept<boost::bad_lexical_cast>: bad lexical cast: source type value could not be interpreted as target
我很困惑。它似乎进行了转换,但仍然抛出异常?我忽略了什么?或者这实际上是一个bug?

这让人困惑

一开始无法重新编译:-您可以在那里更改编译器版本和增强版本

然而,将编译器更改为clang成功了:(即使使用boost 1.73)

事情变得更奇怪:在我的盒子上,即使使用asan/ubsan,叮当++-9也可以

所以我开始安装一些docker发行版

事实证明,当使用
clagn++-stdlib=libc++
时,事情会破裂

结论 经过长时间的调试器和标准库实现,它并没有那么复杂。下面是一些细节:

#include <sstream>
#include <cassert>
#include <iostream>

int main() {
    double v;
    std::cout << std::numeric_limits<double>::min_exponent10 << std::endl;
    std::cout << std::numeric_limits<double>::max_exponent10 << std::endl;
    assert(std::istringstream("1e308") >> v);
    assert(std::istringstream("1.03964e-312") >> v); // line 10
    assert(std::istringstream("1e309") >> v); // line 11
}
关于libc++:

-307
308
sotest: /home/sehe/Projects/stackoverflow/test.cpp:10: int main(): Assertion `std::istringstream("1.03964e-312") >> v' failed.
总之,libstdc++在某些情况下允许:

指数的11位宽度允许表示10到10之间的数字−308和10308,具有完整的15–17位小数精度。通过降低精度,低于正常值的表示允许更小的值,最高可达约5×10−324

图书馆可能会进行一些检查,以确定精度损失是否可以接受,但也可能完全由您自己判断

建议 如果您需要这种范围,我建议您使用多精度库(GMP、MPFR或Boost)

对于十进制输入格式的完全保真度,考虑例如CPPPyDEXFLIFT:

#include <boost/multiprecision/cpp_dec_float.hpp>
using Decimal = boost::multiprecision::cpp_dec_float_50;

int main() {
    Decimal v("1.03964e-312");
    std::cout << v << std::endl;
}

我在macOS High Sierra(10.13.6)。非常感谢您提供的详尽答案。我发现wandbox工具非常有用,也谢谢你。我确实在使用Clang10.0.0(我没有提到这一点)。关于您使用十进制的建议:一个好主意。不幸的是,这并不是我的选择。我的代码大量使用模板,应该可以处理各种数字类型。现在,我正在通过将这些值设置为0来解决这个问题。毫无疑问,它们本身就是舍入误差的结果,我将追查其原因,并尝试在那里消除该问题。“各种数字类型”都有效!但是,我建议您这样做,因为它们确实倾向于破坏(“意外”)通用代码。事实上,听起来准确度并不是一个真正的目标,因为你的输入已经不准确了,所以使用双打可能对你有好处。如果你发现你得到了像这样的“边界条件输入”,并且希望能够更好地诊断它们,你可以混合/匹配。
-307
308
sotest: /home/sehe/Projects/stackoverflow/test.cpp:10: int main(): Assertion `std::istringstream("1.03964e-312") >> v' failed.
#include <boost/multiprecision/cpp_dec_float.hpp>
using Decimal = boost::multiprecision::cpp_dec_float_50;

int main() {
    Decimal v("1.03964e-312");
    std::cout << v << std::endl;
}
1.03964e-312