【问题标题】:How to avoid `std::to_string()` making a very small double number to 0? [duplicate]如何避免`std::to_string()`将一个非常小的双数变为0? [复制]
【发布时间】:2021-02-05 10:12:41
【问题描述】:

我需要将非常小的双精度数存储为字符串格式,然后再将它们反转。但是,当我尝试在像 4.7816457028269855e-143 这样的小数字上运行 std::to_string() 时,它只会变成 0。

我提到了Set precision of std::to_string when converting floating point values 及其链接副本。但是将精度设置为非常大的数字会在所有平台上解决这个问题吗?

如何解决这个问题?
使用 to_string() 的任何替代品都可以。

【问题讨论】:

  • 嗯,它甚至没有那么小,因为 DBL_MIN = 2.2250738585072013830902327173324040642192159804623318306e-308
  • 如果您正在寻找往返的高保真度,并且您想要文本而不是二进制,并且您不在乎文本是否不是很清晰,您可以使用浮点十六进制格式.
  • @Eljay 或者如果你需要足够新的编译器,你可以使用en.cppreference.com/w/cpp/utility/to_chars

标签: c++ floating-point double c++14 tostring


【解决方案1】:

如前所述,使用std::to_string 无法实现此目的,但以足够大的精度将数字输出到std::ostringstream 将解决您的问题。

可以使用 C++ 标准库工具以跨平台方式计算所需的精度,特别是 std::numeric_limits<T>::max_digits10 常量:https://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10

例如:

std::string to_string_exact(double x) {
  std::ostringstream os;
  os << std::setprecision(std::numeric_limits<double>::max_digits10) << x;
  return os.str();
}

有关一些注意事项,另请参阅 https://possiblywrong.wordpress.com/2015/06/21/floating-point-round-trips/

【讨论】:

  • 即使没有设置精度,我看到ostringstream 解决了这个问题。但是它是跨平台的吗?
  • 它在std命名空间中,所以显然它必须是跨平台的,因为它是由C++标准定义的
【解决方案2】:

不,问题不在于精度,而在于格式。您想以科学格式(带指数)打印,但 std::to_string() 默认使用固定格式,我不知道有什么方法可以更改。

但是,如果适当,流使用科学,或者您可以使用 std::scientific 强制它:

std::ostringstream oss;
oss << 4.7816457028269855e-143;
std::string numberAsString = oss.str(); // stores "4.78165e-143"  

当然,除此之外,您还可以增加precision

如果出于某种原因不想使用科学格式,您可以使用精度足够高的固定格式。 “足够高”在这种情况下意味着超过 142,因为将有 142 个前导零:

oss << std::fixed << std::setprecision(142 + x);

但我想科学格式更适合。

【讨论】:

  • 我没有任何要求将其存储为科学格式。它可以是任何格式。主要担心的是,它不应该将其转换为 0.0。你能相应地编辑你的答案吗?
  • @iammilind 这正是这段代码的作用。你试过了吗?顺便提一句。您需要科学格式。这个数字有多少个固定格式的前导零?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多