我試圖避免比較浮點類型的epsilon比較。我可以拿出最好的解決方案應用於ULPS(單位在最後的地方)的區別,雖然this article不得不使用整數表示一個更好的解決方案(///
表明我自己的看法):使用別名與整數表示和ULP正確比較雙打
/* See
https://randomascii.wordpress.com/2012/01/11/tricks-with-the-floating-point-format/
for the potential portability problems with the union and bit-fields below.
*/
#include <stdint.h> // For int32_t, etc.
union Float_t
{
Float_t(float num = 0.0f) : f(num) {}
// Portable extraction of components.
bool Negative() const { return i < 0; }
int32_t RawMantissa() const { return i & ((1 << 23) - 1); }
int32_t RawExponent() const { return (i >> 23) & 0xFF; }
int32_t i; /// Perhaps overflow when using doubles?
float f;
#ifdef _DEBUG
struct
{ // Bitfields for exploration. Do not use in production code.
uint32_t mantissa : 23; /// 52 for double?
uint32_t exponent : 8; /// 11 for double?
uint32_t sign : 1;
} parts;
#endif
};
bool AlmostEqualUlps(float A, float B, int maxUlpsDiff)
{
Float_t uA(A);
Float_t uB(B);
// Different signs means they do not match.
if (uA.Negative() != uB.Negative())
{
// Check for equality to make sure +0==-0
if (A == B)
return true;
return false;
}
// Find the difference in ULPs.
int ulpsDiff = abs(uA.i - uB.i);
if (ulpsDiff <= maxUlpsDiff)
return true;
return false;
}
不過,我可以似乎不會以支持雙打的方式重新格式化代碼。我甚至讀到了解釋,found here。
有誰知道什麼是解決這個問題的最好方法?
在任何人決定,以紀念這是一個重複:不這樣做,因爲只有相似的問題是爲那些JavaScript和C++的回答是:
bool IsAlmostEqual(double A, double B)
{
//http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
long long aInt = reinterpret_cast<long long&>(A);
if (aInt < 0) aInt = -9223372036854775808LL - aInt;
long long bInt = reinterpret_cast<long long&>(B);
if (bInt < 0) bInt = -9223372036854775808LL - bInt;
return (std::abs(aInt - bInt) <= 10000);
}
哪個沒有按不使用ULP,但有一些綁定,我不確定什麼-9223372036854775808LL - aInt
是什麼(可能在int64溢出)。
我建議你嘗試在你的評論中提到的修改,它們看起來合乎邏輯。讓我們看看它出錯的地方,並嘗試修復它。 –
@ A.S.H應用我的評論,我得到錯誤:'錯誤C2034'double_t :: mantissa':位字段的類型對於位數太小。因此,我將尾數設置爲'uint64_t',並且一切順利,但符號不正確地爲'1',而我將1.0與1.0進行比較。 '1.0'的十六進制值似乎是正確的:'0x3ff0000000000000',但它由指數保存?所以我把尾數和指數設置爲'uint64_t',它似乎工作。我還錯過了什麼嗎? – Nikita
它們都應該是uint64_t,因爲它們表示64位「double」的位域。我想你也改變了'f'和'i'的類型分別爲double和int64_t,'RawMantissa'和'RawExponent'等的差別等。 –