2016-04-17 31 views
2

根據我的理解,將舍入方向設置爲+Inf時,將在計算1/3時生成0.333334,如果將其設置爲-Inf,則將生成。從Rust和C++設置FPU舍入方向不會改變

當我在C++中使用fesetround(0x400)fesetround(0x800)來嘗試時,情況並非如此。我得到使用FFI魯斯特相同的行爲叫fsetround從C

C++代碼:

#include <cfenv> 
#include <iostream> 
#include <iomanip> 

using namespace std; 

int main() { 
    double ratio = (double)1/(double)10; 
    fesetround(FE_UPWARD); 
    cout << fegetround() << " upward " << setprecision(18) << ratio << std::endl; 
    fesetround(FE_DOWNWARD); 
    cout << fegetround() << " downward " << setprecision(18) << ratio << std::endl; 
    return 0; 
} 

Pastebin

鏽代碼:

extern crate libc; 

use libc::c_int; 

#[link(name = "rounding")] 
extern { 
    pub static fe_upward: c_int; 
    pub static fe_downward: c_int; 
    fn fesetround(rount: c_int) -> c_int; 
    fn fegetround() -> c_int; 
} 

pub fn upward_round() -> i64 { 
    unsafe { 
     fesetround(fe_upward); 
     fegetround() as i64 
    } 
} 

pub fn downward_round() -> i64 { 
    unsafe { 
     fesetround(fe_downward); 
     fegetround() as i64 
    } 
} 

#[cfg(test)] 
mod tests { 
    use super::*; 
    #[test] 
    fn test_upward() { 
     unsafe { 
      assert_eq!(fe_upward as i64, upward_round()); 
     } 
    } 
    #[test] 
    fn test_downward() { 
     unsafe { 
      assert_eq!(fe_downward as i64, downward_round()); 
     } 
    } 
} 

Pastebin

+0

表現形式爲二進制,所以並不那麼簡單,你的C++程序顯示了兩個舍入模式的最後一個數字的區別,所以它似乎正在工作。 – starblue

+0

對我而言對於兩種表示,C++程序的輸出是:0.1000000 ... 006。我知道浮點表示由於其侷限性而只能表示實數的一個子集,通常實際上1/3是0.33333 ...等等。以浮點形式表示需要四捨五入,當我設置四捨五入到+ inf我期望得到0.333334。 –

+0

我得到'0.100000000000000006'和'0.100000000000000005'爲十分之一,'0.333333333333333315'和'0.333333333333333314'爲三分之一。 – starblue

回答

3

Starblue的評論是正確的,但讓我展開它。

「四捨五入」是指在某些未指定的基礎上用一組有限的數字來近似實數。您的示例1/3 = 0.333333假定四捨五入爲6 十進制數字,即基數爲10.

但是,計算機工作在基數2。二進制1/11是.1010101010101...正如你所看到的,四捨五入有點奇怪。如果你四捨五入到最接近的6位,它將是.101011,如果你舍入到7位它的.1010100 - 最後一位始終與倒數第二位相同,這是因爲這些位交替。

當然,舍入和舍入更簡單。舍入.10101010...簡單地將結果截斷爲N位:0.101010。四捨五入僅僅爲最後一位增加了1。

現在您可以用二進制進行四捨五入了,但是可以用十進制打印結果。這意味着這些模式根本不明顯。

這裏是事情變得複雜的地方「:在FP函數中幾乎所有地方都需要四捨五入,所以它應該是快速的,這意味着你想要在四捨五入模式下進行編譯。但是每次調用時都不能重新編譯你的代碼fesetround。這意味着需要一種妥協,而妥協是#pragma STDC FENV_ACCESS。如果是ON,你會得到緩慢的代碼和fesetround的作品。如果是關閉(默認),fesetround不明結果。

+0

感謝您的詳細解釋。如果#pragma STDC FENV_ACCESS關閉,我怎樣才能在編譯時設置舍入模式? –

+0

@Houss_gc:不知道;你我不知道你有哪個編譯器。檢查你的手冊。 – MSalters

+0

好的(對不起,這個愚蠢的問題:p)實際上我使用gcc 5.3.0,叮3.8(均在Msys2下)和Rust 1.10每晚。我會檢查那些手冊,看看我能做什麼,再次感謝你。 –