1

I'm running this code on my iPhone:

double d = DBL_MAX;
NSString *s = [NSString stringWithFormat:@"%.0f", d];
double dp = atof([s cStringUsingEncoding:[NSString defaultCStringEncoding]]);
NSString *pe = d == dp ? @"YES" : @"NO";

double one = 1;
double dpd = dp / one;
NSString *de = d == dpd ? @"YES" : @"NO";

NSLog(@"### Parsed are equal: %@, divided are equal: %@", pe, de);
NSLog(@"D   : %.0f", d);
NSLog(@"DP  : %.0f", dp);
NSLog(@"DPD : %.0f", dpd);

...and getting this output:

### Parsed are equal: NO, divided are equal: NO
D   : 17976931348623157081452742373170435679807056752584499659891747680315726078002853876058955863276687817154045895351438246423432132688946418276846754670353751698604991057655128207624549009038932894407586850845513394230458323690322294816580855933212334827479
DP  : 17976931348623155723920577891946972866121062246621938439403251722449088432276750723756897307653964877256701669823356283705419341284625019355047863102662518251134787976961389628366367996124520722972986881016593281354069269901878996004952428787693676134400
DPD : 17976931348623155723920577891946972866121062246621938439403251722449088432276750723756897307653964877256701669823356283705419341284625019355047863102662518251134787976961389628366367996124520722972986881016593281354069269901878996004952428787693676134400

Why a sequence of printf()/atof() loses precision (I assume stringWithFormat does printf internally)? It happens not only for DBL_MAX but for every significantly large number (i.e. for 10000 it works as expected, for DBL_MAX / 2 it does not). Is there a way to avoid it?

Sergey Mikhanov
  • 8,880
  • 9
  • 44
  • 54
  • What if you use `-doubleValue` instead of `atof()`? – Richard J. Ross III Mar 12 '12 at 16:40
  • @RichardJ.RossIII: Nothing changed. The output is exactly the same – Sergey Mikhanov Mar 12 '12 at 16:48
  • @sch, after 900719925474091 (2^53-1), there are holes in the integers which are representable exactly in a double. Conserving the input value for a round trip input->output isn't possible. But Sergey does an output followed by an input. It is possible to implement input and output in such a way that that round-trip conserve the value. It is apparently not done. – AProgrammer Mar 12 '12 at 17:28

2 Answers2

2

Not all decimals can be represented in binary. For example 0.2(dec) = 0.001100110011...(bin). Therefore when number is converted from decimal string it's sometimes truncated (or rounded).

When converting from binary to decimal, even though it's always possible, the result sometimes is longer than n*log_10(2), where n is number of binary digits. For example 0.001(bin) = 0.125(dec), but 3*log_10(2)=0.903... Therefore when number is converted from binary to digital string, it's sometimes truncated as well.

That's the reason why you get result that slightly differs.

Here is an example. Suppose your mantissa is 6 digit. Let's convert the number 0.001111(bin) to decimal. The precise result is 0.234375, but this number is rounded to 0.23 because you need only 6*log_10(2)=1.8061 digits to represent any 6-digit binary. In this case 1.8061 is even rounded up to 2.

Now lets see what we will get if we convert our 0.23 back to binary. It's 0.0011101011... This has to be rounded and result could be 0.001110 or 0.001111 depending on the way rounding is done.

1

"Significant", well double have 53 bits of precision, that's between 15 and 16 decimal digits, you have a difference at the 17th one (but the first digit is a 1).

My guess (I've not checked it) is that the difference is only in the less significant bit of the double, so it is a rounding problem in either the output or the input routine. I don't know if objective C asks for correct result in that case (correct results mandate the use of multiprecision arithmetic), I know that C implementation varies.

AProgrammer
  • 51,233
  • 8
  • 91
  • 143