Reputation: 10519
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
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
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
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 int
s back and you'll see :)
EDIT: a better strategy than using ceil
s (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
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