2017-07-31 73 views
0

我在使用浮點數分隔long類型時遇到了精度問題,並最終導致應用程序中的計算出現混亂。假設我只是將毫秒轉換爲秒,因爲這是我們結束的要求。以下是一個樣本測試用例目的C--用浮點數除長而不丟失精度

long startTimeMS = 2529095; 
NSTimeInterval expectedStartTime = 2529.095 
NSTimeInterval startTime = startTimeMS/1000.f; //Results to "2529.09497" 
double startTimeDouble = startTimeMS/1000.0 // Results to "2529.0949999999998" 

XTCAssert(startTime == expectedStartTime, @"Invalid start time") 

在劃分長時間浮點數時,它將精度減少了3,000分之一。類似於長時間除以雙。

我該如何做到這一點,以便它與預期的開始時間相同?我猜在小數四捨五入到最接近的千分之一也將是不錯,但我發現這裏的四捨五入方法是不可靠的或者類似這樣的

float roundToTwo(float num) 
{ 
    return round(100 * num)/100; 
} 

其中最有可能返回相同的值

+1

你確定你的例子嗎?導致「2595.09497」的'2529095/100.f'看起來像是一個巨大的錯誤。 –

+0

爲什麼你想要時間使用浮動而不是整數有什麼原因嗎? (您可以將時間轉換爲雙打以供後期顯示)。 –

+0

@MarkDickinson我在回答第一次計算時,「長」到「浮點」轉換失去了精度,但這並不能解釋第二個結果。 –

回答

1

您誤解了浮點運算。浮點類型floatdouble二進制類型。

您的小數點後0.095等於9/100 + 5/1000 - 所有小數點後的部分爲1/(10^n)的小數點之和。

現在考慮普通分數,什麼是1/3的小數部分相當於?這是3/10 + 3/100 + 3/1000 + ...或等效0.333...,有沒有確切的方式來表示它爲十進制小數的相同。

對於類型floatdouble小數部分是1/(2^n)分數的總和。與上述類似,不是所有的小數可以精確地寫成二進制分數。

除了通過使用不同的鹼,十進制與二進制,計算機浮點在的位數是有限的,任意數量的同時真正的數學是無限的,並且因此計算可能不會產生確切結果誘導的差異。

由於上述原因,不要測試精確的相等性,而是兩個數的差值是否小於一個小數值(可能取決於數值的大小),這是很好的浮點實踐。在你的情況下,如果兩個數字的差值小於0.1毫秒,你可能會認爲兩個數字「相等」。

現在說了這麼多,在你給,如果是糾正的具體實例中,數字實際上是相同的,但也不是2529.095

long startTimeMS = 2529095; 
NSTimeInterval expectedStartTime = 2529.095;  // Result is approx "2529.0949999999998" 
NSTimeInterval startTime = startTimeMS/1000.0; // Result is approx "2529.0949999999998" 

這兩個數字會比較平等,但這種需要不是所有價值的情況。這將是更好地寫你的斷言是:

XTCAssert(fabs(startTime - expectedStartTime) <= 0.0001, @"Invalid start time"); 

其中0.0001應該是什麼幾分之一秒是足夠小,你認爲兩個值「相等」。

如果你打算要做精確的工作,你應該真正閱讀浮點算法,因爲你做了更多的操作,由於基數和有限數字的差異而累積,並且有技巧來最小化和處理這些。

HTH

+0

將此作爲使用double和epsilon的正確答案,因爲這是我可以接受的最接近的答案 –

0

你不應該」對此操作使用浮點數 - 因爲浮點數的基數10表示小數總是產生不均勻的數字。一個更好的解決方案是使用定點算術並將所有東西都乘以1000(如果需要更多小數精度,則更多)。這可以避免浮點計算中固有的舍入誤差。

請參見:

https://softwareengineering.stackexchange.com/questions/101163/what-causes-floating-point-rounding-errors

對於是什麼原因導致這些錯誤一個更好的答案。

+0

我正在處理NSTimeInterval,它是double類型的。我需要它將其轉換爲double/float以包含毫秒信息 –

+0

以定點(整數)數學形式做數學運算,然後在最後轉換爲double。這樣可以避免使用浮點數的舍入誤差累積。 – Alexp