Skip to content

Precision of exp2f on x86 without SSE #1021

@quaternic

Description

@quaternic

Currently libm::exp2f is producing very inaccurate results on x86 without SSE (aka i586 in rustc). For example,
exp2f(1.0312501) evaluates to approximately 2.0885..., when it should be 2.0438..., which is a relative error of ~2%, or only four correct fractional bits.

I looked into why that is, with the conclusion that it's a bad case of rust-lang/rust#114479 . In a nutshell, LLVM
ignores the requirement to round each intermediate result to its type. For example, code like

let xy: f32 = x + y;
xy - y

might be evaluated more like

let xy: f80 = x as f80 + y as f80;
(xy - y as f80) as f32

The current implementation of exp2f is using that implied rounding to compute the exact rounding error, and thus reduce it without loss of precision. (I believe it is effectively https://en.wikipedia.org/wiki/2Sum or at least similar). This of course doesn't work at all if the compiler may arbitrarily choose to leave out some intermediate rounding steps.

It may be possible to tweak exp2f so that it doesn't rely on correct rounding as crucially. However, it's worrying that even basic arithmetic isn't reliable.

One solution could be to implement it directly with inline assembly like we did with ceil and floor. By relying on x87s f2xm1-instruction, it isn't too complex, and I've tested this already. However, this would mean that exact numeric results could still depend on platform. (For ceil/floor, there is only one allowed value, so it didn't matter.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions