C++ 如何正确使用 std::stod

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26008321/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:29:40  来源:igfitidea点击:

How to use std::stod properly

c++

提问by nickfoss32

I am working on writing a simple linear line calculator. For example, a user can enter two equations (strings) such as y=5x+3 and y=-3x+6. The most basic feature of this calculator is that it will return the intersection point of these two lines.

我正在编写一个简单的线性计算器。例如,用户可以输入两个方程(字符串),例如 y=5x+3 和 y=-3x+6。这个计算器最基本的功能就是会返回这两条线的交点。

The obstacle I can't seem to figure out is how to parse the string into two pieces of data: the slope, and the y-intercept. This is a simple calculator, so the format of both lines will be y=mx+b, however, both the slope and/or y-intercept may be non-integer numbers (i.e. floats).

我似乎无法弄清楚的障碍是如何将字符串解析为两部分数据:斜率和 y 截距。这是一个简单的计算器,所以两条线的格式都是 y=mx+b,但是,斜率和/或 y 截距都可能是非整数(即浮点数)。

I came across a function in the string library called stod, which converts a number in a string to a numerical value (am I understanding this correctly?).

我在字符串库中遇到了一个名为 stod 的函数,它将字符串中的数字转换为数值(我理解正确吗?)。

http://www.cplusplus.com/reference/string/stod/

http://www.cplusplus.com/reference/string/stod/

My question is, will this function do the job? If so, how exactly do I use the "idx" parameter? I don't quite understand it.

我的问题是,这个功能能完成这项工作吗?如果是这样,我究竟如何使用“idx”参数?我不太明白。

If this isn't going to work, how can I parse this user-entered data?

如果这不起作用,我该如何解析用户输入的数据?

  • both equations are strings (y=mx+b)
  • m and b have private variables dedicated in storing the decimal value (i.e. double m_ and double b_ are private member variables)
  • 两个方程都是字符串 (y=mx+b)
  • m 和 b 有专门用于存储十进制值的私有变量(即 double m_ 和 double b_ 是私有成员变量)

回答by Brandon

This is how the idx parameter works:

这是 idx 参数的工作方式:

#include <string>
#include <iostream>

int main(void)
{
    std::string data = "y=5.9568x+3.14"; //say you have a string like this..

    double y, x, m, b;
    y = 0;
    x = 0;

    std::size_t offset = 0; //offset will be set to the length of characters of the "value" - 1.
    m = std::stod(&data[2], &offset); //So we want to get the value "5.9568
    b = std::stod(&data[offset + 3]); //When we reach this line, offset has a value of 6

    std::cout<<b;
    return 0;
}

So now you're asking why does it have a value of 6? Well because:

所以现在你要问为什么它的值为 6?嗯,因为:

5.9568 is exactly: 6 characters in length. Thus on the next line when we do

5.9568 正好是:长度为 6 个字符。因此在我们做的下一行

b = std::stod(&data[offset + 3]);

b = std::stod(&data[offset + 3]);

we are actually feeding it a pointer to address of x+ 3.. and that turns out to be right at the beginning of the 3.14.

我们实际上给它提供了一个指向x+ 3 的地址的指针3.14

In other words it's equivalent to:

换句话说,它相当于:

std::stod(&data[9]);

std::stod(&data[9]);

So that idx parameter is actually the index/length of the double in characters within the string. If the string is:

所以 idx 参数实际上是字符串中字符中双精度值的索引/长度。如果字符串是:

str = "3.14159"

str = "3.14159"

Then std::stod(str, &idx)will make idx equal to: 6.

然后std::stod(str, &idx)将使 idx 等于:6。

if the string is:

如果字符串是:

str = "y = 1024.789"then std::stod(&str[4], &idx)will make idx equal to: 8 STARTING FROM &str[4]..

str = "y = 1024.789"然后std::stod(&str[4], &idx)将使 idx 等于:8 STARTING FROM &str[4]..

回答by Null

Here's something simple with no error checking to get you started:

这里有一些简单的没有错误检查的东西可以让你开始:

