2012-03-12 66 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()序列損失精度(I假設stringWithFormat確實printf內部)?它不僅發生在DBL_MAX上,而且發生在每一個非常大的數字上(即10000它按預期工作,而DBL_MAX/2則沒有)。有沒有辦法避免它?

+0

如果使用'-doubleValue'而不是'atof()'怎麼辦? – 2012-03-12 16:40:53

+0

@ RichardJ.RossIII:沒有任何變化。輸出完全相同 – 2012-03-12 16:48:59

+0

@sch,在900719925474091(2^53-1)之後,整數中有空洞,可以用雙精度表示。保留往返輸入 - >輸出的輸入值是不可能的。但是Sergey做了一個輸出,然後是一個輸入。可以實現輸入和輸出,以便往返保存該值。這顯然沒有完成。 – AProgrammer 2012-03-12 17:28:20

回答

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實現有所不同。