[英]Properly subtracting float values
我正在嘗試創建一個值數組。 這些值應為“ 2.4,1.6,.8,0”。 我在每一步都減去0.8。
這就是我的做法(代碼段):
float mean = [[_scalesDictionary objectForKey:@"M1"] floatValue]; //3.2f
float sD = [[_scalesDictionary objectForKey:@"SD1"] floatValue]; //0.8f
nextRegion = mean;
hitWall = NO;
NSMutableArray *minusRegion = [NSMutableArray array];
while (!hitWall) {
nextRegion -= sD;
if(nextRegion<0.0f){
nextRegion = 0.0f;
hitWall = YES;
}
[minusRegion addObject:[NSNumber numberWithFloat:nextRegion]];
}
我得到以下輸出:
minusRegion = (
"2.4",
"1.6",
"0.8000001",
"1.192093e-07",
0
)
我不想在0.8和0之間的數字小得令人難以置信。是否有標准方法來截斷這些值?
3.2和.8都不能完全表示為32位浮點數。 最接近3.2的可表示數字是3.2000000476837158203125(以十六進制浮點數表示,0x1.99999ap + 1)。 最接近.8的可表示數字是0.800000011920928955078125(0x1.99999ap-1)。
從3.2000000476837158203125中減去0.800000011920928955078125后,精確的數學結果為2.400000035762786865234375(0x1.3333338p + 1)。 此結果也不能完全表示為32位浮點數。 (您很容易在十六進制浮點數中看到這一點。32位浮點數的有效位數為24位。“ 1.3333338”在“ 1”中具有一位,在中間六位為24位,而在“ 8”。)因此,將結果四舍五入到最接近的32位浮點數,即2.400000095367431640625(0x1.333334p + 1)。
從中減去0.800000011920928955078125得到1.6000001430511474609375(0x1.99999cp + 0),這是可以精確表示的。 (“ 1”是一位,五個九是20位,“ c”有兩個有效位。“ c”中的低兩位是尾隨零,可以忽略。所以有23個有效位)
從中減去0.800000011920928955078125得出0.800000131130218505859375(0x1.99999ep-1),這也可以精確表示。
最后,從中減去0.800000011920928955078125得到1.1920928955078125e-07(0x1p-23)。
這里要學習的教訓是,浮點數並不代表所有數字,它會將結果四舍五入,以便為您提供可以代表的最接近的數字。 在編寫使用浮點算術的軟件時,您必須了解並允許這些舍入運算。 一種允許這樣做的方法是使用您知道的可以表示的數字。 其他人建議使用整數算法。 另一個選擇是使用大多數您知道可以精確地以浮點表示的值,其中包括不超過2 24的整數。 因此,您可以從32開始並減去8,得出24,然后是16,然后是8,然后是0。這些將是您用於循環控制和繼續計算而沒有錯誤的中間值。 當您准備好交付結果時,可以除以10,得出3.2、2.4、1.6,.8和0(准確)附近的數字。 這樣,您的算術運算法則只會在每個結果中引入一個舍入誤差,而不是在每次迭代之間累積舍入誤差。
這樣做的另一種方法是將減法得到的數字乘以10,然后轉換為整數,然后將該整數除以10.0。
您可以使用下限功能(floorf)輕松完成此操作,如下所示:
float newValue = floorf(oldVlaue * 10)/ 10;
您正在查看良好的舊浮點舍入錯誤。 幸運的是,您的情況應該很容易處理。 只需夾緊:
if( val < increment ){
val = 0.0;
}
不過,正如Eric Postpischil所說明的那樣 :
用這種方式進行鉗位不是一個好主意,因為有時舍入會導致迭代變量比增量略小而不是增量,並且這種鉗位將有效地跳過迭代。 例如,如果初始值為3.6f(而不是3.2f),步長為.9f(而不是.8f),則每次迭代中的值都將略低於3.6、2.7、1.8和.9。 到那時,鉗位會將值略低於.9的值轉換為零,並且跳過迭代。
因此,進行比較時可能需要減去少量。
您應該考慮的一個更好的選擇是使用整數而不是浮點數進行計算,然后再進行轉換。
int increment = 8;
int val = 32;
while( val > 0 ){
val -= increment;
float new_float_val = val / 10.0;
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.