Assuming your input string is always exactly of the form y=mx+band you wish to parse it to obtain the numerical values of mand byou can first tokenize the string with y, =, x, and as delimiters.

假设你的输入字符串总是完全形式的y=mx+b,你要分析它获得的数值m,并b可以先标记化的字符串y=x,和作为分隔符。

An example of a tokenizing function can be found here. Here it is reproduced:

可以在此处找到标记化函数的示例。这里转载:

void tokenize(const std::string &str,
              std::vector<std::string> &tokens,
              const std::string &delimiters)
{
  // Skip delimiters at beginning.
  std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
  // Find first "non-delimiter".
  std::string::size_type pos     = str.find_first_of(delimiters, lastPos);

  while (std::string::npos != pos || std::string::npos != lastPos)
  {
    // Found a token, add it to the vector.
    tokens.push_back(str.substr(lastPos, pos - lastPos));
    // Skip delimiters.  Note the "not_of"
    lastPos = str.find_first_not_of(delimiters, pos);
    // Find next "non-delimiter"
    pos = str.find_first_of(delimiters, lastPos);
  }
}

The first argument is the string to tokenize, the second is a reference to a vector<string>which the function will put the tokens in, and the third argument is a string containing all the delimiter characters. You can use it with the delimiters mentioned above like this:

第一个参数是要标记的字符串,第二个是vector<string>函数将标记放入的对a 的引用,第三个参数是包含所有分隔符的字符串。您可以将它与上面提到的分隔符一起使用,如下所示:

string s = "y=-3x + 10";
vector<string> tokens;
tokenize(s, tokens, "y=x ");

For the example string above tokenswill contain the following strings: -3, +, and 10.

对于例如上面的字符串tokens将包含以下字符串:-3+,和10

Now you can iterate over tokensand call stod()on each token. You can put the results of stod()in a vector<double>:

现在您可以迭代tokens并调用stod()每个令牌。您可以将结果stod()放在 a 中vector<double>

vector<double> doubles;
for (vector<string>::iterator iter = tokens.begin(); iter != tokens.end(); ++iter) {
    try {
        doubles.push_back(stod(*iter)); // size_t* idx is an optional argument
    } catch (...) {
        // handle exceptions here. stod() will throw an exception
        // on the "+" token but you can throw it away
    }
}

Now doublesshould have exactly 2 elements -- one for the slope and another for the intercept. Assuming the slope came first (the string was of the form y=mx+binstead of y=b+mx) then you can extract them from doubles:

现在doubles应该正好有 2 个元素——一个用于斜率,另一个用于截距。假设斜率首先出现(字符串的形式y=mx+b不是y=b+mx),那么您可以从 中提取它们doubles

double m = doubles[0];
double b = doubles[1];

Parsing the initial string is more complicated if the user is allowed different forms like y=b+mx(in that case the intercept came first), and much more complicated if the user can enter even stranger (but valid) forms like x*m+b=y(now you can't just assume that the number before the xcharacter is the slope). It's not clear from your question exactly what alternate forms are considered valid, but nonetheless this should get you started.

如果允许用户使用不同的形式y=b+mx(在这种情况下拦截首先出现),解析初始字符串会更复杂,如果用户可以输入更奇怪(但有效)的形式x*m+b=y(现在你不能假设x字符前的数字是斜率)。从您的问题中不清楚哪些替代形式被认为是有效的,但这应该让您开始。

Finally, as to your question about *idx, stod()puts into it the position of the first character after the number it parsed. This allows you to easily parse multiple numbers in a single string by skipping the number that was just parsed. Using the example at your reference link with some added comments:

最后,对于您关于 的问题*idxstod()将其解析的数字后的第一个字符的位置放入其中。这允许您通过跳过刚刚解析的数字来轻松解析单个字符串中的多个数字。使用参考链接中的示例并添加一些注释:

std::string orbits ("365.24 29.53");
std::string::size_type sz;     // alias of size_t

double earth = std::stod (orbits,&sz);
// sz now holds the position of the first character after 365.24, which is whitespace
// the next call to stod() will start from the sz position
double moon = std::stod (orbits.substr(sz));