2

I wrote the following code for converting double to string.I was not supposed to use sprintf or ostream . The output is quite erratic.

The list of input with corresponding output :

  • 2.0 2.0
  • 2.5 2.5
  • -2.0 -2.0
  • 2.987 2.9879947598364142621957397469375
  • -2.987 -2.9879947598364142621957397469375
Where did these extra digits come from and how to overcome this?My code can be found below.
#include <iostream>
#include <math.h>

using namespace std;

string reverse(string input);
string myDtoA(double num);
string itoa(int num);

int main()
{
    double inp=-2.987;
    cout<<myDtoA(inp)<<endl;
}

string myDtoA(double num)
{
    if(num>0)
    {
        int inPart;
        double intPart,fractPart;
        fractPart = modf(num,&intPart);
        inPart=(int)intPart;
        string ret;
        ret = itoa(inPart);
        if(fractPart!=0)
        {
            ret.append(".");
            double ceilOfFraction = ceil(fractPart);
            while(ceilOfFraction !=0)
            {
                double inP,fP;
                fractPart*=10;
                fP=modf(fractPart,&inP);
                int a =(int)inP;
                ret.append(itoa(a));
                fractPart=fP;
                ceilOfFraction = ceil(fractPart);
            }
        }
        else
        {ret.append(".0");}
        return ret;
    }
    else if(num==0)
    {
        return "0";
    }
    else if(num<0)
    {
        string ret = "-";
        ret.append(myDtoA(-num));
        return ret;
    }
}

string itoa(int num)
{
    char* str = new char[120];
    int i=0;
    // Process individual digits
    while (num != 0)
    {
        int rem = num % 10;
        str[i++] = (rem > 9)? (rem-10) + 'a' : rem + '0';
        num = num/10;
    }
    string ret(str);
    return reverse(ret);
}

/* A utility function to reverse a string  */
string reverse(string input)
{
    return std::string(input.rbegin(), input.rend());
}
Abhash Kumar Singh
  • 1,157
  • 2
  • 12
  • 22
  • Extra digits in generally come because the exact value of any (double precision) floating point value 1.xxxxx is (a large) multiple of 2^-53 (or 2^-52 * N, if the value is in between 2 and 4). But because you are using doubles, you should according my educated guess come much closer to 2.987. In fact you are off by almost 0.0009, or 2^-10. – Aki Suihkonen Mar 20 '14 at 19:54
  • possible duplicate of [Why does "dtoa.c" contain so much code?](http://stackoverflow.com/questions/3173056/why-does-dtoa-c-contain-so-much-code) – bmargulies Mar 20 '14 at 20:38

2 Answers2

2

Rounding floating point output is hard.

Here's the most recent paper I found on the subject:

http://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf

In the footnotes, you'll find a reference to:

[Steele Jr. and White(2004)] G. L. Steele Jr. and J. L. White. How to print floating-point numbers accurately (retrospective). In 20 Years of the ACM SIGPLAN Conference on Programming Language Design and Implementation 1979-1999, A Selection, pages 372–374. ACM, 2004. ISBN 1-58113-623-4. doi: 10.1145/989393.989431.

which is a wonderful exposition. No one is going to be able to pick through your program and tell you what to do to it.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
1

The problem is in your implementation of itoa. What happens if the input to itoa is 0?

Your output of -2.9879947598364142621957397469375 for an input of -2.987 should be -2.9870000000000000994759830064140260219573974609375. Notice that the zeros in my result are missing from yours. Those missing zeros are because of that bug in itoa.

Once you get to the point of dealing with single decimal digits, your itoa is complete overkill. It would be better to use an array that maps the integers 0 to 9 to the characters '0' to '9'. (Or you could just use the fact that '0' to '9' are almost certainly contiguous characters on your computer. That hasn't alway been the case, but I can pretty much guarantee that you aren't working with such a beast.)

Even better would be to recognize that the substring starting with 99475983… is completely extraneous. It would be better to print this as -2.9870000000000001, and even better to print it as -2.987.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
  • Are there any languages or systems which don't require digits to be consecutive? Character sets like EBCDIC don't place *letters* consecutively, and a few obscure character sets which aren't used for computing may place zero last rather than first, but I don't know of any programming languages that use such things. – supercat Nov 17 '14 at 01:17