q0987
q0987

Reputation: 35992

Double precision issues when converting it to a large integer

Precision is the number of digits in a number. Scale is the number of digits to the right of the decimal point in a number. For example, the number 123.45 has a precision of 5 and a scale of 2.

I need to convert a double with a maximum scale of 7(i.e. it may have 7 digits after the decimal point) to a __int128. However, given a number, I don't know in advance, the actual scale the number has.

#include <iostream>
#include "json.hpp"
using json = nlohmann::json;
#include <string>

static std::ostream& operator<<(std::ostream& o, const __int128& x) {
    if (x == std::numeric_limits<__int128>::min()) return o << "-170141183460469231731687303715884105728";
    if (x < 0) return o << "-" << -x;
    if (x < 10) return o << (char)(x + '0');
    return o << x / 10 << (char)(x % 10 + '0');
}

int main()
{
    std::string str = R"({"time": [0.143]})";
    std::cout << "input: " << str << std::endl;
    json j = json::parse(str);
    std::cout << "output: " << j.dump(4) << std::endl;
    double d = j["time"][0].get<double>();
    __int128_t d_128_bad = d * 10000000;
    __int128_t d_128_good = __int128(d * 1000) * 10000;
    std::cout << std::setprecision(16) << std::defaultfloat << d << std::endl;
    std::cout << "d_128_bad: " << d_128_bad << std::endl;
    std::cout << "d_128_good: " << d_128_good << std::endl;
}

Output:

input: {"time": [0.143]}
output: {
    "time": [
        0.143
    ]
}
0.143
d_128_bad: 1429999
d_128_good: 1430000

As you can see, the converted double is not the expected 1430000 instead it is 1429999. I know the reason is that a float point number can not be represented exactly. The problem can be solved if I know the number of digit after the decimal point.

For example,

I can instead use __int128_t(d * 1000) * 10000. However, I don't know the scale of a given number which might have a maximum of scale 7.

Question> Is there a possible solution for this? Also, I need to do this conversion very fast.

Upvotes: 1

Views: 145

Answers (1)

Pete Kirkham
Pete Kirkham

Reputation: 49331

I'm not familiar with this library, but it does appear to have a mechanism to get a json object's string representation (dump()). I would suggest you parse that into your value rather than going through the double intermediate representation, as in that case you will know the scale of the value as it was written.

Upvotes: 1

Related Questions