8000 Split nextafter and nextafter_with_step · RustPython/RustPython@3e8e22b · GitHub
[go: up one dir, main page]

Skip to content

Commit 3e8e22b

Browse files
committed
Split nextafter and nextafter_with_step
1 parent 60805fb commit 3e8e22b

File tree

2 files changed

+74
-60
lines changed

2 files changed

+74
-60
lines changed

common/src/float_ops.rs

Lines changed: 68 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ pub fn divmod(v1: f64, v2: f64) -> Option<(f64, f64)> {
108108

109109
// nextafter algorithm based off of https://gitlab.com/bronsonbdevost/next_afterf
110110
#[allow(clippy::float_cmp)]
111-
pub fn nextafter(x: f64, y: f64, steps: Option<u64>) -> f64 {
111+
pub fn nextafter(x: f64, y: f64) -> f64 {
112112
if x == y {
113113
y
114114
} else if x.is_nan() || y.is_nan() {
@@ -120,69 +120,79 @@ pub fn nextafter(x: f64, y: f64, steps: Option<u64>) -> f64 {
120120
} else if x == 0.0 {
121121
f64::from_bits(1).copysign(y)
122122
} else {
123-
return match steps {
124-
None => {
125-
// next x after 0 if y is farther from 0 than x, otherwise next towards 0
126-
// the sign is a separate bit in floats, so bits+1 moves away from 0 no matter the float
127-
let b = x.to_bits();
128-
let bits = if (y > x) == (x > 0.0) { b + 1 } else { b - 1 };
129-
let ret = f64::from_bits(bits);
130-
if ret == 0.0 {
131-
ret.copysign(x)
132-
} else {
133-
ret
134-
}
135-
}
136-
Some(steps) => {
137-
if steps == 0 {
138-
return x;
139-
}
123+
// next x after 0 if y is farther from 0 than x, otherwise next towards 0
124+
// the sign is a separate bit in floats, so bits+1 moves away from 0 no matter the float
125+
let b = x.to_bits();
126+
let bits = if (y > x) == (x > 0.0) { b + 1 } else { b - 1 };
127+
let ret = f64::from_bits(bits);
128+
if ret == 0.0 {
129+
ret.copysign(x)
130+
} else {
131+
ret
132+
}
133+
}
134+
}
140135

141-
if x.is_nan() {
142-
return x;
143-
}
136+
#[allow(clippy::float_cmp)]
137+
pub fn nextafter_with_steps(x: f64, y: f64, steps: u64) -> f64 {
138+
if x == y {
139+
y
140+
} else if x.is_nan() || y.is_nan() {
141+
f64::NAN
142+
} else if x >= f64::INFINITY {
143+
f64::MAX
144+
} else if x <= f64::NEG_INFINITY {
145+
f64::MIN
146+
} else if x == 0.0 {
147+
f64::from_bits(1).copysign(y)
148+
} else {
149+
if steps == 0 {
150+
return x;
151+
}
144152

145-
if y.is_nan() {
146-
return y;
147-
}
153+
if x.is_nan() {
154+
return x;
155+
}
148156

149-
let sign_bit: u64 = 1 << 63;
157+
if y.is_nan() {
158+
return y;
159+
}
150160

151-
let mut ux = x.to_bits();
152-
let uy = y.to_bits();
161+
let sign_bit: u64 = 1 << 63;
153162

154-
let ax = ux & !sign_bit;
155-
let ay = uy & !sign_bit;
163+
let mut ux = x.to_bits();
164+
let uy = y.to_bits();
156165

157-
// If signs are different
158-
if ((ux ^ uy) & sign_bit) != 0 {
159-
return if ax + ay <= steps {
< 685C code>160-
f64::from_bits(uy)
161-
} else if ax < steps {
162-
let result = (uy & sign_bit) | (steps - ax);
163-
f64::from_bits(result)
164-
} else {
165-
ux -= steps;
166-
f64::from_bits(ux)
167-
};
168-
}
166+
let ax = ux & !sign_bit;
167+
let ay = uy & !sign_bit;
169168

170-
// If signs are the same
171-
if ax > ay {
172-
if ax - ay >= steps {
173-
ux -= steps;
174-
f64::from_bits(ux)
175-
} else {
176-
f64::from_bits(uy)
177-
}
178-
} else if ay - ax >= steps {
179-
ux += steps;
180-
f64::from_bits(ux)
181-
} else {
182-
f64::from_bits(uy)
183-
}
169+
// If signs are different
170+
if ((ux ^ uy) & sign_bit) != 0 {
171+
return if ax + ay <= steps {
172+
f64::from_bits(uy)
173+
} else if ax < steps {
174+
let result = (uy & sign_bit) | (steps - ax);
175+
f64::from_bits(result)
176+
} else {
177+
ux -= steps;
178+
f64::from_bits(ux)
179+
};
180+
}
181+
182+
// If signs are the same
183+
if ax > ay {
184+
if ax - ay >= steps {
185+
ux -= steps;
186+
f64::from_bits(ux)
187+
} else {
188+
f64::from_bits(uy)
184189
}
185-
};
190+
} else if ay - ax >= steps {
191+
ux += steps;
192+
f64::from_bits(ux)
193+
} else {
194+
f64::from_bits(uy)
195+
}
186196
}
187197
}
188198

@@ -191,10 +201,10 @@ pub fn ulp(x: f64) -> f64 {
191201
return x;
192202
}
193203
let x = x.abs();
194-
let x2 = nextafter(x, f64::INFINITY, None);
204+
let x2 = nextafter(x, f64::INFINITY);
195205
if x2.is_infinite() {
196206
// special case: x is the largest positive representable float
197-
let x2 = nextafter(x, f64::NEG_INFINITY, None);
207+
let x2 = nextafter(x, f64::NEG_INFINITY);
198208
x - x2
199209
} else {
200210
x2 - x

stdlib/src/math.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -855,9 +855,13 @@ mod math {
855855
vm.new_value_error("steps must be a non-negative integer".to_string())
856856
);
857857
}
858-
Ok(float_ops::nextafter(*arg.x, *arg.y, Some(steps as u64)))
858+
Ok(float_ops::nextafter_with_steps(
859+
*arg.x,
860+
*arg.y,
861+
steps as u64,
862+
))
859863
}
860-
None => Ok(float_ops::nextafter(*arg.x, *arg.y, None)),
864+
None => Ok(float_ops::nextafter(*arg.x, *arg.y)),
861865
}
862866
}
863867

0 commit comments

Comments
 (0)
0