с плавающей точкой — установка направления округления FPU из Rust и C ++ ничего не меняет

В моем понимании, установка направления округления в сторону +Inf даст 0.333334 при оценке 1/3 и 0.33333 при установке его в сторону -Inf,

Это не тот случай, когда я пытался в C ++, используя fesetround(0x400) а также fesetround(0x800), Я получаю такое же поведение в Rust, используя FFI для вызова 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)

Код ржавчины:

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)

2

Решение

Комментарий Starblue прав, но позвольте мне расширить его.

«Округление» означает аппроксимацию действительного числа конечным набором цифр в некоторой неопределенной базе. Ваш пример 1/3 = 0,333333 предполагает округление до 6 десятичный цифры, то есть основание 10.

Компьютеры работают в базе 2, однако. Двоичный 1/11 является .1010101010101... Как видите, округление это немного своеобразно. Если вы округлите до ближайшего к 6 битам, это будет .101011 и если вы округлите его до 7 бит, это .1010100 — последний бит всегда совпадает с предпоследним битом, и это потому, что биты чередуются.

Конечно, округлять вверх-вниз проще. округление .10101010... down просто усекает результат до N битов: 0.101010, И округление просто добавляет 1 к последнему биту.

Теперь вы делаете округление в двоичном виде, но вы выводите результат в десятичном виде. Это означает, что эти шаблоны совсем не очевидны.

Вот где все усложняется «: округление необходимо почти везде в функциях FP, поэтому оно должно быть быстрым. Это означает, что вы хотите, чтобы режим округления был скомпилирован. Но вы не можете перекомпилировать свой код при каждом вызове fesetround, Это означает, что нужен компромисс, и компромисс #pragma STDC FENV_ACCESS. Если это ON, вы получаете медленный код и fesetround работает. Если он выключен (по умолчанию), fesetround имеет неопределенные Результаты.

3

Другие решения

Других решений пока нет …