2012-03-12 2 views
1

Я выполняющей этот код на моем iPhone:DBL_MAX теряет значительную часть своей точности после повторного разобран из строки

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 это не так). Есть ли способ избежать этого?

+0

Что делать, если вы используете '-doubleValue' вместо' atof() '? –

+0

@ RichardJ.RossIII: Ничего не изменилось. Вывод точно такой же: –

+0

@sch, после 900719925474091 (2^53-1), в целых числах есть отверстия, которые представляются точно в двойном. Сохранение входного значения для выхода с обратной связью -> выход невозможно. Но Сергей делает вывод, за которым следует вход. Можно реализовать ввод и вывод таким образом, чтобы этот «круглый стол» сохранял значение. По-видимому, это не сделано. – AProgrammer

ответ

2

Не все десятичные знаки могут быть представлены в двоичном формате. Например, 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

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

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

Смежные вопросы