Hi,
In an effort to spare myself and downstream users some effort, I'm idly working on re-writing ERFA C library into Rust. This project lends itself to a re-write as it has no dependencies and is relatively simple. Despite its simplicity, it is extremely important that the library's calculations are accurate, as its primary purpose is providing precise astronomical measurements.
I've already published erfa-sys
on crates.io, which simply provides Rust bindings for the C library (and optionally compiles it from source). In an effort to ensure that my re-write is behaving, I'm testing my erfa
crate against my erfa-sys
crate, and I've spotted some subtle differences, e.g. (light edits for brevity):
double eraFaom03(double t) {
double a;
a = fmod( 450160.398036 +
t * ( - 6962890.5431 +
t * ( 7.4722 +
t * ( 0.007702 +
t * ( - 0.00005939 ) ) ) ), ERFA_TURNAS ) * ERFA_DAS2R;
return a;
/* Finished. */
}
pub fn om03(t: f64) -> f64 {
#[rustfmt::skip]
let a =
(( 450160.398036 +
t * ( - 6962890.5431 +
t * ( 7.4722 +
t * ( 0.007702 +
t * ( - 0.00005939 ) ) ) )) % ERFA_TURNAS ) * ERFA_DAS2R;
a
}
#[test]
fn test_eraFaom03() {
for t in [0.1, 1.2, 12.34] {
let result = eraFaom03(t);
let expected = unsafe { erfa_sys::eraFaom03(t) };
dbg!(t);
// approx 0.5.0
approx::assert_abs_diff_eq!(result, expected);
}
}
---- aliases::tests::test_eraFaom03 stdout ----
[erfa/src/aliases/tests.rs:171] t = 0.1
[erfa/src/aliases/tests.rs:171] t = 1.2
thread 'aliases::tests::test_eraFaom03' panicked at 'assert_abs_diff_eq!(result, expected)
left = -0.6268518749398361
right = -0.6268518749398405
', erfa/src/aliases/tests.rs:172:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Obviously in at least one case, there is no difference, but in another there's a few different mantissa bits. I've just re-compiled the C library and I'm using up-to-date Arch with an x86-64 CPU. I've tried looking at the assembly but (once again) my eyes glaze over with uncertainty and confusion.
Seeing as the code that comprises these two functions is relatively simple, I guess I'm surprised that differences are possible. Would anyone be able to clarify what is going on here, and whether I should be worried? I can whack an epsilon onto my tests, but I'd like to understand what's going on. Thanks!