2015-04-27 62 views
8

比方說,我有兩個對象if各自類型IF。我知道std::is_integral<I>::value爲真,並且std::is_floating_point<F>::value爲真。符合標準的方法來比較float到積分?

是否有完全符合標準的方法來確定i的值是否小於值f?注意強調'完全符合標準',對於這個問題,我只對那些由C++標準提供保證的答案感興趣。


瑣碎實現i < I(f)不起作用,因爲f值可能不適合內部i。由於f的精度可能不足以代表i,導致i四捨五入到等於f的值(如果您有IEEE754浮點數,16777219 < 16777220.f失敗),所以微不足道的實現F(i) < f也不起作用。

但是,真正的困境是:如果您想用std::numeric_limits::max來緩解這些問題,那麼您可以回到比較浮點數和整數的原始問題!這是因爲std::numeric_limits::max的類型等於原始類型。

+0

「對於這個問題,我只是在被從C++標準保證備份的答案感興趣」是不合理的,傻這個問題的要求。這類似於要求實現冒泡排序的方式,並且要求由C++標準來備份答案。 C++標準對泡沫排序沒有什麼可說的。 –

+0

'我 Barry

+3

@ Cheersandhth.-Alf我不同意。問題的關鍵在於找到一種在任何C++實現上都有明確定義的方法。你可以做到這一點泡沫排序,但我不確定你可以進行這種比較,因此我的問題。 – orlp

回答

0

這是我會怎麼做:

我假定f是有限的,無限大和NaN的情況是在其他地方處理。

  1. 比較F和F(I),如果不相等,就大功告成了,f和我要麼<或>

  2. 如果相等

    ,然後比較I(f)和我

唯一的假設是:

  • 如果存在具有完全相同的值i浮點數,則F(I)給出v ALUE

  • 是否存在具有完全相同的值爲f的整數,則I(f)給出的函數F值

  • 單調性和我

EDIT

爲了更加明確,上面的技巧用於編寫比較函數,而不僅僅是測試相等...

floatType F(intType i); 
intType I(floatType f); 
int cmpfi(floatType f,intType i) 
{ 
    assert(isfinite(f)); 
    if(f < F(i)) return -1; 
    if(f == F(i)) 
    { 
    if(I(f) < i) return -1; 
    return I(f) > i; 
    } 
    return 1; 
} 

你來如果fI範圍之外這個草案轉換成C++代碼,可以處理多種不同floatType/IntType上

+1

我正在尋找一個排序測試,而不是平等。 – orlp

+0

@orlp,我沒有詳細說明答案,但這些提示是爲了寫一種cmp函數 –

+1

好吧,在第1步中,在發現f!= i後,你說「你完成了」。這顯然不解決問題:) – orlp

2
  1. ,你可以通過它的標誌告訴結果。

  2. 如果fI的範圍內,但太大而不能有小數部分,請將其作爲整數進行比較。

  3. 否則,它是安全的投iF因爲四捨五入不會改變比較的結果是:f已經比將四捨五入的I任何值。

template< typename I, typename F > 
std::enable_if_t< std::is_integral_v<I> && std::is_floating_point_v<F>, 
bool > less(I i, F f) { 
    // Return early for operands of different signs. 
    if (i < 0 != f < 0) return i < 0; 

    bool rev = i >= 0; 
    if (rev) { 
     f = - f; // Make both operands non-positive. 
     i = - i; // (Negativity avoids integer overflow here.) 
    } 

    if (f < /* (F) */ std::numeric_limits<I>::min()) { 
     // |i| < |f| because f is outside the range of I. 
     return rev; 
    } 
    if (f * std::numeric_limits<F>::epsilon() <= -1) { 
     // f must be an integer (in I) because of limited precision in F. 
     I fi = f; 
     return rev? fi < i : i < fi; 
    } 
    // |f| has better than integer precision. 
    // If (F) |i| loses precision, it will still be greater than |f|. 
    return rev? f < i : i < f; 
} 

演示:http://coliru.stacked-crooked.com/a/b5c4bea14bc09ee7

+0

...呃,這個代碼只適用於* signed *整數。您可以通過刪除所有符號業務來爲無符號整數添加重載。 – Potatoswatter