pass string to double

I have a string containing "EoGUESS = 1e10"
How can I pass 1e10 to double EoGUESS?
I should comment that I used a search on a file for EoGUESS, and used getline to grab the whole line.
1
2
3
4
5
6
7
8
9
#include <sstream>

double str2doub(std::string str)
{
  double d;
  std::stringstream iss (str);
  d << iss;
  return d;
}



Last edited on
Stewbond's function isn't needed if you using a C++11 compliant compiler as std::stod() (along with other conversion functions) was added to the standard library.
http://www.cplusplus.com/reference/string/stod/

Andy
Last edited on
Thank you for your responses, however I still get errors. In regards to Stewbond's solution, I get the following error:

error: cannot convert 'std::string' to 'double' in initialization

with the code:

1
2
3
4
5
6
7
                                double str2doub(EoGUESS_in);
                                        {
                                        double EoGUESS;
                                        std::stringstream iss (EoGUESS_in);
                                        iss >> EoGUESS;
                                        return EoGUESS;
                                        }

where EoGUESS_in is the string "EoGUESS = 1e10"

Using stod, this will compile:

1
2
3
                             std::string::size_type sz;     // alias of size_t
                              EoGUESS = std::stod (EoGUESS_in.substr(sz));
                              cout << EoGUESS << endl;


but, I get the following output:

terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::substr
Aborted



I should mention that I mostly deal with bash scripts, where this would be extremely simple. I don't do much coding, but a c++ program was handed to me, and it needs file reading desperately. System calls are no good, because I need it to run on both Windows and Linux. Thanks, if you can help me.
Last edited on
You're missing the argument type in your function definition:
1
2
3
4
5
6
double str2doub (const string & EoGUESS_in);
{  double EoGUESS;
    std::stringstream iss (EoGUESS_in);
    iss >> EoGUESS;
    return EoGUESS;
}

PLEASE USE CODE TAGS (the <> formatting button) when posting code.
It makes it easier to read your code and also easier to respond to your post.
http://www.cplusplus.com/articles/jEywvCM9/
Hint: You can edit your post, highlight your code and press the <> formatting button.

Thanks, but it still prints out nothing for

1
2
3
4
5
6
7
double str2doub (const string & EoGUESS_in);
{  double EoGUESS;
    std::stringstream iss (EoGUESS_in);
    iss >> EoGUESS;
    return EoGUESS;
}
cout << str2doub << endl;


Is this because

 
string EoGUESS_in = "EoGuess = 1e10"


has more than just a double in there?
Yep!

You're trying to read "EoGuess" (the string up to the first whitespace) into a double, which will fail.

You could use >> three times: once for the name, once for the =, and once for the value but you might be better off with using std::string's find() and substr() methods to split the string. This will also allow you to handle "EoGuess=1e10" if you need to.

Andy
Here is the entire code, so you can see what I'm trying to do:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <fstream>
#include <stdio.h>
#include <iostream>
#include <cstdlib>
#include <sstream>
#include <istream>
#include <ostream>
#include <iostream>
#include <string>
using namespace std;

int main()
        {
        string line_EoGUESS_in;
        double EoGUESS;
        std::string search_EoGUESS_in = "EoGUESS";
        ifstream myfile;
        myfile.open("example.txt");
        if(myfile.fail())
                {
                cout << "File not found\n";
                exit(1);
                }
        bool isFound = 0;
        while(!myfile.eof())
                {
                std::string EoGUESS_in = "EoGUESS";
                getline(myfile,EoGUESS_in);
                for(int i=0;i<search_EoGUESS_in.size();i++)
                        {
                        if(EoGUESS_in[i]==search_EoGUESS_in[i])
                                {
                                isFound = 1;
                                break;
                                }
                        else
                                {
                                isFound = 0;
                                break;
                                }
                        }
                if(isFound)
                        {
                        getline(myfile,line_EoGUESS_in);
                        if (line_EoGUESS_in.find(EoGUESS_in))
                                {
                                std::cout << EoGUESS_in << endl;
                                double strtodoub (string line_EoGUESS_in);
                                        {
                                        double EoGUESS;
                                        std::stringstream iss (line_EoGUESS_in);
                                        iss >> EoGUESS;
                                        return EoGUESS;
                                        }
                                        std::cout << strtodoub << endl;

                                }
                        }
                }
        myfile.close();
        return 0;
        }
