Hopefully this helps in parsing decimal numbers..

I've seen a lot of posts around the net about parsing decimal precisions. The problem is everyone wants to use atof or atod, which while faster produces inaccurate results. The below code should produce more exact results.. Keeping in mind that any assignment to a float would cause it to be inaccurate again, and maybe even assigning it to a different double might do the same.

I briefly tested this on linux... Seems to work fine, please make any corrections as necessary. Wasn't sure what all to include in imports from my main program, this is just a snippet..

Happy coding..


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

#include <stdlib.h>
#include <string>
#include <stdio.h>
#include <sstream>
#include <iomanip>

class test {
public:
    test();
    ~test();
    double parseDouble(std::string &in, std::size_t &loc);
    long double parseBigDouble(std::string &in, std::size_t &loc);


double test::parseDouble(std::string &in, std::size_t &loc) {
    std::string s;

    int i = 0; //decimal positions
    bool incri = false;
    double floatval = 0.0;
    for (loc; loc < in.size(); loc++) {
        if (in.at(loc) == ' ') {
            if (!s.empty()) break;
        } else if (in.at(loc) == '\n' || in.at(loc) == '\r') {
            loc = in.size(); //tell us we're done with this line..
            break;
        } else if (in.at(loc) == '.') {
            incri = true;
            s += in.at(loc);
        } else {
            if (incri) {
                i++;
            }
            s += in.at(loc);
        }
    }
    if (!s.empty()) {
        std::stringstream ss;
        ss.setf(std::ios::fixed, std::ios::floatfield);
        ss.precision(i);
        ss << s;
        ss >> floatval;
        //std::cout.precision(10);
        //std::cout << std::endl << ss.str() << ' ' << floatval << std::endl;
    }
    return floatval;
}

long double test::parseBigDouble(std::string &in, std::size_t &loc) {
    std::string s;

    int i = 0; //decimal positions
    bool incri = false;
    long double floatval = 0.0;
    for (loc; loc < in.size(); loc++) {
        if (in.at(loc) == ' ') {
            if (!s.empty()) break;
        } else if (in.at(loc) == '\n' || in.at(loc) == '\r') {
            loc = in.size(); //tell us we're done with this line..
            break;
        } else if (in.at(loc) == '.') {
            incri = true;
            s += in.at(loc);
        } else {
            if (incri) {
                i++;
            }
            s += in.at(loc);
        }
    }
    if (!s.empty()) {
        std::stringstream ss;
        ss.setf(std::ios::fixed, std::ios::floatfield);
        ss.precision(i);
        ss << s;
        ss >> floatval;
        //std::cout.precision(10);
        //std::cout << std::endl << ss.str() << ' ' << floatval << std::endl;
    }
    return floatval;
}

zerohour wrote:
The problem is everyone wants to use atof or atod, which while faster produces inaccurate results.


Why do you say that? Remember that FP numbers cannot represent every real number exactly

Your code doesn't take into account signs in the mantissa or the exponent, or the e or E to specify the exponent :

1
2
3
4
5
6
-1.23456e+12
-1.23456E12
-1.23456e-12
+1.23456e12
1.23456E12
1.23456E-12


Library functions are there for a reason, I think you will find them to be very well tested & optimised.
Topic archived. No new replies allowed.