c++ - 从 Rust 和 C++ 设置 FPU 舍入方向没有任何改变

标签 c++ floating-point rust rounding computation

据我所知,将舍入方向设置为 +Inf 会在计算 1/3 时产生 0.333334,而在设置为 0.33333 时会产生 0.33333 -Inf.

当我尝试在 C++ 中使用 fesetround(0x400)fesetround(0x800) 时,情况并非如此。我在 Rust 中使用 FFI 从 C 调用 fsetround 得到相同的行为。

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 )

防 rust 代码:

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 )

最佳答案

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 会产生未指定的结果。

关于c++ - 从 Rust 和 C++ 设置 FPU 舍入方向没有任何改变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36681157/

相关文章:

c++ - 是否有用转义序列替换 xml 特殊字符的 c++ 函数?

c++ - 如何添加对 Boost.Proto 表达式的父引用?

c++ - Cin 并指向所选函数

c# - float 乘法返回意外结果

architecture - 32位 float 可以表示多少个数字

c++ - gtest 的 undefined reference

c - printf ("%.15e", 1e23) 应该是什么;打印?

rust - 如何使用 Arc<Mutex<...>> 转换特征对象?

Rust:如何实现链表?

random - 如何在其他两个数组之间创建一个随机数组?