精确浮点<-&燃气轮机;字符串转换 我正在寻找一个库函数,将浮点数转换为字符串,然后再返回到C++中。我想要的属性是str2num(num2str(x))==x和num2str(str2num(x))==x(尽可能)。一般属性是num2str应该表示最简单的有理数,当四舍五入到最接近的可表示的浮点指针数时,它将返回原始数

精确浮点<-&燃气轮机;字符串转换 我正在寻找一个库函数,将浮点数转换为字符串,然后再返回到C++中。我想要的属性是str2num(num2str(x))==x和num2str(str2num(x))==x(尽可能)。一般属性是num2str应该表示最简单的有理数,当四舍五入到最接近的可表示的浮点指针数时,它将返回原始数,c++,C++,到目前为止,我已经尝试了boost::lexical_cast: double d = 1.34; string_t s = boost::lexical_cast<string_t>(d); printf("%s\n", s.c_str()); // outputs 1.3400000000000001 double d=1.34; 字符串s=boost::词法转换(d); printf(“%s\n”,s.c_str()); //产出13400000000000001 我尝试了

到目前为止,我已经尝试了boost::lexical_cast:

double d = 1.34;
string_t s = boost::lexical_cast<string_t>(d);
printf("%s\n", s.c_str());
// outputs 1.3400000000000001
double d=1.34;
字符串s=boost::词法转换(d);
printf(“%s\n”,s.c_str());
//产出13400000000000001
我尝试了std::ostringstream,如果我使用stream.precision(16),它似乎适用于大多数值。然而,在精度为15或17时,它会截断或给出像1.34这样的输出。我认为精度16不能保证有我所需要的任何特定属性,并且怀疑它在许多数字中都会失效

<>有一个C++库有这样的转换吗?或者,这样的转换函数已经埋在标准库/boost中了吗

需要这些函数的原因是将浮点值保存到CSV文件中,然后正确读取它们。此外,我希望CSV文件尽可能包含简单的数字,以便人类可以使用它们

我知道Haskell read/show函数已经具有我想要的属性,BSD C库也是如此。stringdouble转换的标准参考文献是一对来自PLDI 1990的论文:

  • 如何准确读取浮点数,威尔·克林格
  • 如何准确打印浮点数,Guy Steele等人

基于这些的任何C++库/函数都是合适的。 编辑:我完全知道浮点数是十进制数的不精确表示,1.34==1.3400000000000001。然而,正如上面提到的论文所指出的,这不是选择显示为“1.34000000000000001”的借口


编辑2:这篇文章准确地解释了我要找的是什么:

事实上,我想你会发现1.34等于1.34000000001。浮点数不精确。你不能逃避这个。例如,1.34f是1.340000000333786011。

如其他人所述。浮点数没有那么精确,这是它们如何存储值的一个伪影

您真正需要的是十进制数字表示法。 基本上,它使用一个整数来存储数字,并且在小数点后具有特定的精度

谷歌很快就发现了这一点:

我仍然找不到提供必要代码的库,但我确实找到了一些有效的代码:


通过提供相当少的定义,很容易抽象出Python集成。这段代码确实满足了我列出的所有属性。

我认为这符合您的要求,与标准库的strod()结合使用:

我想您的C库需要符合一些足够新的标准版本,以保证正确的舍入

我不确定我选择了
prec
的理想边界,但我想它们一定很接近。也许他们可以更紧些?类似地,我认为
buf
的32个字符总是足够的,但从来没有必要。显然,这一切都假设64位IEEE双倍。也许值得用某种聪明的预处理器指令来检查这个假设--
sizeof(double)==8将是一个好的开始

指数有点混乱,但在中断循环后但在返回之前修复它并不困难,也许可以使用
memmove()
或类似的方法向左移动。我很确定最多保证有一个
+
和最多一个领先的
0
,我认为它们甚至不能同时出现在
prec>=10
左右的情况下

同样,如果您希望像Javascript那样忽略带符号的零,您可以轻松地预先处理它,例如:

if(n == 0) return snprintf(buf, size, "0");
我很想看到与您在Python代码库中挖掘的3000行怪物的详细比较。大概短版本比较慢,或者不太正确,或者什么的?如果两者都不是,那将是令人失望的

需要这些函数的原因是将浮点值保存到CSV文件中,然后正确读取它们。此外,我希望CSV文件尽可能包含简单的数字,以便人类可以使用它们

不能有双精度转换→ 一串→ 双击并同时使字符串可读

您需要在精确转换和人类可读字符串之间进行选择。这是
max_digit10
digit10
的定义:

这里是一个
num2str
str2num
的实现,它使用两个不同的上下文
从双精度转换→ 一串→ 双精度)和
(转换字符串→ 双重的→ 字符串):

#包括
#包括
#包括
#包括
名称空间从\u double
{
std::string num2str(双d)
{
std::stringstream-ss;
ss标准::设置精度(标准::数值限制::最大数字10)>>d;
返回d;
}
}
来自\u字符串的名称空间
{
std::string num2str(双d)
{
std::stringstream-ss;
ss std::setprecision(std::numeric_limits::digits10)>>d;
返回d;
}
}
int main()
{
双d=1.34;
if(from_double::str2num(from_double::num2str(d))==d)

当我搜索一个,我发现了一个C,而不是C++。我没有链接。我好像记得它是在NAG的FTP站点上的,但是我可能错了。C库同样是好的。我现在只是检查NAG文档。你可以查看GMP和MPFR,用于软件浮点仿真。但是你要的是我。对于C++的
fl是不可能的
int main(int argc, char** argv)
{
  int i;
  for(i = 1; i < argc; i++)
  {
    char buf[32];
    dtostr(buf, sizeof(buf), strtod(argv[i], 0));
    printf("%s\n", buf);
  }
  return 0;
}
% ./a.out 0.1 1234567890.1234567890 17 1e99 1.34 0.000001 0 -0 +INF NaN
0.1
1234567890.1234567
17
1e+99
1.34
1e-06
0
-0
inf
nan
if(n == 0) return snprintf(buf, size, "0");
#include <iostream>
#include <limits>
#include <iomanip>
#include <sstream>

namespace from_double
{
  std::string num2str(double d)
  {
    std::stringstream ss;
    ss << std::setprecision(std::numeric_limits<double>::max_digits10) << d;
    return ss.str();
  }

  double str2num(const std::string& s)
  {
    double d;
    std::stringstream ss(s);
    ss >> std::setprecision(std::numeric_limits<double>::max_digits10) >> d;
    return d;
  }
}

namespace from_string
{
  std::string num2str(double d)
  {
    std::stringstream ss;
    ss << std::setprecision(std::numeric_limits<double>::digits10) << d;
    return ss.str();
  }

  double str2num(const std::string& s)
  {
    double d;
    std::stringstream ss(s);
    ss >> std::setprecision(std::numeric_limits<double>::digits10) >> d;
    return d;
  }
}

int main()
{
  double d = 1.34;
  if (from_double::str2num(from_double::num2str(d)) == d)
    std::cout << "Good for double -> string -> double" << std::endl;
  else
    std::cout << "Bad for double -> string -> double" << std::endl;

  std::string s = "1.34";
  if (from_string::num2str(from_string::str2num(s)) == s)
    std::cout << "Good for string -> double -> string" << std::endl;
  else
    std::cout << "Bad for string -> double -> string" << std::endl;

  return 0;
}