- 有效的方式來比較兩個浮點值。
一個簡單double a,b; if (a == b)
是比較兩個浮點值的有效方法。然而,正如OP注意到的,這可能不符合整體編碼目標。更好的方法取決於比較的上下文,OP沒有提供。見下面。
- 如何向另一個浮動值添加浮動值。例。加入到0.1111 94.4345得到確切的價值94.5456
浮動值作爲源代碼具有無限的有效範圍和精度,如1.23456789e1234567
。將該文本轉換爲double
通常限於不同的值中的一個。選擇最接近的,但可能不完全匹配。
作爲典型的double
,0.1111, 94.4345, 94.5456
都不能代表正好。
OP具有選擇:
1)使用比double, float
等其他類型。各種庫提供十進制浮點類型。
2)限制代碼到罕見的平臺,支持double
到基地10的形式,如FLT_RADIX == 10
。
3)編寫自己的代碼來處理像"0.1111"
這樣的用戶輸入到結構/字符串中並執行所需的操作。
4)將用戶輸入視爲字符串並將其轉換爲某種整數類型,再次使用支持的例程讀取/計算/寫入。
5)接受浮點運算在數學上不精確並處理舍入誤差。
double a = 0.1111;
printf("a: %.*e\n", DBL_DECIMAL_DIG -1 , a);
double b = 94.4345;
printf("b: %.*e\n", DBL_DECIMAL_DIG -1 , b);
double sum = a + b;
printf("sum: %.*e\n", DBL_DECIMAL_DIG -1 , sum);
printf("%.4f\n", sum);
輸出
a: 1.1110000000000000e-01
b: 9.4434500000000000e+01
sum: 9.4545599999999993e+01
94.5456 // Desired textual output based on a rounded `sum` to the nearest 0.0001
更多關於#1
如果確切比較不尋求而是某種「有足夠的兩個值接近?「,需要」足夠接近「的定義 - 其中有很多。
以下「足夠接近」通過檢查這兩個數字的ULP來比較距離。當這些值處於相同的冪乘,並且其他方式變爲對數時,它是線性差異。當然,改變標誌是一個問題。
float
例如:
考慮所有有限float
從最負到最正有序。以下稍微可移植的代碼將爲每個float
返回一個整數,其中的順序爲。
uint32_t sequence_f(float x) {
union {
float f;
uint32_t u32;
} u;
assert(sizeof(float) == sizeof(uint32_t));
u.f = x;
if (u.u32 & 0x80000000) {
u.u32 ^= 0x80000000;
return 0x80000000 - u.u32;
}
return u.u3
}
現在,爲了確定兩個float
是「足夠接近」,簡單的比較兩個整數。
static bool close_enough(float x, float y, uint32_t ULP_delta) {
uint32_t ullx = sequence_f(x);
uint32_t ully = sequence_f(y);
if (ullx > ully) return (ullx - ully) <= ULP_delta;
return (ully - ullx) <= ULP_delta;
}
閱讀[這篇文章](http://stackoverflow.com/questions/588004/is-floating-point-math-broken)。 –
「不應該直接比較兩個浮點值。」如果你的教授這麼說,找一位新教授。他應該說的是從不直接檢查** equal **的兩個浮點值。比較它們以確定一個是大於還是小於另一個是沒有問題的。 – JeremyP
我忘了,他確實說過不應該進行平等檢查。 – AstroMax