Skip to content

core::num::dec2flt interprets the rounding mode incorrectly for negative numbers #41753

Closed
@eseraygun

Description

@eseraygun

core::num::dec2flt interprets the floating-point rounding mode incorrectly for negative numbers. The assumption in the implementation that negative numbers can be handled by just flipping the sign bit is wrong in the general case.

Observed Behavior

core::num::dec2flt rounds negative numbers upwards when the rounding mode is set to downwards and vice versa.

Here is the code that demonstrates the issue.

extern crate libc;

use libc::c_int;
use std::str::FromStr;

const FE_TONEAREST: c_int = 0;
const FE_DOWNWARD:  c_int = 0x400;
const FE_UPWARD:    c_int = 0x800;

extern {
    fn fesetround(rdir: c_int) -> c_int;
}

fn main() {
    unsafe { fesetround(FE_DOWNWARD); }
    let p_lo = f64::from_str("0.9").unwrap();
    let n_lo = f64::from_str("-0.9").unwrap();

    unsafe { fesetround(FE_UPWARD); }
    let p_hi = f64::from_str("0.9").unwrap();
    let n_hi = f64::from_str("-0.9").unwrap();

    unsafe { fesetround(FE_TONEAREST); }
    println!(" 0.9: <{:19.16}, {:19.16}>", p_lo, p_hi);
    println!("-0.9: <{:19.16}, {:19.16}>", n_lo, n_hi);
}

Output:

 0.9: < 0.8999999999999999,  0.9000000000000000>
-0.9: <-0.8999999999999999, -0.9000000000000000>

Here is the equivalent code in C.

#include <fenv.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    double p_lo, p_hi, n_lo, n_hi;

    fesetround(FE_DOWNWARD);
    p_lo = strtod("0.9", NULL);
    n_lo = strtod("-0.9", NULL);

    fesetround(FE_UPWARD);
    p_hi = strtod("0.9", NULL);
    n_hi = strtod("-0.9", NULL);

    fesetround(FE_TONEAREST);
    printf(" 0.9: <%19.16f, %19.16f>\n", p_lo, p_hi);
    printf("-0.9: <%19.16f, %19.16f>\n", n_lo, n_hi);
}

Output:

 0.9: < 0.8999999999999999,  0.9000000000000000>
-0.9: <-0.9000000000000000, -0.8999999999999999>

C handles the rounding correctly whereas Rust gets it wrong for negative numbers.

Expected Behavior

core::num::dec2flt should either not be affected by the rounding mode and always use half-to-even rounding as stated in the documentation or interpret the rounding mode correctly.

Meta

rustc --version --verbose:

rustc 1.19.0-nightly (6a5fc9eec 2017-05-02)
binary: rustc
commit-hash: 6a5fc9eecec235312755e737fb5b984abe537f2e
commit-date: 2017-05-02
host: x86_64-unknown-linux-gnu
release: 1.19.0-nightly
LLVM version: 4.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions