DBL_MAX теряет значительную часть своей точности после повторного анализа из строки - PullRequest
1 голос
/ 12 марта 2012

Я запускаю этот код на своем 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);

... и получаю этот вывод:

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

Почему последовательность printf() / atof()теряет точность (я полагаю, stringWithFormat внутренне printf)?Это происходит не только для DBL_MAX, но и для каждого значительно большего числа (т. Е. Для 10000 это работает, как ожидается, для DBL_MAX / 2 - нет).Есть ли способ избежать этого?

Ответы [ 2 ]

2 голосов
/ 13 марта 2012

Не все десятичные дроби могут быть представлены в двоичном виде. Например, 0.2 (dec) = 0.001100110011 ... (bin). Поэтому, когда число преобразуется из десятичной строки, оно иногда усекается (или округляется).

При преобразовании из двоичного в десятичное, даже если это всегда возможно, результат иногда длиннее, чем n * log_10 (2), где n - количество двоичных цифр. Например, 0,001 (bin) = 0,125 (dec), но 3 * log_10 (2) = 0,903 ... Поэтому, когда число преобразуется из двоичной в цифровую строку, оно иногда также усекается.

Это причина, по которой вы получаете результат, который немного отличается.

Вот пример. Предположим, ваша мантисса состоит из 6 цифр. Давайте преобразуем число 0.001111 (bin) в десятичное. Точный результат равен 0,234375, но это число округляется до 0,23, потому что вам нужно только 6 * log_10 (2) = 1,8061 цифр для представления любого 6-значного двоичного файла. В этом случае 1.8061 округляется до 2.

Теперь давайте посмотрим, что мы получим, если мы переведем наш 0.23 обратно в двоичный файл. Это 0.0011101011 ... Это должно быть округлено, и результат может быть 0,001110 или 0,001111 в зависимости от способа округления.

1 голос
/ 12 марта 2012

«Значительный», хорошо двойной, с 53 битами точности, то есть между 15 и 16 десятичными цифрами, у вас есть разница с 17-й (но первая цифра - 1).

Мое предположение (я не проверял это) состоит в том, что разница заключается только в менее значимом бите двойного, поэтому это проблема округления либо в выходных данных, либо в подпрограмме ввода. Я не знаю, запрашивает ли цель C правильный результат в этом случае (правильные результаты требуют использования многоточной арифметики), я знаю, что реализация C варьируется.

...