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::floating_point::f32_as_2s_compliment; |
8 | |
9 | #[allow (missing_docs)] |
10 | pub const SCALAR_MAX: f32 = 3.402823466e+38; |
11 | #[allow (missing_docs)] |
12 | pub const SCALAR_NEARLY_ZERO: f32 = 1.0 / (1 << 12) as f32; |
13 | #[allow (missing_docs)] |
14 | pub const SCALAR_ROOT_2_OVER_2: f32 = 0.707106781; |
15 | |
16 | /// Float number extension methods. |
17 | /// |
18 | /// Mainly for internal use. Do not rely on it! |
19 | #[allow (missing_docs)] |
20 | pub trait Scalar { |
21 | fn half(self) -> Self; |
22 | fn ave(self, other: Self) -> Self; |
23 | fn sqr(self) -> Self; |
24 | fn invert(self) -> Self; |
25 | fn bound(self, min: Self, max: Self) -> Self; |
26 | fn is_nearly_equal(self, other: Self) -> bool; |
27 | fn is_nearly_zero(self) -> bool; |
28 | fn is_nearly_zero_within_tolerance(self, tolerance: Self) -> bool; |
29 | fn almost_dequal_ulps(self, other: Self) -> bool; |
30 | } |
31 | |
32 | impl Scalar for f32 { |
33 | fn half(self) -> f32 { |
34 | self * 0.5 |
35 | } |
36 | |
37 | fn ave(self, other: Self) -> f32 { |
38 | (self + other) * 0.5 |
39 | } |
40 | |
41 | fn sqr(self) -> f32 { |
42 | self * self |
43 | } |
44 | |
45 | fn invert(self) -> f32 { |
46 | 1.0 / self |
47 | } |
48 | |
49 | // Works just like SkTPin, returning `max` for NaN/inf |
50 | /// A non-panicking clamp. |
51 | fn bound(self, min: Self, max: Self) -> Self { |
52 | max.min(self).max(min) |
53 | } |
54 | |
55 | fn is_nearly_equal(self, other: Self) -> bool { |
56 | (self - other).abs() <= SCALAR_NEARLY_ZERO |
57 | } |
58 | |
59 | fn is_nearly_zero(self) -> bool { |
60 | self.is_nearly_zero_within_tolerance(SCALAR_NEARLY_ZERO) |
61 | } |
62 | |
63 | fn is_nearly_zero_within_tolerance(self, tolerance: Self) -> bool { |
64 | debug_assert!(tolerance >= 0.0); |
65 | self.abs() <= tolerance |
66 | } |
67 | |
68 | // From SkPathOpsTypes. |
69 | fn almost_dequal_ulps(self, other: Self) -> bool { |
70 | const ULPS_EPSILON: i32 = 16; |
71 | let a_bits = f32_as_2s_compliment(self); |
72 | let b_bits = f32_as_2s_compliment(other); |
73 | // Find the difference in ULPs. |
74 | a_bits < b_bits + ULPS_EPSILON && b_bits < a_bits + ULPS_EPSILON |
75 | } |
76 | } |
77 | |
78 | #[allow (missing_docs)] |
79 | #[cfg (all(not(feature = "std" ), feature = "no-std-float" ))] |
80 | pub trait NoStdFloat { |
81 | fn trunc(self) -> Self; |
82 | fn sqrt(self) -> Self; |
83 | fn abs(self) -> Self; |
84 | fn sin(self) -> Self; |
85 | fn cos(self) -> Self; |
86 | fn ceil(self) -> Self; |
87 | fn floor(self) -> Self; |
88 | fn round(self) -> Self; |
89 | fn powf(self, y: Self) -> Self; |
90 | fn acos(self) -> Self; |
91 | } |
92 | |
93 | #[cfg (all(not(feature = "std" ), feature = "no-std-float" ))] |
94 | impl NoStdFloat for f32 { |
95 | fn trunc(self) -> Self { |
96 | libm::truncf(self) |
97 | } |
98 | fn sqrt(self) -> Self { |
99 | libm::sqrtf(self) |
100 | } |
101 | fn abs(self) -> Self { |
102 | libm::fabsf(self) |
103 | } |
104 | fn sin(self) -> Self { |
105 | libm::sinf(self) |
106 | } |
107 | fn cos(self) -> Self { |
108 | libm::cosf(self) |
109 | } |
110 | fn ceil(self) -> Self { |
111 | libm::ceilf(self) |
112 | } |
113 | fn floor(self) -> Self { |
114 | libm::floorf(self) |
115 | } |
116 | fn round(self) -> Self { |
117 | libm::roundf(self) |
118 | } |
119 | fn powf(self, y: Self) -> Self { |
120 | libm::powf(self, y) |
121 | } |
122 | fn acos(self) -> Self { |
123 | libm::acosf(self) |
124 | } |
125 | } |
126 | |
127 | #[cfg (all(not(feature = "std" ), feature = "no-std-float" ))] |
128 | impl NoStdFloat for f64 { |
129 | fn trunc(self) -> Self { |
130 | libm::trunc(self) |
131 | } |
132 | fn sqrt(self) -> Self { |
133 | libm::sqrt(self) |
134 | } |
135 | fn abs(self) -> Self { |
136 | libm::fabs(self) |
137 | } |
138 | fn sin(self) -> Self { |
139 | libm::sin(self) |
140 | } |
141 | fn cos(self) -> Self { |
142 | libm::cos(self) |
143 | } |
144 | fn ceil(self) -> Self { |
145 | libm::ceil(self) |
146 | } |
147 | fn floor(self) -> Self { |
148 | libm::floor(self) |
149 | } |
150 | fn round(self) -> Self { |
151 | libm::round(self) |
152 | } |
153 | fn powf(self, y: Self) -> Self { |
154 | libm::pow(self, y) |
155 | } |
156 | fn acos(self) -> Self { |
157 | libm::acos(self) |
158 | } |
159 | } |
160 | |
161 | #[cfg (test)] |
162 | mod tests { |
163 | use super::*; |
164 | |
165 | #[test ] |
166 | fn bound() { |
167 | assert_eq!(f32::NAN.bound(0.0, 1.0), 1.0); |
168 | assert_eq!(f32::INFINITY.bound(0.0, 1.0), 1.0); |
169 | assert_eq!(f32::NEG_INFINITY.bound(0.0, 1.0), 0.0); |
170 | assert_eq!(f32::EPSILON.bound(0.0, 1.0), f32::EPSILON); |
171 | assert_eq!(0.5.bound(0.0, 1.0), 0.5); |
172 | assert_eq!((-1.0).bound(0.0, 1.0), 0.0); |
173 | assert_eq!(2.0.bound(0.0, 1.0), 1.0); |
174 | } |
175 | } |
176 | |