math.rs
math.rs copied to clipboard
Results from math.rs and glibc are different
math.rs library looks promising and can used as a template for Rust float functions implementation. In this case performance and correctness are 2 extremely important properties. I checked some functions and found that most of them work well, but cos
shows incorrect results. Here is an example:
cos(2.0) gives following results:
libm: -0.4161468365471424
math.rs: -0.4161468365471425
google: -0.41614683654
ruby: -0.4161468365471424
math.rs result is slightly different from what libm returns.
Most likely because the implementation wasn’t copied from glibc. The current implementation in math.rs acknowledges it is not too accurate for example here. Moreover, I suspect glibc just calls a hardware instruction to calculate cosine making this a comparison between hardware instruction and software implementation and not two software implementations. It may very well be that glibc’s software implementation is not very good either.
If there’s a possibility to contribute a more correct, properly licensed version (MIT/Apache), by all means please do so.
(for the reference, less rounded result of cos(2.)
is -0.41614683654714238699756822950076218976600077107554489075
, so glibc/hardware is clearly more correct here).
It seems that glibc calculates sine and cosine in software: https://stackoverflow.com/questions/12485190/calling-fsincos-instruction-in-llvm-slower-than-calling-libc-sin-cos-functions#24470801.
So I’ve redone the test suite to quick-check and there’s a number of functions that do not match the glibc output exactly:
- sin, cos, tan – trigonometry functions, which I’ve already acknowledged to be inaccurate;
- exp – significantly wrong (I must have done a mistake somewhere);
- sqrtf, expf – 1 ulp, most likely because these are calculated with sqrt/exp and then cast to f32;
- llroundf, lroundf – seems like a wrong shift;
- hypot, hypotf – mismatch of NaN bit-pattern for undefined result (i.e. not something to be worried about);
- logb, logbf, scalbn, scalbnf – mistakes/UBs/different constants around special cases, I think;
- ilogb, ilogbf – different value for the FP_ILOGBNAN constant.
It might worth to integrate math unit tests from libc-test project http://repo.or.cz/libc-test.git/tree/HEAD:/src/math