【问题标题】:Converting strange string to double C++将奇怪的字符串转换为双 C++
【发布时间】:2020-10-16 11:58:09
【问题描述】:

我需要将数据从文件转换为双精度数据,有时数据格式为:

0.3387000000D+02  0.6067999217D-02
0.5095000000D+01  0.4530799416D-01
0.1159000000D+01  0.2028219738D+00
0.3258000000D+00  0.5039029350D+00
0.1027000000D+00  0.3834209505D+00

您将如何处理此处的D

这是科学记数法,只有D 而不是E

我正在考虑在这里使用std::regex,但我希望有一个更优雅的策略。

类似于以下内容:

std::regex rr("((\\+|-)?[[:digit:]]+)(\\.(([[:digit]]+)?))?(d|D )((\\+|-)?)[[:digit:]]+)""?");

【问题讨论】:

  • 你确定D和E的意思一样吗?您从哪里获得这些数据?
  • 已确认,它确实意味着 E。此数据来自量子化学包 MOLPRO。我可以用 E 替换 D 并让标准转换函数处理其余部分...
  • @JohnFilleau Fortran 使用 D 而不是 E。参见 Scientific d notation not read in C++
  • 是的,完全正确。 MOLPRO 是用 FORTRAN 编写的,感谢您的链接!
  • 回复:“希望有更优雅的策略”——良好的直觉。正则表达式很少适用。我用一只手就能数出我在 StackOverflow 上看到的有关正则表达式的问题的数量,其中正则表达式实际上是最好的解决方案。

标签: c++ regex string double data-conversion


【解决方案1】:

D 替换为Estd::replace,之后就很简单了:

Live demo

std::string s = "0.3387000000D+02";
std::replace( s.begin(), s.end(), 'D', 'E');
std::cout << std::stod(s);

std::replace_if:

Live demo

bool isD(char c) { 
    return c == 'D'; 
}
std::string s = "0.3387000000D+02";
std::replace_if( s.begin(), s.end(), isD, 'E');
std::cout << std::stod(s);

输出:

33.87

【讨论】:

  • 非常好!现在取决于程序的版本,只有有时字符串会有一个 D。那么,如果替换函数实际替换了任何内容,您可以修改您的代码以包含 if 语句吗?
  • @zstreet,当然。
  • @zstreet,完成了,第一个只有在找到 D 时才会替换,否则它什么也不做,但你有第二个选项。
  • 哦,std::replace 的第一个选项如果不合适 D 就什么也不做?我喜欢!谢谢!
【解决方案2】:

你可以这样做。

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <cmath>

double string2double(std::string s)
{
    // Find the index of scientific D
    int indexD = s.find('D');
    // separate the base from rest, start at 0 and go till index of D, without D
    std::string number = s.substr(0, indexD);
    //indexD+2 to ignore D and plus 
    std::string power = s.substr(indexD+2);
    
    // do conversion from string to number
    double rawNumber = std::stod(number);
    double powerNumber = std::stod(power);
    //test
    std::cout << rawNumber << std::endl;
    std::cout << powerNumber << std::endl;
    //return
    return rawNumber * std::pow(10, powerNumber);
}



int main()
{   

    std::string s = "0.3387000000D+02";
    std::cout << string2double(s) << std::endl;
    return 0;
}

【讨论】:

  • 解析浮点文字有几个微妙的问题。这种蛮力代码在大多数情况下都可以工作,但会导致许多边缘情况出错。例如,对于典型的 64 位双精度数,最大指数为 37。但.00001e40 是一个有效的有限值;它只是写得很有趣。 std::stod 可以处理;它产生与std::stod(1.0e35) 相同的结果。但是,如果您拆分指数,std::pow(10, 40) 将给出无穷大。将无穷大乘以任何非零值会得到无穷大,这就是此函数将为.00001D40 返回的值。
  • 还要注意有一个错字:s.substr(indexD+2) 应该是s.substr(indexD+1)。该代码适用于main 中的测试值,因为指数为02;如果是12,结果将是错误的。
  • 这里的寓意是:在处理浮点数学时不要相信自己的直觉。你的直觉来自对实数的经验;浮点数不是实数,你的直觉(和我的!)经常是错误的。
  • 感谢皮特的评论!很高兴知道
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-06
  • 1970-01-01
  • 1970-01-01
  • 2015-01-26
  • 2021-12-24
  • 1970-01-01
相关资源
最近更新 更多