Skip to content

Commit 29508f0

Browse files
BenjaminBrienenalice-i-cecileIQuick143Jondolf
authored
Fix floating point math (#15239)
# Objective - Fixes #15236 ## Solution - Use bevy_math::ops instead of std floating point operations. ## Testing - Did you test these changes? If so, how? Unit tests and `cargo run -p ci -- test` - How can other people (reviewers) test your changes? Is there anything specific they need to know? Execute `cargo run -p ci -- test` on Windows. - If relevant, what platforms did you test these changes on, and are there any important ones you can't test? Windows ## Migration Guide - Not a breaking change - Projects should use bevy math where applicable --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: IQuick 143 <IQuick143cz@gmail.com> Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
1 parent 0dd00e9 commit 29508f0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+331
-266
lines changed

clippy.toml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,33 @@ doc-valid-idents = [
1010
"WebGPU",
1111
"..",
1212
]
13+
14+
disallowed-methods = [
15+
{ path = "f32::powi", reason = "use bevy_math::ops::FloatPow::squared, bevy_math::ops::FloatPow::cubed, or bevy_math::ops::powf instead for libm determinism" },
16+
{ path = "f32::log", reason = "use bevy_math::ops::ln, bevy_math::ops::log2, or bevy_math::ops::log10 instead for libm determinism" },
17+
{ path = "f32::abs_sub", reason = "deprecated and deeply confusing method" },
18+
{ path = "f32::powf", reason = "use bevy_math::ops::powf instead for libm determinism" },
19+
{ path = "f32::exp", reason = "use bevy_math::ops::exp instead for libm determinism" },
20+
{ path = "f32::exp2", reason = "use bevy_math::ops::exp2 instead for libm determinism" },
21+
{ path = "f32::ln", reason = "use bevy_math::ops::ln instead for libm determinism" },
22+
{ path = "f32::log2", reason = "use bevy_math::ops::log2 instead for libm determinism" },
23+
{ path = "f32::log10", reason = "use bevy_math::ops::log10 instead for libm determinism" },
24+
{ path = "f32::cbrt", reason = "use bevy_math::ops::cbrt instead for libm determinism" },
25+
{ path = "f32::hypot", reason = "use bevy_math::ops::hypot instead for libm determinism" },
26+
{ path = "f32::sin", reason = "use bevy_math::ops::sin instead for libm determinism" },
27+
{ path = "f32::cos", reason = "use bevy_math::ops::cos instead for libm determinism" },
28+
{ path = "f32::tan", reason = "use bevy_math::ops::tan instead for libm determinism" },
29+
{ path = "f32::asin", reason = "use bevy_math::ops::asin instead for libm determinism" },
30+
{ path = "f32::acos", reason = "use bevy_math::ops::acos instead for libm determinism" },
31+
{ path = "f32::atan", reason = "use bevy_math::ops::atan instead for libm determinism" },
32+
{ path = "f32::atan2", reason = "use bevy_math::ops::atan2 instead for libm determinism" },
33+
{ path = "f32::sin_cos", reason = "use bevy_math::ops::sin_cos instead for libm determinism" },
34+
{ path = "f32::exp_m1", reason = "use bevy_math::ops::exp_m1 instead for libm determinism" },
35+
{ path = "f32::ln_1p", reason = "use bevy_math::ops::ln_1p instead for libm determinism" },
36+
{ path = "f32::sinh", reason = "use bevy_math::ops::sinh instead for libm determinism" },
37+
{ path = "f32::cosh", reason = "use bevy_math::ops::cosh instead for libm determinism" },
38+
{ path = "f32::tanh", reason = "use bevy_math::ops::tanh instead for libm determinism" },
39+
{ path = "f32::asinh", reason = "use bevy_math::ops::asinh instead for libm determinism" },
40+
{ path = "f32::acosh", reason = "use bevy_math::ops::acosh instead for libm determinism" },
41+
{ path = "f32::atanh", reason = "use bevy_math::ops::atanh instead for libm determinism" },
42+
]

crates/bevy_animation/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use bevy_app::{App, Plugin, PostUpdate};
2222
use bevy_asset::{Asset, AssetApp, Assets, Handle};
2323
use bevy_core::Name;
2424
use bevy_ecs::{entity::MapEntities, prelude::*, reflect::ReflectMapEntities};
25-
use bevy_math::{FloatExt, Quat, Vec3};
25+
use bevy_math::{FloatExt, FloatPow, Quat, Vec3};
2626
use bevy_reflect::std_traits::ReflectDefault;
2727
use bevy_reflect::Reflect;
2828
use bevy_render::mesh::morph::MorphWeights;
@@ -1211,10 +1211,10 @@ fn cubic_spline_interpolation<T>(
12111211
where
12121212
T: Mul<f32, Output = T> + Add<Output = T>,
12131213
{
1214-
value_start * (2.0 * lerp.powi(3) - 3.0 * lerp.powi(2) + 1.0)
1215-
+ tangent_out_start * (step_duration) * (lerp.powi(3) - 2.0 * lerp.powi(2) + lerp)
1216-
+ value_end * (-2.0 * lerp.powi(3) + 3.0 * lerp.powi(2))
1217-
+ tangent_in_end * step_duration * (lerp.powi(3) - lerp.powi(2))
1214+
value_start * (2.0 * lerp.cubed() - 3.0 * lerp.squared() + 1.0)
1215+
+ tangent_out_start * (step_duration) * (lerp.cubed() - 2.0 * lerp.squared() + lerp)
1216+
+ value_end * (-2.0 * lerp.cubed() + 3.0 * lerp.squared())
1217+
+ tangent_in_end * step_duration * (lerp.cubed() - lerp.squared())
12181218
}
12191219

12201220
/// Adds animation support to an app

crates/bevy_color/src/laba.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::{
22
impl_componentwise_vector_space, Alpha, ColorToComponents, Gray, Hsla, Hsva, Hwba, LinearRgba,
33
Luminance, Mix, Oklaba, Srgba, StandardColor, Xyza,
44
};
5-
use bevy_math::{Vec3, Vec4};
5+
use bevy_math::{ops, Vec3, Vec4};
66
#[cfg(feature = "bevy_reflect")]
77
use bevy_reflect::prelude::*;
88

@@ -225,7 +225,7 @@ impl From<Laba> for Xyza {
225225
let fx = a / 500.0 + fy;
226226
let fz = fy - b / 200.0;
227227
let xr = {
228-
let fx3 = fx.powf(3.0);
228+
let fx3 = ops::powf(fx, 3.0);
229229

230230
if fx3 > Laba::CIE_EPSILON {
231231
fx3
@@ -234,12 +234,12 @@ impl From<Laba> for Xyza {
234234
}
235235
};
236236
let yr = if l > Laba::CIE_EPSILON * Laba::CIE_KAPPA {
237-
((l + 16.0) / 116.0).powf(3.0)
237+
ops::powf((l + 16.0) / 116.0, 3.0)
238238
} else {
239239
l / Laba::CIE_KAPPA
240240
};
241241
let zr = {
242-
let fz3 = fz.powf(3.0);
242+
let fz3 = ops::powf(fz, 3.0);
243243

244244
if fz3 > Laba::CIE_EPSILON {
245245
fz3
@@ -262,17 +262,17 @@ impl From<Xyza> for Laba {
262262
let yr = y / Xyza::D65_WHITE.y;
263263
let zr = z / Xyza::D65_WHITE.z;
264264
let fx = if xr > Laba::CIE_EPSILON {
265-
xr.cbrt()
265+
ops::cbrt(xr)
266266
} else {
267267
(Laba::CIE_KAPPA * xr + 16.0) / 116.0
268268
};
269269
let fy = if yr > Laba::CIE_EPSILON {
270-
yr.cbrt()
270+
ops::cbrt(yr)
271271
} else {
272272
(Laba::CIE_KAPPA * yr + 16.0) / 116.0
273273
};
274274
let fz = if yr > Laba::CIE_EPSILON {
275-
zr.cbrt()
275+
ops::cbrt(zr)
276276
} else {
277277
(Laba::CIE_KAPPA * zr + 16.0) / 116.0
278278
};

crates/bevy_color/src/lcha.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::{
22
Alpha, ColorToComponents, Gray, Hue, Laba, LinearRgba, Luminance, Mix, Srgba, StandardColor,
33
Xyza,
44
};
5-
use bevy_math::{Vec3, Vec4};
5+
use bevy_math::{ops, Vec3, Vec4};
66
#[cfg(feature = "bevy_reflect")]
77
use bevy_reflect::prelude::*;
88

@@ -257,8 +257,9 @@ impl From<Lcha> for Laba {
257257
) -> Self {
258258
// Based on http://www.brucelindbloom.com/index.html?Eqn_LCH_to_Lab.html
259259
let l = lightness;
260-
let a = chroma * hue.to_radians().cos();
261-
let b = chroma * hue.to_radians().sin();
260+
let (sin, cos) = ops::sin_cos(hue.to_radians());
261+
let a = chroma * cos;
262+
let b = chroma * sin;
262263

263264
Laba::new(l, a, b, alpha)
264265
}
@@ -274,9 +275,9 @@ impl From<Laba> for Lcha {
274275
}: Laba,
275276
) -> Self {
276277
// Based on http://www.brucelindbloom.com/index.html?Eqn_Lab_to_LCH.html
277-
let c = (a.powf(2.0) + b.powf(2.0)).sqrt();
278+
let c = ops::hypot(a, b);
278279
let h = {
279-
let h = b.to_radians().atan2(a.to_radians()).to_degrees();
280+
let h = ops::atan2(b.to_radians(), a.to_radians()).to_degrees();
280281

281282
if h < 0.0 {
282283
h + 360.0

crates/bevy_color/src/oklaba.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::{
22
color_difference::EuclideanDistance, impl_componentwise_vector_space, Alpha, ColorToComponents,
33
Gray, Hsla, Hsva, Hwba, Lcha, LinearRgba, Luminance, Mix, Srgba, StandardColor, Xyza,
44
};
5-
use bevy_math::{Vec3, Vec4};
5+
use bevy_math::{ops, FloatPow, Vec3, Vec4};
66
#[cfg(feature = "bevy_reflect")]
77
use bevy_reflect::prelude::*;
88

@@ -156,9 +156,9 @@ impl Luminance for Oklaba {
156156
impl EuclideanDistance for Oklaba {
157157
#[inline]
158158
fn distance_squared(&self, other: &Self) -> f32 {
159-
(self.lightness - other.lightness).powi(2)
160-
+ (self.a - other.a).powi(2)
161-
+ (self.b - other.b).powi(2)
159+
(self.lightness - other.lightness).squared()
160+
+ (self.a - other.a).squared()
161+
+ (self.b - other.b).squared()
162162
}
163163
}
164164

@@ -229,9 +229,9 @@ impl From<LinearRgba> for Oklaba {
229229
let l = 0.4122214708 * red + 0.5363325363 * green + 0.0514459929 * blue;
230230
let m = 0.2119034982 * red + 0.6806995451 * green + 0.1073969566 * blue;
231231
let s = 0.0883024619 * red + 0.2817188376 * green + 0.6299787005 * blue;
232-
let l_ = l.cbrt();
233-
let m_ = m.cbrt();
234-
let s_ = s.cbrt();
232+
let l_ = ops::cbrt(l);
233+
let m_ = ops::cbrt(m);
234+
let s_ = ops::cbrt(s);
235235
let l = 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_;
236236
let a = 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_;
237237
let b = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_;

crates/bevy_color/src/oklcha.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::{
22
color_difference::EuclideanDistance, Alpha, ColorToComponents, Gray, Hsla, Hsva, Hue, Hwba,
33
Laba, Lcha, LinearRgba, Luminance, Mix, Oklaba, Srgba, StandardColor, Xyza,
44
};
5-
use bevy_math::{Vec3, Vec4};
5+
use bevy_math::{ops, FloatPow, Vec3, Vec4};
66
#[cfg(feature = "bevy_reflect")]
77
use bevy_reflect::prelude::*;
88

@@ -191,9 +191,9 @@ impl Luminance for Oklcha {
191191
impl EuclideanDistance for Oklcha {
192192
#[inline]
193193
fn distance_squared(&self, other: &Self) -> f32 {
194-
(self.lightness - other.lightness).powi(2)
195-
+ (self.chroma - other.chroma).powi(2)
196-
+ (self.hue - other.hue).powi(2)
194+
(self.lightness - other.lightness).squared()
195+
+ (self.chroma - other.chroma).squared()
196+
+ (self.hue - other.hue).squared()
197197
}
198198
}
199199

@@ -260,8 +260,8 @@ impl From<Oklaba> for Oklcha {
260260
alpha,
261261
}: Oklaba,
262262
) -> Self {
263-
let chroma = a.hypot(b);
264-
let hue = b.atan2(a).to_degrees();
263+
let chroma = ops::hypot(a, b);
264+
let hue = ops::atan2(b, a).to_degrees();
265265

266266
let hue = if hue < 0.0 { hue + 360.0 } else { hue };
267267

@@ -279,8 +279,9 @@ impl From<Oklcha> for Oklaba {
279279
}: Oklcha,
280280
) -> Self {
281281
let l = lightness;
282-
let a = chroma * hue.to_radians().cos();
283-
let b = chroma * hue.to_radians().sin();
282+
let (sin, cos) = ops::sin_cos(hue.to_radians());
283+
let a = chroma * cos;
284+
let b = chroma * sin;
284285

285286
Oklaba::new(l, a, b, alpha)
286287
}

crates/bevy_color/src/srgba.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{
33
impl_componentwise_vector_space, Alpha, ColorToComponents, ColorToPacked, Gray, LinearRgba,
44
Luminance, Mix, StandardColor, Xyza,
55
};
6-
use bevy_math::{Vec3, Vec4};
6+
use bevy_math::{ops, Vec3, Vec4};
77
#[cfg(feature = "bevy_reflect")]
88
use bevy_reflect::prelude::*;
99
use thiserror::Error;
@@ -215,7 +215,7 @@ impl Srgba {
215215
if value <= 0.04045 {
216216
value / 12.92 // linear falloff in dark values
217217
} else {
218-
((value + 0.055) / 1.055).powf(2.4) // gamma curve in other area
218+
ops::powf((value + 0.055) / 1.055, 2.4) // gamma curve in other area
219219
}
220220
}
221221

@@ -228,7 +228,7 @@ impl Srgba {
228228
if value <= 0.0031308 {
229229
value * 12.92 // linear falloff in dark values
230230
} else {
231-
(1.055 * value.powf(1.0 / 2.4)) - 0.055 // gamma curve in other area
231+
(1.055 * ops::powf(value, 1.0 / 2.4)) - 0.055 // gamma curve in other area
232232
}
233233
}
234234
}

crates/bevy_core_pipeline/src/bloom/mod.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
use bevy_app::{App, Plugin};
1616
use bevy_asset::{load_internal_asset, Handle};
1717
use bevy_ecs::{prelude::*, query::QueryItem};
18-
use bevy_math::UVec2;
18+
use bevy_math::{ops, UVec2};
1919
use bevy_render::{
2020
camera::ExtractedCamera,
2121
diagnostic::RecordDiagnostics,
@@ -462,9 +462,11 @@ fn prepare_bloom_bind_groups(
462462
/// This function can be visually previewed for all values of *mip* (normalized) with tweakable
463463
/// [`Bloom`] parameters on [Desmos graphing calculator](https://www.desmos.com/calculator/ncc8xbhzzl).
464464
fn compute_blend_factor(bloom: &Bloom, mip: f32, max_mip: f32) -> f32 {
465-
let mut lf_boost = (1.0
466-
- (1.0 - (mip / max_mip)).powf(1.0 / (1.0 - bloom.low_frequency_boost_curvature)))
467-
* bloom.low_frequency_boost;
465+
let mut lf_boost =
466+
(1.0 - ops::powf(
467+
1.0 - (mip / max_mip),
468+
1.0 / (1.0 - bloom.low_frequency_boost_curvature),
469+
)) * bloom.low_frequency_boost;
468470
let high_pass_lq = 1.0
469471
- (((mip / max_mip) - bloom.high_pass_frequency) / bloom.high_pass_frequency)
470472
.clamp(0.0, 1.0);

crates/bevy_core_pipeline/src/dof/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use bevy_ecs::{
2626
system::{lifetimeless::Read, Commands, Query, Res, ResMut, Resource},
2727
world::{FromWorld, World},
2828
};
29+
use bevy_math::ops;
2930
use bevy_reflect::{prelude::ReflectDefault, Reflect};
3031
use bevy_render::{
3132
camera::{PhysicalCameraParameters, Projection},
@@ -848,7 +849,7 @@ fn extract_depth_of_field_settings(
848849
///
849850
/// See <https://photo.stackexchange.com/a/97218>.
850851
pub fn calculate_focal_length(sensor_height: f32, fov: f32) -> f32 {
851-
0.5 * sensor_height / f32::tan(0.5 * fov)
852+
0.5 * sensor_height / ops::tan(0.5 * fov)
852853
}
853854

854855
impl DepthOfFieldPipelines {

crates/bevy_ecs/src/query/iter.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
146146

147147
let range = range.unwrap_or(0..table.entity_count());
148148
accum =
149-
// SAFETY:
149+
// SAFETY:
150150
// - The fetched table matches both D and F
151151
// - caller ensures `range` is within `[0, table.entity_count)`
152152
// - The if block ensures that the query iteration is dense
@@ -2083,15 +2083,15 @@ mod tests {
20832083
let mut query = world.query::<&Sparse>();
20842084
let mut iter = query.iter(&world);
20852085
println!(
2086-
"before_next_call: archetype_entities: {} table_entities: {} current_len: {} current_row: {}",
2086+
"before_next_call: archetype_entities: {} table_entities: {} current_len: {} current_row: {}",
20872087
iter.cursor.archetype_entities.len(),
20882088
iter.cursor.table_entities.len(),
20892089
iter.cursor.current_len,
20902090
iter.cursor.current_row
20912091
);
20922092
_ = iter.next();
20932093
println!(
2094-
"after_next_call: archetype_entities: {} table_entities: {} current_len: {} current_row: {}",
2094+
"after_next_call: archetype_entities: {} table_entities: {} current_len: {} current_row: {}",
20952095
iter.cursor.archetype_entities.len(),
20962096
iter.cursor.table_entities.len(),
20972097
iter.cursor.current_len,
@@ -2108,15 +2108,15 @@ mod tests {
21082108
let mut query = world.query::<(&A, &Sparse)>();
21092109
let mut iter = query.iter(&world);
21102110
println!(
2111-
"before_next_call: archetype_entities: {} table_entities: {} current_len: {} current_row: {}",
2111+
"before_next_call: archetype_entities: {} table_entities: {} current_len: {} current_row: {}",
21122112
iter.cursor.archetype_entities.len(),
21132113
iter.cursor.table_entities.len(),
21142114
iter.cursor.current_len,
21152115
iter.cursor.current_row
21162116
);
21172117
_ = iter.next();
21182118
println!(
2119-
"after_next_call: archetype_entities: {} table_entities: {} current_len: {} current_row: {}",
2119+
"after_next_call: archetype_entities: {} table_entities: {} current_len: {} current_row: {}",
21202120
iter.cursor.archetype_entities.len(),
21212121
iter.cursor.table_entities.len(),
21222122
iter.cursor.current_len,
@@ -2136,7 +2136,7 @@ mod tests {
21362136
let mut query = world.query::<(&A, &Sparse)>();
21372137
let mut iter = query.iter(&world);
21382138
println!(
2139-
"before_next_call: archetype_entities: {} table_entities: {} current_len: {} current_row: {}",
2139+
"before_next_call: archetype_entities: {} table_entities: {} current_len: {} current_row: {}",
21402140
iter.cursor.archetype_entities.len(),
21412141
iter.cursor.table_entities.len(),
21422142
iter.cursor.current_len,
@@ -2145,7 +2145,7 @@ mod tests {
21452145
assert!(iter.cursor.table_entities.len() | iter.cursor.archetype_entities.len() == 0);
21462146
_ = iter.next();
21472147
println!(
2148-
"after_next_call: archetype_entities: {} table_entities: {} current_len: {} current_row: {}",
2148+
"after_next_call: archetype_entities: {} table_entities: {} current_len: {} current_row: {}",
21492149
iter.cursor.archetype_entities.len(),
21502150
iter.cursor.table_entities.len(),
21512151
iter.cursor.current_len,

0 commit comments

Comments
 (0)