-
Notifications
You must be signed in to change notification settings - Fork 6
Add sin,cos,floor,floorf,scalbn,copysign,copysignf #15
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR, @odlg.
This looks good to me but it's going to be very hard to land this if the results don't always match libm results though.
The discrepancy between the results doesn't seem to be small either -- I ran the test suite locally and some results are way off when the inputs are large. Though probably we shouldn't be testing functions like sin and cos for inputs beyond -2PI and 2PI.
sin(-1_f32) should be equal to -0.84147096_f32
It's weird that the result is off for that input. Could this be a bug in the openlibm implementation? libm seems to get the mathematically correct result.
P.S. It's ... interesting that openlibm computes sinf using double precision. I expect that will be heavyweight to compute on 32-bit architectures, specially ones without a FPU (e.g. microcontrollers).
src/ll.rs
Outdated
unimplemented!() | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: extra newline
src/ll.rs
Outdated
} | ||
|
||
|
||
pub fn cosdf(x: f64) -> f32 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this doesn't need to be public.
src/ll.rs
Outdated
} | ||
|
||
|
||
pub extern "C" fn ieee754_rem_pio2f(x: f32) -> (i32, f64) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this doesn't need to be public.
src/ll.rs
Outdated
} | ||
|
||
|
||
pub extern "C" fn kernel_rem_pio2(x: [f64; 1], e0: i32, nx: i32, prec: i32) -> (i32, [f64; 3]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this doesn't need to be public.
(x.repr() & 0x7fffffffffffffff) | (y.repr() & 0x8000000000000000), | ||
) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: extra newline
src/ll.rs
Outdated
assert_eq!(super::floor(-14207526.52111395f64), -14207527f64); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: extra newline
I have fixed some porting bugs, results are much better now. I guess the minor differences are caused by comparing different libm implementations. At least reading JuliaMath/openlibm#30 makes me think so. At one point I got this error running the tests: Making C openlibm doing this gives the same result as the rust port of openlibm. So: |
@odlg sorry for taking so long to get back to this. I tried increasing the tolerance of the approximate equality comparison to 100 ULP (see patch bellow) #[cfg(test)]
fn eq_repr(self, rhs: Self) -> bool {
+ const TOLERANCE_ULP: $repr_ty = 100;
+
if self.is_nan() && rhs.is_nan() {
true
} else {
let (lhs, rhs) = (self.repr(), rhs.repr());
- lhs == rhs || (lhs > rhs && lhs - rhs == 1) ||
- (rhs > lhs && rhs - lhs == 1)
+ lhs.wrapping_sub(rhs) <= TOLERANCE_ULP
}
} but I got some "errors" in the order of 1000 ULPs or higher when randomly testing ---- ll::tests::sinf stdout ----
sinf - Args: x = -0.00390625 (0xbb800000)
us: -0.0039183237 (0xbb806548)
libm: -0.00390624 (0xbb7fffd5)
Any chance there could still be bugs in the I also tried your //#include <openlibm.h>
#include <math.h>
#include <stdio.h>
int main() {
float x = -0.4352397;
float y = sinf(x);
printf("%.*e\n", y);
} returns I do agree that testing against openlibm would be ideal but it'll probably be complicated to get that C / asm code building for all the test targets. OTOH, we could reuse that build infrastructure to provide a C fall back for this crate (i.e. if asinf is not implemented in Rust you'll be able to use openlibm's C implementation through FFI). |
And I'm getting |
I think I was partly fooled by differences between C |
Neat! Let's see what homu thinks. @homunkulus r+ |
📌 Commit 0b78d9b has been approved by |
Add sin,cos,floor,floorf,scalbn,copysign,copysignf This adds sin, cos and dependencies. I have seen some inaccuracies when using the libm comparison. For instance: `sin(-1_f32) should be equal to -0.84147096_f32` but when libm comparison is used it is -0.83888906_f32. Debugging points to doing a f64 as f32 introduces this. When using these sin and cos functions in clean rust environments results are OK.
💔 Test failed - status-appveyor |
@japaric Any ideas on what to do about this? Limit the range of which sinf and cosf are tested? |
Yes, to a few PIs around zero. (I think I may have mentioned this above)
It's OK to increase the tolerance (e.g. using the patch above) as long as the allowed tolerance is "reasonable". I'm not sure what would be reasonable but a difference of hundreds of ULPs between us and libm is likely indicating some bug (assuming the input is also reasonable). |
Add sin,cos,floor,floorf,scalbn,copysign,copysignf This adds sin, cos and dependencies. I have seen some inaccuracies when using the libm comparison. For instance: `sin(-1_f32) should be equal to -0.84147096_f32` but when libm comparison is used it is -0.83888906_f32. Debugging points to doing a f64 as f32 introduces this. When using these sin and cos functions in clean rust environments results are OK.
💔 Test failed - status-travis |
Add sin,cos,floor,floorf,scalbn,copysign,copysignf This adds sin, cos and dependencies. I have seen some inaccuracies when using the libm comparison. For instance: `sin(-1_f32) should be equal to -0.84147096_f32` but when libm comparison is used it is -0.83888906_f32. Debugging points to doing a f64 as f32 introduces this. When using these sin and cos functions in clean rust environments results are OK.
💔 Test failed - status-appveyor |
Add sin,cos,floor,floorf,scalbn,copysign,copysignf This adds sin, cos and dependencies. I have seen some inaccuracies when using the libm comparison. For instance: `sin(-1_f32) should be equal to -0.84147096_f32` but when libm comparison is used it is -0.83888906_f32. Debugging points to doing a f64 as f32 introduces this. When using these sin and cos functions in clean rust environments results are OK.
💔 Test failed - status-appveyor |
Add sin,cos,floor,floorf,scalbn,copysign,copysignf This adds sin, cos and dependencies. I have seen some inaccuracies when using the libm comparison. For instance: `sin(-1_f32) should be equal to -0.84147096_f32` but when libm comparison is used it is -0.83888906_f32. Debugging points to doing a f64 as f32 introduces this. When using these sin and cos functions in clean rust environments results are OK.
💔 Test failed - status-travis |
@japaric Results are better now - one platform fails on doc-tests. Do you have an idea? |
This crate has been deprecated in favor of the libm crate. This repository will be archived. |
This adds sin, cos and dependencies.
I have seen some inaccuracies when using the libm comparison. For instance:
sin(-1_f32) should be equal to -0.84147096_f32
but when libm comparison is used it is -0.83888906_f32. Debugging points to doing a f64 as f32 introduces this.
When using these sin and cos functions in clean rust environments results are OK.