gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-01 14:18:15 28 4
gpt4 key购买 nike

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

string problemStr = "1.03964e-312";
double problemChild = boost::lexical_cast<double>(problemStr);

在boost的代码中设置断点:

namespace boost 
{
template <typename Target, typename Source>
inline Target lexical_cast(const Source &arg)
{
Target result = Target();

if (!boost::conversion::detail::try_lexical_convert(arg, result)) {
boost::conversion::detail::throw_bad_cast<Source, Target>();
}

return result;
}

boost::conversion::detail::throw_bad_cast<Source, Target>(); 行显示,虽然该值实际上转换为 double (结果=1.0396399999979624E-312),但测试boost::conversion::detail::try_lexical_convert(arg, result)失败的!这会导致异常:

  boost::wrapexcept<boost::bad_lexical_cast>: bad lexical cast: source type value could not be interpreted as target

我很困惑。它似乎进行了转换但仍然抛出异常?我忽略了什么?或者这实际上是一个错误?

最佳答案

这令人困惑。

一开始无法重现:https://wandbox.org/permlink/MWJ3Ys7iUhNIaBek - 您可以在那里更改编译器版本并 boost 版本

但是,将编译器更改为 clang 就可以了:https://wandbox.org/permlink/Ml8lQWESprfEplBi (即使有 boost 1.73)

事情变得更奇怪了:在我的盒子上,clang++-9 fine 即使是 asan/ubsan。

所以我开始安装一些 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
}

在 libstdc++ 上打印:

-307
308
sotest: /home/sehe/Projects/stackoverflow/test.cpp:11: int main(): Assertion `std::istringstream("1e309") >> v' failed.

在 libc++ 上:

-307
308
sotest: /home/sehe/Projects/stackoverflow/test.cpp:10: int main(): Assertion `std::istringstream("1.03964e-312") >> v' failed.

总而言之,libstdc++ 允许 subnormal representations在某些情况下:

The 11 bit width of the exponent allows the representation of numbers between 10−308 and 10308, with full 15–17 decimal digits precision. By compromising precision, the subnormal representation allows even smaller values up to about 5 × 10−324.

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

建议

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

要完全保真地使用十进制输入格式,请考虑例如cpp_dec_float:

#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

关于c++ - 为什么 boost::lexical_cast 即使转换了值也会抛出异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62553744/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com