Skip to content

Commit 1b0f4b0

Browse files
committed
fix linux compat
1 parent e5ee9dc commit 1b0f4b0

File tree

4 files changed

+49
-38
lines changed

4 files changed

+49
-38
lines changed

src/cmath/misc.rs

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,15 @@ static RECT_SPECIAL_VALUES: [[Complex64; 7]; 7] = [
1717

1818
/// Return the phase angle (argument) of z.
1919
#[inline]
20-
pub fn phase(z: Complex64) -> f64 {
21-
m::atan2(z.im, z.re)
20+
pub fn phase(z: Complex64) -> Result<f64> {
21+
crate::err::set_errno(0);
22+
let phi = m::atan2(z.im, z.re);
23+
match crate::err::get_errno() {
24+
0 => Ok(phi),
25+
libc::EDOM => Err(Error::EDOM),
26+
libc::ERANGE => Err(Error::ERANGE),
27+
_ => Err(Error::EDOM), // Unknown errno treated as domain error (like PyErr_SetFromErrno)
28+
}
2229
}
2330

2431
/// Convert z to polar coordinates (r, phi).
@@ -123,20 +130,40 @@ mod tests {
123130
pyo3::Python::attach(|py| {
124131
let cmath = pyo3::types::PyModule::import(py, "cmath").unwrap();
125132
let py_func = cmath.getattr("phase").unwrap();
126-
let py_result: f64 = py_func
127-
.call1((pyo3::types::PyComplex::from_doubles(py, re, im),))
128-
.unwrap()
129-
.extract()
130-
.unwrap();
131-
132-
if py_result.is_nan() && rs_result.is_nan() {
133-
return;
133+
let py_result = py_func.call1((pyo3::types::PyComplex::from_doubles(py, re, im),));
134+
135+
match py_result {
136+
Ok(result) => {
137+
let py_val: f64 = result.extract().unwrap();
138+
match rs_result {
139+
Ok(rs_val) => {
140+
if py_val.is_nan() && rs_val.is_nan() {
141+
return;
142+
}
143+
assert_eq!(
144+
py_val.to_bits(),
145+
rs_val.to_bits(),
146+
"phase({re}, {im}): py={py_val} vs rs={rs_val}"
147+
);
148+
}
149+
Err(e) => {
150+
panic!("phase({re}, {im}): py={py_val} but rs returned error {e:?}");
151+
}
152+
}
153+
}
154+
Err(e) => {
155+
// Python raised an exception - check we got an error too
156+
if rs_result.is_ok() {
157+
let rs_val = rs_result.unwrap();
158+
if e.is_instance_of::<pyo3::exceptions::PyValueError>(py) {
159+
panic!("phase({re}, {im}): py raised ValueError but rs={rs_val}");
160+
} else if e.is_instance_of::<pyo3::exceptions::PyOverflowError>(py) {
161+
panic!("phase({re}, {im}): py raised OverflowError but rs={rs_val}");
162+
}
163+
}
164+
// Both raised errors - OK
165+
}
134166
}
135-
assert_eq!(
136-
py_result.to_bits(),
137-
rs_result.to_bits(),
138-
"phase({re}, {im}): py={py_result} vs rs={rs_result}"
139-
);
140167
});
141168
}
142169

src/m_sys.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// These symbols are all defined by `libm`,
22
// or by `compiler-builtins` on unsupported platforms.
3+
#[cfg_attr(unix, link(name = "m"))]
34
#[allow(dead_code)]
45
unsafe extern "C" {
56
// Trigonometric functions

src/math.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ pub(crate) use libm_simple;
4848
/// math_1: wrapper for 1-arg functions
4949
/// - isnan(r) && !isnan(x) -> domain error
5050
/// - isinf(r) && isfinite(x) -> overflow (can_overflow=true) or domain error (can_overflow=false)
51+
/// - isfinite(r) && errno -> check errno (unnecessary on most platforms)
5152
#[inline]
5253
pub(crate) fn math_1(x: f64, func: fn(f64) -> f64, can_overflow: bool) -> crate::Result<f64> {
54+
crate::err::set_errno(0);
5355
let r = func(x);
5456
if r.is_nan() && !x.is_nan() {
5557
return Err(crate::Error::EDOM);
@@ -61,6 +63,10 @@ pub(crate) fn math_1(x: f64, func: fn(f64) -> f64, can_overflow: bool) -> crate:
6163
crate::Error::EDOM
6264
});
6365
}
66+
// This branch unnecessary on most platforms
67+
if r.is_finite() && crate::err::get_errno() != 0 {
68+
return crate::err::is_error(r);
69+
}
6470
Ok(r)
6571
}
6672

src/math/aggregate.rs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,36 +27,13 @@ fn dl_sum(a: f64, b: f64) -> DoubleLength {
2727
}
2828

2929
/// Algorithm 3.5. Error-free transformation of a product using FMA
30-
#[cfg(any(feature = "mul_add", target_os = "windows"))]
3130
#[inline]
3231
fn dl_mul(x: f64, y: f64) -> DoubleLength {
3332
let z = x * y;
3433
let zz = x.mul_add(y, -z);
3534
DoubleLength { hi: z, lo: zz }
3635
}
3736

38-
/// Dekker's algorithm for error-free product without FMA
39-
#[cfg(not(any(feature = "mul_add", target_os = "windows")))]
40-
#[inline]
41-
fn dl_mul(x: f64, y: f64) -> DoubleLength {
42-
// Dekker (5.5) and (5.6) - split
43-
fn dl_split(x: f64) -> DoubleLength {
44-
let t = x * 134217729.0; // Veltkamp constant = 2^27 + 1
45-
let hi = t - (t - x);
46-
let lo = x - hi;
47-
DoubleLength { hi, lo }
48-
}
49-
50-
// Dekker (5.12) and mul12()
51-
let xx = dl_split(x);
52-
let yy = dl_split(y);
53-
let p = xx.hi * yy.hi;
54-
let q = xx.hi * yy.lo + xx.lo * yy.hi;
55-
let z = p + q;
56-
let zz = p - z + q + xx.lo * yy.lo;
57-
DoubleLength { hi: z, lo: zz }
58-
}
59-
6037
/// Triple-length number for extra precision
6138
#[derive(Clone, Copy)]
6239
struct TripleLength {

0 commit comments

Comments
 (0)