1#![no_std]
20
21#[cfg(feature = "std")]
22extern crate std;
23
24pub trait WasmFloat {
25 fn wasm_trunc(self) -> Self;
26 fn wasm_copysign(self, sign: Self) -> Self;
27 fn wasm_floor(self) -> Self;
28 fn wasm_ceil(self) -> Self;
29 fn wasm_sqrt(self) -> Self;
30 fn wasm_abs(self) -> Self;
31 fn wasm_nearest(self) -> Self;
32 fn wasm_minimum(self, other: Self) -> Self;
33 fn wasm_maximum(self, other: Self) -> Self;
34 fn wasm_mul_add(self, b: Self, c: Self) -> Self;
35}
36
37impl WasmFloat for f32 {
38 #[inline]
39 fn wasm_trunc(self) -> f32 {
40 if self.is_nan() {
41 return f32::NAN;
42 }
43 #[cfg(feature = "std")]
44 if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
45 return self.trunc();
46 }
47 libm::truncf(self)
48 }
49 #[inline]
50 fn wasm_copysign(self, sign: f32) -> f32 {
51 #[cfg(feature = "std")]
52 if true {
53 return self.copysign(sign);
54 }
55 libm::copysignf(self, sign)
56 }
57 #[inline]
58 fn wasm_floor(self) -> f32 {
59 if self.is_nan() {
60 return f32::NAN;
61 }
62 #[cfg(feature = "std")]
63 if !cfg!(target_arch = "riscv64") {
64 return self.floor();
65 }
66 libm::floorf(self)
67 }
68 #[inline]
69 fn wasm_ceil(self) -> f32 {
70 if self.is_nan() {
71 return f32::NAN;
72 }
73 #[cfg(feature = "std")]
74 if !cfg!(target_arch = "riscv64") {
75 return self.ceil();
76 }
77 libm::ceilf(self)
78 }
79 #[inline]
80 fn wasm_sqrt(self) -> f32 {
81 #[cfg(feature = "std")]
82 if true {
83 return self.sqrt();
84 }
85 libm::sqrtf(self)
86 }
87 #[inline]
88 fn wasm_abs(self) -> f32 {
89 #[cfg(feature = "std")]
90 if true {
91 return self.abs();
92 }
93 libm::fabsf(self)
94 }
95 #[inline]
96 fn wasm_nearest(self) -> f32 {
97 if self.is_nan() {
98 return f32::NAN;
99 }
100 #[cfg(feature = "std")]
101 if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
102 return self.round_ties_even();
103 }
104 let round = libm::roundf(self);
105 if libm::fabsf(self - round) != 0.5 {
106 return round;
107 }
108 match round % 2.0 {
109 1.0 => libm::floorf(self),
110 -1.0 => libm::ceilf(self),
111 _ => round,
112 }
113 }
114 #[inline]
115 fn wasm_maximum(self, other: f32) -> f32 {
116 if self > other {
119 self
120 } else if other > self {
121 other
122 } else if self == other {
123 if self.is_sign_positive() && other.is_sign_negative() {
124 self
125 } else {
126 other
127 }
128 } else {
129 self + other
130 }
131 }
132 #[inline]
133 fn wasm_minimum(self, other: f32) -> f32 {
134 if self < other {
137 self
138 } else if other < self {
139 other
140 } else if self == other {
141 if self.is_sign_negative() && other.is_sign_positive() {
142 self
143 } else {
144 other
145 }
146 } else {
147 self + other
148 }
149 }
150 #[inline]
151 fn wasm_mul_add(self, b: f32, c: f32) -> f32 {
152 #[cfg(feature = "std")]
155 if !(cfg!(windows) && cfg!(target_env = "gnu")) {
156 return self.mul_add(b, c);
157 }
158 libm::fmaf(self, b, c)
159 }
160}
161
162impl WasmFloat for f64 {
163 #[inline]
164 fn wasm_trunc(self) -> f64 {
165 if self.is_nan() {
166 return f64::NAN;
167 }
168 #[cfg(feature = "std")]
169 if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
170 return self.trunc();
171 }
172 libm::trunc(self)
173 }
174 #[inline]
175 fn wasm_copysign(self, sign: f64) -> f64 {
176 #[cfg(feature = "std")]
177 if true {
178 return self.copysign(sign);
179 }
180 libm::copysign(self, sign)
181 }
182 #[inline]
183 fn wasm_floor(self) -> f64 {
184 if self.is_nan() {
185 return f64::NAN;
186 }
187 #[cfg(feature = "std")]
188 if !cfg!(target_arch = "riscv64") {
189 return self.floor();
190 }
191 libm::floor(self)
192 }
193 #[inline]
194 fn wasm_ceil(self) -> f64 {
195 if self.is_nan() {
196 return f64::NAN;
197 }
198 #[cfg(feature = "std")]
199 if !cfg!(target_arch = "riscv64") {
200 return self.ceil();
201 }
202 libm::ceil(self)
203 }
204 #[inline]
205 fn wasm_sqrt(self) -> f64 {
206 #[cfg(feature = "std")]
207 if true {
208 return self.sqrt();
209 }
210 libm::sqrt(self)
211 }
212 #[inline]
213 fn wasm_abs(self) -> f64 {
214 #[cfg(feature = "std")]
215 if true {
216 return self.abs();
217 }
218 libm::fabs(self)
219 }
220 #[inline]
221 fn wasm_nearest(self) -> f64 {
222 if self.is_nan() {
223 return f64::NAN;
224 }
225 #[cfg(feature = "std")]
226 if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
227 return self.round_ties_even();
228 }
229 let round = libm::round(self);
230 if libm::fabs(self - round) != 0.5 {
231 return round;
232 }
233 match round % 2.0 {
234 1.0 => libm::floor(self),
235 -1.0 => libm::ceil(self),
236 _ => round,
237 }
238 }
239 #[inline]
240 fn wasm_maximum(self, other: f64) -> f64 {
241 if self > other {
244 self
245 } else if other > self {
246 other
247 } else if self == other {
248 if self.is_sign_positive() && other.is_sign_negative() {
249 self
250 } else {
251 other
252 }
253 } else {
254 self + other
255 }
256 }
257 #[inline]
258 fn wasm_minimum(self, other: f64) -> f64 {
259 if self < other {
262 self
263 } else if other < self {
264 other
265 } else if self == other {
266 if self.is_sign_negative() && other.is_sign_positive() {
267 self
268 } else {
269 other
270 }
271 } else {
272 self + other
273 }
274 }
275 #[inline]
276 fn wasm_mul_add(self, b: f64, c: f64) -> f64 {
277 #[cfg(feature = "std")]
280 if !(cfg!(windows) && cfg!(target_env = "gnu")) {
281 return self.mul_add(b, c);
282 }
283 libm::fma(self, b, c)
284 }
285}