1#![allow(missing_docs, reason = "self-describing methods")]
27
28pub const fn f32_cvt_to_int_bounds(signed: bool, out_bits: u32) -> (f32, f32) {
41 match (signed, out_bits) {
42 (true, 8) => (i8::min_value() as f32 - 1., i8::max_value() as f32 + 1.),
43 (true, 16) => (i16::min_value() as f32 - 1., i16::max_value() as f32 + 1.),
44 (true, 32) => (-2147483904.0, 2147483648.0),
45 (true, 64) => (-9223373136366403584.0, 9223372036854775808.0),
46 (false, 8) => (-1., u8::max_value() as f32 + 1.),
47 (false, 16) => (-1., u16::max_value() as f32 + 1.),
48 (false, 32) => (-1., 4294967296.0),
49 (false, 64) => (-1., 18446744073709551616.0),
50 _ => unreachable!(),
51 }
52}
53
54pub const fn f64_cvt_to_int_bounds(signed: bool, out_bits: u32) -> (f64, f64) {
56 match (signed, out_bits) {
57 (true, 8) => (i8::min_value() as f64 - 1., i8::max_value() as f64 + 1.),
58 (true, 16) => (i16::min_value() as f64 - 1., i16::max_value() as f64 + 1.),
59 (true, 32) => (-2147483649.0, 2147483648.0),
60 (true, 64) => (-9223372036854777856.0, 9223372036854775808.0),
61 (false, 8) => (-1., u8::max_value() as f64 + 1.),
62 (false, 16) => (-1., u16::max_value() as f64 + 1.),
63 (false, 32) => (-1., 4294967296.0),
64 (false, 64) => (-1., 18446744073709551616.0),
65 _ => unreachable!(),
66 }
67}
68
69pub trait WasmFloat {
70 fn wasm_trunc(self) -> Self;
71 fn wasm_copysign(self, sign: Self) -> Self;
72 fn wasm_floor(self) -> Self;
73 fn wasm_ceil(self) -> Self;
74 fn wasm_sqrt(self) -> Self;
75 fn wasm_abs(self) -> Self;
76 fn wasm_nearest(self) -> Self;
77 fn wasm_minimum(self, other: Self) -> Self;
78 fn wasm_maximum(self, other: Self) -> Self;
79 fn wasm_mul_add(self, b: Self, c: Self) -> Self;
80}
81
82impl WasmFloat for f32 {
83 #[inline]
84 fn wasm_trunc(self) -> f32 {
85 if self.is_nan() {
86 return f32::NAN;
87 }
88 #[cfg(feature = "std")]
89 if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
90 return self.trunc();
91 }
92 libm::truncf(self)
93 }
94 #[inline]
95 fn wasm_copysign(self, sign: f32) -> f32 {
96 #[cfg(feature = "std")]
97 if true {
98 return self.copysign(sign);
99 }
100 libm::copysignf(self, sign)
101 }
102 #[inline]
103 fn wasm_floor(self) -> f32 {
104 if self.is_nan() {
105 return f32::NAN;
106 }
107 #[cfg(feature = "std")]
108 if !cfg!(target_arch = "riscv64") {
109 return self.floor();
110 }
111 libm::floorf(self)
112 }
113 #[inline]
114 fn wasm_ceil(self) -> f32 {
115 if self.is_nan() {
116 return f32::NAN;
117 }
118 #[cfg(feature = "std")]
119 if !cfg!(target_arch = "riscv64") {
120 return self.ceil();
121 }
122 libm::ceilf(self)
123 }
124 #[inline]
125 fn wasm_sqrt(self) -> f32 {
126 #[cfg(feature = "std")]
127 if true {
128 return self.sqrt();
129 }
130 libm::sqrtf(self)
131 }
132 #[inline]
133 fn wasm_abs(self) -> f32 {
134 #[cfg(feature = "std")]
135 if true {
136 return self.abs();
137 }
138 libm::fabsf(self)
139 }
140 #[inline]
141 fn wasm_nearest(self) -> f32 {
142 if self.is_nan() {
143 return f32::NAN;
144 }
145 #[cfg(feature = "std")]
146 if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
147 return self.round_ties_even();
148 }
149 let round = libm::roundf(self);
150 if libm::fabsf(self - round) != 0.5 {
151 return round;
152 }
153 match round % 2.0 {
154 1.0 => libm::floorf(self),
155 -1.0 => libm::ceilf(self),
156 _ => round,
157 }
158 }
159 #[inline]
160 fn wasm_maximum(self, other: f32) -> f32 {
161 if self > other {
164 self
165 } else if other > self {
166 other
167 } else if self == other {
168 if self.is_sign_positive() && other.is_sign_negative() {
169 self
170 } else {
171 other
172 }
173 } else {
174 self + other
175 }
176 }
177 #[inline]
178 fn wasm_minimum(self, other: f32) -> f32 {
179 if self < other {
182 self
183 } else if other < self {
184 other
185 } else if self == other {
186 if self.is_sign_negative() && other.is_sign_positive() {
187 self
188 } else {
189 other
190 }
191 } else {
192 self + other
193 }
194 }
195 #[inline]
196 fn wasm_mul_add(self, b: f32, c: f32) -> f32 {
197 #[cfg(feature = "std")]
200 if !(cfg!(windows) && cfg!(target_env = "gnu")) {
201 return self.mul_add(b, c);
202 }
203 libm::fmaf(self, b, c)
204 }
205}
206
207impl WasmFloat for f64 {
208 #[inline]
209 fn wasm_trunc(self) -> f64 {
210 if self.is_nan() {
211 return f64::NAN;
212 }
213 #[cfg(feature = "std")]
214 if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
215 return self.trunc();
216 }
217 libm::trunc(self)
218 }
219 #[inline]
220 fn wasm_copysign(self, sign: f64) -> f64 {
221 #[cfg(feature = "std")]
222 if true {
223 return self.copysign(sign);
224 }
225 libm::copysign(self, sign)
226 }
227 #[inline]
228 fn wasm_floor(self) -> f64 {
229 if self.is_nan() {
230 return f64::NAN;
231 }
232 #[cfg(feature = "std")]
233 if !cfg!(target_arch = "riscv64") {
234 return self.floor();
235 }
236 libm::floor(self)
237 }
238 #[inline]
239 fn wasm_ceil(self) -> f64 {
240 if self.is_nan() {
241 return f64::NAN;
242 }
243 #[cfg(feature = "std")]
244 if !cfg!(target_arch = "riscv64") {
245 return self.ceil();
246 }
247 libm::ceil(self)
248 }
249 #[inline]
250 fn wasm_sqrt(self) -> f64 {
251 #[cfg(feature = "std")]
252 if true {
253 return self.sqrt();
254 }
255 libm::sqrt(self)
256 }
257 #[inline]
258 fn wasm_abs(self) -> f64 {
259 #[cfg(feature = "std")]
260 if true {
261 return self.abs();
262 }
263 libm::fabs(self)
264 }
265 #[inline]
266 fn wasm_nearest(self) -> f64 {
267 if self.is_nan() {
268 return f64::NAN;
269 }
270 #[cfg(feature = "std")]
271 if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
272 return self.round_ties_even();
273 }
274 let round = libm::round(self);
275 if libm::fabs(self - round) != 0.5 {
276 return round;
277 }
278 match round % 2.0 {
279 1.0 => libm::floor(self),
280 -1.0 => libm::ceil(self),
281 _ => round,
282 }
283 }
284 #[inline]
285 fn wasm_maximum(self, other: f64) -> f64 {
286 if self > other {
289 self
290 } else if other > self {
291 other
292 } else if self == other {
293 if self.is_sign_positive() && other.is_sign_negative() {
294 self
295 } else {
296 other
297 }
298 } else {
299 self + other
300 }
301 }
302 #[inline]
303 fn wasm_minimum(self, other: f64) -> f64 {
304 if self < other {
307 self
308 } else if other < self {
309 other
310 } else if self == other {
311 if self.is_sign_negative() && other.is_sign_positive() {
312 self
313 } else {
314 other
315 }
316 } else {
317 self + other
318 }
319 }
320 #[inline]
321 fn wasm_mul_add(self, b: f64, c: f64) -> f64 {
322 #[cfg(feature = "std")]
325 if !(cfg!(windows) && cfg!(target_env = "gnu")) {
326 return self.mul_add(b, c);
327 }
328 libm::fma(self, b, c)
329 }
330}