Skip to content

Commit 73bad8d

Browse files
committed
Rely on libm for a no_std alternative to round_ties_even
1 parent cb447fb commit 73bad8d

File tree

3 files changed

+28
-38
lines changed

3 files changed

+28
-38
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

naga/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ hashbrown.workspace = true
9191
half = { workspace = true, default-features = false, features = ["num-traits"] }
9292
rustc-hash.workspace = true
9393
indexmap.workspace = true
94+
libm = { version = "0.2", default-features = false }
9495
log.workspace = true
9596
# `half` requires 0.2.16 for `FromBytes` and `ToBytes`.
9697
num-traits = { version = "0.2.16", default-features = false }

naga/src/proc/constant_evaluator.rs

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,46 +1171,34 @@ impl<'a> ConstantEvaluator<'a> {
11711171
component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) })
11721172
}
11731173
crate::MathFunction::Round => {
1174-
/// Rounds to the nearest integer, with ties biasing towards an even result.
1175-
///
1176-
/// # TODO
1177-
///
1178-
/// - `round_ties_even` is not available on `half::f16` yet.
1179-
/// - It is also not available on `no_std`
1180-
///
1181-
/// This polyfill is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source],
1182-
/// which has licensing compatible with ours. See also
1183-
/// <https://github.com/rust-lang/rust/issues/96710>.
1184-
///
1185-
/// [polyfill source]: https://github.com/imeka/ndarray-ndimage/blob/8b14b4d6ecfbc96a8a052f802e342a7049c68d8f/src/lib.rs#L98
1186-
fn round_ties_even<T: num_traits::float::FloatCore>(x: T) -> T {
1187-
let half = (T::one() + T::one()).recip();
1188-
1189-
if x.fract().abs() != half {
1190-
x.round()
1191-
} else {
1192-
let i = x.abs().trunc();
1193-
1194-
let value = if (i * half).fract() == half {
1195-
// -1.5, 1.5, 3.5, ...
1196-
x.abs() + half
1197-
} else {
1198-
// -0.5, 0.5, 2.5, ...
1199-
x.abs() - half
1200-
};
1201-
1202-
if x.signum() != value.signum() {
1203-
-value
1204-
} else {
1205-
value
1174+
component_wise_float(self, span, [arg], |e| match e {
1175+
Float::Abstract([e]) => Ok(Float::Abstract([libm::rint(e)])),
1176+
Float::F32([e]) => Ok(Float::F32([libm::rintf(e)])),
1177+
Float::F16([e]) => {
1178+
// TODO: `round_ties_even` is not available on `half::f16` yet.
1179+
//
1180+
// This polyfill is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source],
1181+
// which has licensing compatible with ours. See also
1182+
// <https://github.com/rust-lang/rust/issues/96710>.
1183+
//
1184+
// [polyfill source]: https://github.com/imeka/ndarray-ndimage/blob/8b14b4d6ecfbc96a8a052f802e342a7049c68d8f/src/lib.rs#L98
1185+
fn round_ties_even(x: f64) -> f64 {
1186+
let i = x as i64;
1187+
let f = (x - i as f64).abs();
1188+
if f == 0.5 {
1189+
if i & 1 == 1 {
1190+
// -1.5, 1.5, 3.5, ...
1191+
(x.abs() + 0.5).copysign(x)
1192+
} else {
1193+
(x.abs() - 0.5).copysign(x)
1194+
}
1195+
} else {
1196+
x.round()
1197+
}
12061198
}
1207-
}
1208-
}
12091199

1210-
component_wise_float(self, span, [arg], |e| match e {
1211-
Float::Abstract([e]) => Ok(Float::Abstract([round_ties_even(e)])),
1212-
Float::F32([e]) => Ok(Float::F32([round_ties_even(e)])),
1213-
Float::F16([e]) => Ok(Float::F16([round_ties_even(e)])),
1200+
Ok(Float::F16([(f16::from_f64(round_ties_even(f64::from(e))))]))
1201+
}
12141202
})
12151203
}
12161204
crate::MathFunction::Fract => {

0 commit comments

Comments
 (0)