C++ Function 'stod': String-to-Double (convert a string to a double)

tux4life 0 Tallied Votes 4K Views Share

Hello there, I've written a C++ function 'stod', which converts a C++ string to a double ...
You're free to use this code for EVERYTHING you want ...
There's only one thing which I'm not appreciating:
It's not allowed to sell this source code to anyone !

The usage is simple:

double dbl;
string test = "25.23";
dbl = stod(test); /* We convert the string to a real double */

If you pass a string which can't be turned into a number, the function's output is always '0' ...

As you maybe already have found out (is this grammatically correct?) the function's name is inspired by the C-function 'atoi' ...

Hope you find this code useful !!!

P.S.: Sorry if my English is bad, my native language is Dutch ...

double stod(const string &strInput)
{
    /* STOD: String to double  */
    /* Written by Mathias Van Malderen */

    double dbl_one = 0;
    double dbl_two = 0;
    double dbl_final = 0;
    int strlen;
    bool dec_pt = false;
    int nums_before_dec = 0;
    int nums_after_dec = 0;

    strlen = strInput.length();

    /* Check whether the string can be transformed into a number */
    if(strInput[0] == '0' && strInput[1] == '0')
    {
        // invalid number !
        return 0;
    }
    for(int i = 0; i < strlen; i++)
    {
        if(strInput[i] == '0' || strInput[i] == '1' || strInput[i] == '2' || strInput[i] == '3' || strInput[i] == '4' || strInput[i] == '5' || strInput[i] == '6' || strInput[i] == '7' || strInput[i] == '8' || strInput[i] == '9')
        {
            // valid number
        } else if(strInput[i] == '.'){
            if(dec_pt)
            {
                // there was already a decimal point counted
                // invalid number !
                return 0;
            } else {
                dec_pt = true; // increment by one
            }
        } else {
            // invalid number !
            return 0;
        }
    }

    /* Convert the number */

    // STEP 1: Calculate the amount of numbers before/after the decimal point (if there's one)
    if(dec_pt) // if there's a decimal point in the number
    {
        for(int i = 0; i < strlen; i++)
        {
            if(strInput[i+1] != '.')
            {
                nums_before_dec++;
            } else {
                nums_before_dec++;
                break;
            }
        }
		nums_after_dec = strlen-nums_before_dec;
		nums_after_dec -= 1;
    } else {
		// This piece of code was added later as a BUGFIX !
		// Now the STOD-function is working 100% perfect !!!
		nums_after_dec = 0;
		nums_before_dec = strlen;
    }

    

    // STEP 2: Convert the string to a real number
    for(int i = 0; i < nums_before_dec; i++)
    {
        switch(strInput[i])
        {
            case '0':
                dbl_one += 0 * apow(10, (nums_before_dec - i));
                break;
            case '1':
                dbl_one += 1 * apow(10, (nums_before_dec - i));
                break;
            case '2':
                dbl_one += 2 * apow(10, (nums_before_dec - i));
                break;
            case '3':
                dbl_one += 3 * apow(10, (nums_before_dec - i));
                break;
            case '4':
                dbl_one += 4 * apow(10, (nums_before_dec - i));
                break;
            case '5':
                dbl_one += 5 * apow(10, (nums_before_dec - i));
                break;
            case '6':
                dbl_one += 6 * apow(10, (nums_before_dec - i));
                break;
            case '7':
                dbl_one += 7 * apow(10, (nums_before_dec - i));
                break;
            case '8':
                dbl_one += 8 * apow(10, (nums_before_dec - i));
                break;
            case '9':
                dbl_one += 9 * apow(10, (nums_before_dec - i));
                break;
            default:
                // invalid number !
                return 0;
        }
    }

    dbl_one = dbl_one / 10; // little fix

    for(int i = 0; i < nums_after_dec; i++)
    {
        switch(strInput[i + nums_before_dec + 1])
        {
            case '0':
                dbl_two += (0 / apow(10, i+1));
                break;
            case '1':
                dbl_two += (1 / apow(10, i+1));
                break;
            case '2':
                dbl_two += (2 / apow(10, i+1));
                break;
            case '3':
                dbl_two += (3 / apow(10, i+1));
                break;
            case '4':
                dbl_two += (4 / apow(10, i+1));
                break;
            case '5':
                dbl_two += (5 / apow(10, i+1));
                break;
            case '6':
                dbl_two += (6 / apow(10, i+1));
                break;
            case '7':
                dbl_two += (7 / apow(10, i+1));
                break;
            case '8':
                dbl_two += (8 / apow(10, i+1));
                break;
            case '9':
                dbl_two += (9 / apow(10, i+1));
                break;
            default:
                // invalid number !
                return 0;
        }
    }

    // STEP 3: Return the converted string as a double:
    dbl_final = dbl_one + dbl_two;
    return dbl_final;
}

/* This function 'apow' raises x to the power of y, it's a dependency of 'stod' */
double apow(const float &x, int y)
{
    double result = 1;
    if(y == 0)
        return result;

    if(y < 0)
    {
        y = -y;
        for(int i = 0; i < y; i++)
            result = result * x;
        return 1/result;
    }

    for(int i = 0; i < y; i++)
        result = result * x;

    return result;
}
tux4life 2,072 Postaholic

I know this can also be achieved using string streams (in a few lines of code), but my purpose was to do it without ...
I just tried to avoid as much standard C++ functions as I could ...
Off course this was only to test my programming skills and I know some of you are maybe saying that I'm reinventing the wheel, but it was only a test ...

William Hemsworth 1,339 Posting Virtuoso

Or simply use the atof function :) but I see nothing wrong in reinventing the wheel too.

Lines 71 to 106 can be changed to:

if ( isdigit(strInput[i]) ) {
  dbl_one += (strInput[i] - '0') * apow(10, (nums_before_dec - i));
} else {
  return 0;
}

Nice snippet.

IanYates 0 Newbie Poster

Hey tux4life,

to reiterate William's comment, remember that chars (in single quotes) are just numbers, so you don't need big if's and switches to determine them.

To know if a char's a number, try something like:

if (chr >= '0' && chr <= '9')
{
    cout << "It's a number!";
}

So, as William said, if you do "chr - '0'" you'll get the actual numeric value of the char.

Reinventing the wheel is a fine way to think about what the standard functions do - as opposed to assuming they're magically and don't cost anything ;)

tux4life 2,072 Postaholic

That's why I like this forum: You post your code, people give their opinion (+suggestions) about your code, you can make your code better/more efficient/shorter, and everyone has profit ...

Thank you for your replies !
I have learnt some useful things, I'll consider changing my code (bearing your suggestions in mind) ...

BTW: Where do I have to post my changed code ?

William Hemsworth 1,339 Posting Virtuoso

As far as I know, you can't edit a snippet.
You will just have to post another snippet with the adjustments if you want to.

tux4life 2,072 Postaholic

Yeah, surely I want to post the updated code, it's only a matter of time ...

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.