Read the help on std::string::find() and std::string::substr() in the reference section on this site and then have another go.

Lines 29-41 look like some sort of attempt at a find() routine.

Andy

PS It will prob help if you write a little test program to work out how to use the string mehods to split a string on a token.
Last edited on
Lines 29-41 work perfectly. It is setting EoGUESS equal to the second token (i.e. 1e10) that I can't figure out how to do. I can split into tokens using the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <cstdlib>
#include <istream>
#include <ostream>
#include <sstream>
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;

double EoGUESS;

int main()
        {
                        std::string EoGUESS_in = "EoGUESS = 1e10";
                                std::cout << EoGUESS_in << endl;
                                string delimiter = "=";
                                size_t pos = 0;
                                string token;
                                while ((pos = EoGUESS_in.find(delimiter)) != std::string::npos)
                                       {
                                       token = EoGUESS_in.substr(0, pos);
                                        cout << token << std::endl;
                                        EoGUESS_in.erase(0, pos + delimiter.length());
                                std::cout << EoGUESS_in << endl;
                                        }
        }


My output is the following:

EoGUESS = 1e10
EoGUESS
1e10

I want to set the second token to the double EoGUESS. If I try

 
EoGUESS = token[1];


I just get 1... I would use a system call to awk if I could, and it would be the simplest thing ever (I could do this whole code in one or two lines), but it has to run on Windows as well as Linux... Please someone tell me how to do it. I have no choice, since the main program is written in c++, and I am just making it easier to use for others.
Last edited on
EoGUESS = token[1];

Why did you think this would be of any use??? cf. using Stewbond's function?

(I thought you understood what that did.)

Andy

PS Regarding

Lines 29-41 work perfectly.

But doing what?

