I have a double which is not necessarily positive but usually. It can be 0.xxxx000 or X.xxxx00000 or XX.00000 or 0.xxx0xxx00000, where eventually there are all 0's to the right of the last number. I need to keep track of how many digits there are. I've been having trouble with this, any help? This is C.
-
what have you tried? can you do something where you count # of zeroes from each end of the double in string form and then figure out the difference between the two iterators to get your count? – Anon Mar 28 '11 at 13:15
-
I've tried loops where I try to divide off each digit until only 0.0000000000.. remains but it never seemed to compare to 0.000000... correctly and never stopped. I then tried from the other direction where I subtracted and multiplied the number until the subtraction hit 0, but plenty of edge cases break that – cdietschrun Mar 28 '11 at 13:28
-
2How many digits are there in the result of 1.0 / 3? It is the same for any double calculation. *You* pick the number of digits. – Hans Passant Mar 28 '11 at 13:37
3 Answers
A double has 52 mantissa bits plus an implicit "1" bit, so you should be able to type-pun a double pointer to a 64-bit integer (getting the raw bits into an integer), &= this with (1<<52)-1, and |= the result with (1<<52).
The log10 of that would be the number of decimal digits.
Though, I'm almost inclined to say "go with jonsca's solution" because it is so ingeniously simple (it deserves a +1 in any case for being KISS).

- 67,688
- 20
- 135
- 185
-
-
"The log10 of that would be the number of decimal digits." No! It would not. Consider the example: 1+1/2^52. How many decimal digits? The right answer is 52. But log10(2^52+1) is much less than that. – Serge Dundich Mar 28 '11 at 14:31
-
The base-N logarithm of _any number_ is the number of digits counting in base-N. Or, more precisely, one should say ceil(log-N), because obviously there are no "fractional digits" (if you calculate 4.1 digits, that's 5). Your example of 1+1/2^52 does not apply, since that number is not properly representable in double precision at all. Also, IEEE 754 double is well-known to have 16 significant decimals (or less), your figure of 52 cannot be right by any means. – Damon Mar 28 '11 at 14:52
-
"The base-N logarithm of any number is the number of digits counting in base-N." True. But what makes you think that number of decimal digits in the number calculated with your method equals the number of decimal digits after point before all-zeroes in decimal representation of that double value? In fact those values are almost completely unrelated. – Serge Dundich Mar 29 '11 at 07:24
-
"Your example of 1+1/2^52 does not apply, since that number is not properly representable in double precision at all." Not true. You have 52 floating point bits of the significand plus implicit 1 before them. The type-punned 64-bit hexadecimal representation of 1+1/2^52 double number is 3ff0000000000001 [(look here)](http://babbage.cs.qc.cuny.edu/IEEE-754/64bit.html). 1+1/2^52 is the most soft example. For any double number your method always produces number in range from 2^52 to 2^53-1 and number of decimal digits in any of those numbers is 16. – Serge Dundich Apr 01 '11 at 09:40
-
We may take 1.5 = 1+1/2. Your method produces number 0x18000000000000 and its log10 is 16 (as always) which is not related to 1.5 in any way (it is just maximum decimal precision of double). – Serge Dundich Apr 01 '11 at 09:43
-
2Sigh... ok, I'll try one last time: 1/2^52 = 0.00000000000000022204460492503131. (double)(0.00000000000000022204460492503131) = 0.00000000000000022204, and (double)(1.0 + 0.00000000000000022204460492503131) = 1.0000000000000002. IEEE 754 double can represent 15.955 (+ 1) decimal digits, no more. It does not matter how many digits may or may not, even in theory, come after that. They simply aren't there, double does not have them. Anything between 1.0000000000000002 and 1.0000000000000003 is the same number. – Damon Apr 01 '11 at 14:24
Use sprintf to turn it into a string and do whatever counting/testing you need to do on the digits

- 10,218
- 26
- 54
- 62
-
1sprintf will convert only at most some default number of digits that may be overridden by precision parameter of the format specifier. E.g. `sprintf(s,"%.7f",x);` - will convert up to 7 digits after '.'. So using sprintf is definitely not a solution. – Serge Dundich Mar 28 '11 at 13:22
-
Good point, I was thinking that there were some possible precision problems. – jonsca Mar 28 '11 at 13:23
-
@Serge Dundich: then why not `sprintf( s, "%.50f", x);`? Granted, the question isn't entirely clear (especially given the base 2 vs. base 10 problem you describe so well), but jonsca's answer may be what the asker is looking for. – tomlogic Mar 28 '11 at 15:30
-
@tomlogic: `sprintf( s, "%.52f", x )` may be OK if sprintf implementation is perfect (that is more than likely not true). Anyway 52 is some strange magic number that is correct only for the specific double format that is not mandatory by C standard. – Serge Dundich Mar 29 '11 at 07:59
The representation of the double is not decimal - it is binary (like all the other numbers in a computer). The problem you defined makes little sense really. Consider the example: number 1.2 is converted to binary - 1+1/5 = 1.(0011) binary [0011 in period]. If you cut it to 52 bits of precision (double) - you'll have 1.0011001100110011001100110011001100110011001100110011 binary that equals 1+(1-1/2^52)/5. If you represent this number in decimal form precisely you will get 52 decimals before all-zeroes that is a lot more than the maximum decimal precision of a double that is 16 digits (and all those digits of representation from 17 to 52 are just meaningless).
Anyway if you have purely abstract problem (like in school):
int f( double x )
{
int n = 0;
x = fabs(x);
x -= floor(x);
while( x != floor(x) )
{
x *= 2;
++n;
}
return n;
}
The function returns number of binary digits before all-zeroes and it is also the number of decimal digits before all-zeroes (the last decimal digit is always 5 if returned value > 0).

- 4,221
- 2
- 21
- 16