1 | // Copyright 2006 The Android Open Source Project |
2 | // Copyright 2020 Yevhenii Reizner |
3 | // |
4 | // Use of this source code is governed by a BSD-style license that can be |
5 | // found in the LICENSE file. |
6 | |
7 | use crate::scalar::Scalar; |
8 | |
9 | pub use strict_num::{FiniteF32, NonZeroPositiveF32, NormalizedF32}; |
10 | |
11 | #[cfg (all(not(feature = "std" ), feature = "no-std-float" ))] |
12 | use crate::NoStdFloat; |
13 | |
14 | pub(crate) const FLOAT_PI: f32 = 3.14159265; |
15 | |
16 | const MAX_I32_FITS_IN_F32: f32 = 2147483520.0; |
17 | const MIN_I32_FITS_IN_F32: f32 = -MAX_I32_FITS_IN_F32; |
18 | |
19 | // TODO: is there an std alternative? |
20 | /// Custom float to integer conversion routines. |
21 | pub trait SaturateCast<T>: Sized { |
22 | /// Return the closest integer for the given float. |
23 | fn saturate_from(n: T) -> Self; |
24 | } |
25 | |
26 | impl SaturateCast<f32> for i32 { |
27 | /// Return the closest integer for the given float. |
28 | /// |
29 | /// Returns MAX_I32_FITS_IN_F32 for NaN. |
30 | fn saturate_from(mut x: f32) -> Self { |
31 | x = if x < MAX_I32_FITS_IN_F32 { |
32 | x |
33 | } else { |
34 | MAX_I32_FITS_IN_F32 |
35 | }; |
36 | x = if x > MIN_I32_FITS_IN_F32 { |
37 | x |
38 | } else { |
39 | MIN_I32_FITS_IN_F32 |
40 | }; |
41 | x as i32 |
42 | } |
43 | } |
44 | |
45 | impl SaturateCast<f64> for i32 { |
46 | /// Return the closest integer for the given double. |
47 | /// |
48 | /// Returns i32::MAX for NaN. |
49 | fn saturate_from(mut x: f64) -> Self { |
50 | x = if x < i32::MAX as f64 { |
51 | x |
52 | } else { |
53 | i32::MAX as f64 |
54 | }; |
55 | x = if x > i32::MIN as f64 { |
56 | x |
57 | } else { |
58 | i32::MIN as f64 |
59 | }; |
60 | x as i32 |
61 | } |
62 | } |
63 | |
64 | /// Custom float to integer rounding routines. |
65 | #[allow (missing_docs)] |
66 | pub trait SaturateRound<T>: SaturateCast<T> { |
67 | fn saturate_floor(n: T) -> Self; |
68 | fn saturate_ceil(n: T) -> Self; |
69 | fn saturate_round(n: T) -> Self; |
70 | } |
71 | |
72 | impl SaturateRound<f32> for i32 { |
73 | fn saturate_floor(x: f32) -> Self { |
74 | Self::saturate_from(x.floor()) |
75 | } |
76 | |
77 | fn saturate_ceil(x: f32) -> Self { |
78 | Self::saturate_from(x.ceil()) |
79 | } |
80 | |
81 | fn saturate_round(x: f32) -> Self { |
82 | Self::saturate_from(x.floor() + 0.5) |
83 | } |
84 | } |
85 | |
86 | /// Return the float as a 2s compliment int. Just to be used to compare floats |
87 | /// to each other or against positive float-bit-constants (like 0). This does |
88 | /// not return the int equivalent of the float, just something cheaper for |
89 | /// compares-only. |
90 | pub(crate) fn f32_as_2s_compliment(x: f32) -> i32 { |
91 | sign_bit_to_2s_compliment(bytemuck::cast(x)) |
92 | } |
93 | |
94 | /// Convert a sign-bit int (i.e. float interpreted as int) into a 2s compliement |
95 | /// int. This also converts -0 (0x80000000) to 0. Doing this to a float allows |
96 | /// it to be compared using normal C operators (<, <=, etc.) |
97 | fn sign_bit_to_2s_compliment(mut x: i32) -> i32 { |
98 | if x < 0 { |
99 | x &= 0x7FFFFFFF; |
100 | x = -x; |
101 | } |
102 | |
103 | x |
104 | } |
105 | |
106 | /// An immutable `f32` that is larger than 0 but less then 1. |
107 | #[derive (Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Debug)] |
108 | #[repr (transparent)] |
109 | pub struct NormalizedF32Exclusive(FiniteF32); |
110 | |
111 | impl NormalizedF32Exclusive { |
112 | /// Just a random, valid number. |
113 | pub const ANY: Self = Self::HALF; |
114 | |
115 | /// A predefined 0.5 value. |
116 | pub const HALF: Self = NormalizedF32Exclusive(unsafe { FiniteF32::new_unchecked(0.5) }); |
117 | |
118 | /// Creates a `NormalizedF32Exclusive`. |
119 | pub fn new(n: f32) -> Option<Self> { |
120 | if n > 0.0 && n < 1.0 { |
121 | // `n` is guarantee to be finite after the bounds check. |
122 | FiniteF32::new(n).map(NormalizedF32Exclusive) |
123 | } else { |
124 | None |
125 | } |
126 | } |
127 | |
128 | /// Creates a `NormalizedF32Exclusive` clamping the given value. |
129 | /// |
130 | /// Returns zero in case of NaN or infinity. |
131 | pub fn new_bounded(n: f32) -> Self { |
132 | let n = n.bound(f32::EPSILON, 1.0 - f32::EPSILON); |
133 | // `n` is guarantee to be finite after clamping. |
134 | debug_assert!(n.is_finite()); |
135 | NormalizedF32Exclusive(unsafe { FiniteF32::new_unchecked(n) }) |
136 | } |
137 | |
138 | /// Returns the value as a primitive type. |
139 | pub fn get(self) -> f32 { |
140 | self.0.get() |
141 | } |
142 | |
143 | /// Returns the value as a `FiniteF32`. |
144 | pub fn to_normalized(self) -> NormalizedF32 { |
145 | // NormalizedF32 is (0,1), while NormalizedF32 is [0,1], so it will always fit. |
146 | unsafe { NormalizedF32::new_unchecked(self.0.get()) } |
147 | } |
148 | } |
149 | |