Guillaume Paris
Guillaume Paris

Reputation: 10519

count the # of decimal digits after the radix point

I would like to count the number of decimal digits after the radix point of a floating point number. The problem obviously raise when the real number doesn't have a representation in the binary system, like 3.5689113.

I am wondering - if for example someone write this real in a source code - if it is possible to get the number 7 namely the number of digits after the radix point

the naive following code for example doesn't work :

int main()
{  
    double num = 3.5689113;

    int count = 0;
    num = abs(num);
    num = num - int(num);

    while ( abs(num) >
        0.0000001 )
    {
        num = num * 10;
        count = count + 1;
        num = num - int(num);
    }

    std::cout << count; //48
    std::cin.ignore();
}

Upvotes: 0

Views: 2292

Answers (4)

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 154035

For a floating point type T you can get up to std::numeric_limits<T>::digits10 digits restored exactly. Thus, to determine the position of the last non-zero fractional digits you'd use this value as a precision and format the number. To avoid the output using exponent notation you need to set the formatting flags to std::ios_base::fixed and account for the number of non-fractional digits:

std::ostringstream out;
int non_fraction(std::abs(value) < std::numeric_limits<double>::epsilon()
                 ? 1: (1 + std::log(std::abs(value)) / std::log(10)));
out << std::setprecision(std::numeric_limits<double>::digits10 - non_fraction)
    << std::fixed
    << value;

If there is a decimal point, you just need to count the number of digits up to the trailing sequence of zeros.

Upvotes: 1

Mark Ransom
Mark Ransom

Reputation: 308530

To prevent the errors introduced by floating point approximation, convert the number to an integer at the earliest possible opportunity and work with that.

double num = 3.5689113;

int count = 7;  // a maximum of 7 places
num = abs(num);
int remainder = int(0.5 + 10000000 * (num - int(num)));

while ( remainder % 10 == 0 )
{
    remainder = remainder / 10;
    --count;
}

Upvotes: 3

alestanis
alestanis

Reputation: 21863

When something like that doesn't work, you try to print the numbers.

I did so here, and I found you had some floating number precision issues. I changed the int rounding to ceil rounding and it worked like a charm.

Try putting the ints back and you'll see :)

EDIT: a better strategy than using ceils (which can give the same rounding problems) is to just round the numbers to the nearest integer. You can do that with floor(myNumber+0.5).

Here's the modified code

int main()
{  
    double num = 3.56891132326923333;

    // Limit to 7 digits
    num  = floor(num*10000000 + 0.5)/10000000;

    int count = 0;
    num = abs(num);
    num = num - floor(num+0.5);

    while ( abs(num) >
        0.0000001 )
    {
        cout << num << endl;
        num = num * 10;
        count = count + 1;
        num = num - floor(num+0.5);
    }

    std::cout << count; //48
    std::cin.ignore();

    return 0;
}

Upvotes: 3

evanmcdonnal
evanmcdonnal

Reputation: 48134

I would recommend converting to a string, then looping over it and counting how many chars occur after you hit the period. Below is a sample (may need some minor tinkering, been awhile since I've done this in C++);

bool passedRadix = false
int i = 0; // for counting decimals
std::ostringstream strs;
strs << dbl; // dbl is 3.415 or whatever you're counting
std::string str = strs.str();

for(char& c : str) {
   if (passedRadix == true)
       i++; 
   if (c == '.')
       passedRadix = true;

}

Upvotes: 0

Related Questions