Dunka
Dunka

Reputation: 135

Arithmetic Error When Converting String to Double

I'm writing a function to convert a user provided string into a double. It works quite well for certain values, but fails for others. For example

string_to_double("123.45") = 123.45
string_to_double(12345) = 12345

but

string_to_double(123.4567) = 123.457

I'm fairly certain that this is some kind of round off error, but I'm not using approximations nor am I using very small or large values. My question is two-fold why am I getting these strange results and how can I change my code to get more accurate results? I'm also doing this as a personal challenge, so suggestions to use methods such as std::stod are not helpful. I believe the problem occurs in the second for-loop, but I felt it was wise to include the entire method because if I missed something it isn't that much extra code to read.

My Code

template <class T>
double numerical_descriptive_measures<T>::string_to_double(std::string user_input)
{
    double numeric_value = 0;//Stores numeric value of string. Return value.
    int user_input_size = user_input.size();
    int power = 0;
    /*This loop is for the characteristic portion of the input
    once this loop finishes, we know what to multiply the
    characterstic portion by(e.g. 1234 = 1*10^3 + 2*10^2 + 3*10^1 + 4)
    */
    for(int i = 0;i < user_input_size;i++)
    {
        if(user_input[i] == '.')
            break;
        else
            power++;
    }
    /*This loop is for the mantissa. If this portion is zero, 
    the loop doesn't execute because i will be greater than
    user_input_size.*/
    for(int i = 0;i < user_input_size;i++)
    {
        if(user_input[i] != '.')
        {
            numeric_value += ((double)user_input[i] - 48.0)*pow(10,power-i-1);
        }
        else
        {
            double power = -1.0;
            for(int j = i+1;j < user_input_size;j++)
            {
                numeric_value += ((double)user_input[j] - 48.0)*pow(10.0,power);
                power = power-1.0;
            }
            break;
        }
    }
    return numeric_value;
}

Upvotes: 1

Views: 63

Answers (2)

Rick Regan
Rick Regan

Reputation: 3512

Your code is not producing an incorrect value for "123.4567" but it will produce incorrect values in general. For example, string_to_double("0.0012") produces (on Visual Studio 2015)

0.0012000000000000001117161918529063768801279366016387939453125

but the correct answer is

0.00119999999999999989487575735580549007863737642765045166015625

(You would have to print them to 17 significant digits to tell the difference.)

The problem is that you can't use floating-point to convert to floating-point -- it does not have enough precision in general.

(I've written a lot about this on my site; for example, see http://www.exploringbinary.com/quick-and-dirty-decimal-to-floating-point-conversion/ and http://www.exploringbinary.com/decimal-to-floating-point-needs-arbitrary-precision/ .)

Upvotes: 2

John Zwinck
John Zwinck

Reputation: 249153

The problem is not that you are producing the wrong floating point value, the problem is that you are printing it with insufficient precision:

std::cout<<data<<std::endl

This will only print about six digits of precision. You can use std::setprecision or other methods to print more.

Upvotes: 2

Related Questions