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