As you break out of you loop whatever your if condition evaluates to, you only ever test the first element of the strings. So you code is equivalent to

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    bool  isFound = true; // bool values are true or false

    if(EoGUESS_in[0]==search_EoGUESS_in[0])
    {
        isFound = true;
    }
    else
    {
        isFound = false;
    }

    if(isFound)
    {
        // etc 


or more succintly

1
2
3
    if(EoGUESS_in[0]==search_EoGUESS_in[0])
    {
        // etc 
Last edited on
Maybe if I post the input file, it will make more sense. Sorry if I seem dense, but I am not a programmer by trade. I am a physicist. Here is what I am trying to do -- I have the following input file:


NtsGUESS = 1e10*1e4
EoGUESS = 1e10
EoDEFAULT = 4
NtsDEFAULT = 1e19*1e4
paramSTEP = 1.2,
deltx = 1e-8

Na = 1e16*1e6
Nd = 1e15*1e6
Brad = 1e-10*1e-6
sigma = 1e-12 *1e-4
sigmaneutral = sigma*1e-3
&vary = Nd
varystart = 1e16*1e6
varymax = 1e16*1e6
varystep = sqrt(10.0)

T = 300


I need to parse each of these values with the above subroutine into the main program and set them equal to a double with the same name as the left set of characters. So, for example, I scan the file for EoGUESS, getline, and then I need to set the double EoGUESS = 1e10. I need to do this for all values. This is a test program. Am I going about this all wrong?
Last edited on
OK, so after much trial and error, I was able to pass my substring to a double. FYI, I figured token[1] would be similar to vector[1], but it was not. That is why I tried that. With the following code, I do something similar with vector[1]... This is my solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <string>
#include <vector>
#include <functional>
#include <iostream>
#include <sstream>

using namespace std;

double EoGUESS;


                                void EoGUESS_split (const string &EoGUESS_in, char EoGUESS_c, vector<string> &EoGUESS_v)
                                        {
                                        string::size_type k = 0;
                                        string::size_type j = EoGUESS_in.find(EoGUESS_c);

                                        while (j != string::npos)
                                                {
                                                EoGUESS_v.push_back(EoGUESS_in.substr(k,j-1));
                                                k = ++j;
                                                j = EoGUESS_in.find(EoGUESS_c,j);

                                                if (j==string::npos)
                                                        EoGUESS_v.push_back(EoGUESS_in.substr(k,EoGUESS_in.length()));
                                                }
                                        }
                                int main()
                                        {
                                        string EoGUESS_in = "EoGUESS = 1e10";
                                        vector<string> EoGUESS_v;
                                        EoGUESS_split(EoGUESS_in, '=', EoGUESS_v);
                                        istringstream ss(EoGUESS_v[1]);
                                        ss >> EoGUESS;
                                        cout << EoGUESS << endl;
                                        return 0;
                                        }
As the file is just name-value pairs I would simplify your split routine to return the name and value, rather than a vector.

Your split routine has a bug on line 19 which affects strings with more than one =. For example, "EoGUESS = 1e10 = whatever" ends up as "EoGUESS", " 1e10 = whatev" and " whatever".

EoGUESS_v.push_back(EoGUESS_in.substr(k,j-k)); // it was 'substr(k,j-1);

It also does not handle badly formed strings.

Howabout?

1
2
3
4
5
6
7
8
9
10
11
12
13
bool EoGUESS_split (const string &EoGUESS_in, char EoGUESS_c, string& name, string& value)
{
    using namespace StringUtils;

    string::size_type pos = EoGUESS_in.find(EoGUESS_c);
    if (pos == string::npos)
        return false;

    name  = Trim(EoGUESS_in.substr(0, pos));
    value = Trim(EoGUESS_in.substr(pos + 1));

    return true;
}


where the Trim() function removes leading and trailing whitespace (see below)

Andy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <string>
#include <iostream>
#include <sstream>

using namespace std;

//double EoGUESS; => now a local

// http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring/347974#347974
namespace StringUtils {

const std::string WHITESPACE = " \t";

inline std::string TrimLeft(const std::string& s) {
    size_t startpos = s.find_first_not_of(WHITESPACE);
    return (startpos == s.npos) ? "" : s.substr(startpos);
}

inline std::string TrimRight(const std::string& s) {
    size_t endpos = s.find_last_not_of(WHITESPACE);
    return (endpos == s.npos) ? "" : s.substr(0, endpos + 1);
}

inline std::string Trim(const std::string& s) {
    return TrimRight(TrimLeft(s));
}

} // end namespace StringUtils

bool EoGUESS_split (const string &EoGUESS_in, char EoGUESS_c, string& name, string& value)
{
    using namespace StringUtils;

    string::size_type pos = EoGUESS_in.find(EoGUESS_c);
    if (pos == string::npos)
        return false;

    name  = Trim(EoGUESS_in.substr(0, pos));
    value = Trim(EoGUESS_in.substr(pos + 1));

    return true;
}

bool StrToDbl(const std::string& str, double& val)
{
    istringstream ss(str);
    char dummy = '\0';
    // if we successfuly extract a double value and don't
    // find anything apart from whitespace afterwards
    return ((ss >> val) && (ss >> std::ws && !ss.get(dummy)));
}

void test(const string &EoGUESS_in)
{
    cout << "[Input]" << endl;
    cout << "\"" << EoGUESS_in << "\"" << endl;
    cout << endl;

    string name;
    string value;
    bool split_ok = EoGUESS_split(EoGUESS_in, '=', name, value);

    if(split_ok)
    {
        cout << "[Split]" << endl;
        cout << "name  = \"" << name  << "\"" << endl;
        cout << "value = \"" << value << "\"" << endl;
        cout << endl;

        double EoGUESS = 0.0;
        bool conv_ok = StrToDbl(value, EoGUESS);
        if(conv_ok)
        {
            cout << "[Value]" << endl;
            cout << EoGUESS << endl;
            cout << endl;
        }
        else
        {
            cout << "conversion failed?" << endl;
            cout << endl;
        }
    }
    else
    {
        cout << "split failed?" << endl;
        cout << endl;
    }
}

int main()
{
    const char* testdata[] =
    { "EoGUESS = 1e10"
    , "EoGUESS = 1e10 whatevers"
    , "EoGUESS=1e10"
    , "EoGUESS - 1e10"
    , "  EoGUESS  =1e10"
    , "        "
    , "" };

    const size_t count = sizeof(testdata)/sizeof(testdata[0]);

    for(size_t index = 0; index < count; ++index)
    {
        test(testdata[index]);
    }

    return 0;
}

Last edited on
Wow, thanks Andy. I'm not sure I understand everything here, since I just started learning c++ the other day, but I get most of it. I see your point, because when I try the same code for Na, rather than EoGUESS, I get

1e16

rather than

1e16*1e6

Also, I see what you meant about my find routine. It finds a little more than I would like, and I just posted another thread about it.
Topic archived. No new replies allowed.