簡體   English   中英

C思維:浮點數與整數和浮點數表示形式

[英]C thinking : float vs. integers and float representation

在C語言(和許多其他語言)中使用整數時,除精度外,必須注意一個問題。 最好在除法之前將事物相乘並相加(從而產生更大的中間結果,只要它不會溢出)。

但是花車呢? 那還成立嗎? 還是以這樣一種方式來表示:最好將數量級相近的數量相除,而不是數量級較小的數量級?

浮點數/雙精度數和類似的浮點數表示法是針對保留有效數字 (也稱為“精度”),而不是固定的小數位數 ,例如定點數或整數運算。

最好避免組合數量,這些數量可能導致指數的隱式不足或溢出,即在浮點數范圍的極限處。

因此,應避免對數量相差很大(明顯地或由於具有相反符號的數量)進行加/減,並在可能的情況下重新安排,以避免這種眾所周知的精度下降途徑。

示例:最好重構/重新排序

small + big + small + big + small * big

(small+small+small) + big + big

因為小個體可能對大個體沒有影響,因此它們的貢獻可能會消失。

如果任何數量的低位存在任何“噪聲”或不精確度,明智的做法是知道有效位的丟失如何通過計算傳播。

使用整數:
只要沒有溢出, +,-,*始終是精確的。
通過除法,結果將被截斷,並且通常不等於數學答案。
ia,ib,ic ,在除ia*ib/icia*(ib/ic)之前相乘更好,因為商是基於乘積ia*ib位數多於ib

帶浮點數:
問題是微妙的。 同樣,只要不發生上溢/下溢,順序或*,/序列所產生的影響將小於整數。 FP */-類似於添加/減去日志。 典型結果在數學上正確答案的0.5 ULP之內。

使用FP和+,-如果1)值的幅度相差較大或2)減去幾乎相等的值且先前計算中的誤差現在變為fa,fb,fc的結果可能與數學正確的結果有顯着差異。重大。

考慮二次方程:

double d = sqrt(b*b - 4*a/c);  // assume b*b - 4*a/c >= 0
double root1 = (-b + d)/(2*a);
double root2 = (-b - d)/(2*a);

double d = sqrt(b*b - 4*a/c);  // assume b*b - 4*a/c >= 0
double root1 = (b < 0) ? (-b + d)/(2*a)  :  (-b - d)/(2*a)
double root2 = c/(a*root1);  // assume a*root1 != 0

當一個根接近0且|b|時,第二根具有更好的root2精度結果|b| 接近d 這是因為b,d減法消除了許多有效位,從而使d的計算誤差變得顯着。


(對於整數)總是最好在相除之前對它們進行相乘和相加(從而創建更大的中間結果,只要它不會溢出)。

仍然保持(對於浮動)嗎?

一般來說,答案是否定的

構造一個簡單的示例,其中在除法之前添加所有輸入會給您帶來巨大的舍入誤差。

假設您要添加10000000000值並將它們除以1000。進一步假定每個值均為1。因此,預期結果為10000000。

方法1但是,如果在除法之前添加所有值,則將獲得結果16777.216(對於32位浮點數)。 如您所見,它已經關閉了。

方法2那么在將每個值加到結果上之前,將每個值除以1000更好嗎? 如果這樣做,您將得到結果32768.0(對於32位浮點數)。 如您所見,它幾乎也處於關閉狀態。

方法3但是,如果繼續添加值,直到臨時結果大於1000000,然后將臨時結果除以1000,然后將中間結果添加到最終結果中,然后重復該操作,直到添加總計10000000000的值,您將得到正確的結果。

因此,在處理浮點時,沒有簡單的“總是在除法前添加”或“總是在除法前添加”。 通常,將操作數保持在相似的大小通常是一個好主意。 這就是第三個示例所做的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM