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 #[cfg(feature = "std")]
41 if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
42 return self.trunc();
43 }
44 if self.is_nan() {
45 return f32::NAN;
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 #[cfg(feature = "std")]
60 if !cfg!(target_arch = "riscv64") {
61 return self.floor();
62 }
63 if self.is_nan() {
64 return f32::NAN;
65 }
66 libm::floorf(self)
67 }
68 #[inline]
69 fn wasm_ceil(self) -> f32 {
70 #[cfg(feature = "std")]
71 if !cfg!(target_arch = "riscv64") {
72 return self.ceil();
73 }
74 if self.is_nan() {
75 return f32::NAN;
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 #[cfg(feature = "std")]
98 if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
99 return self.round_ties_even();
100 }
101 if self.is_nan() {
102 return f32::NAN;
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 #[cfg(feature = "std")]
166 if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
167 return self.trunc();
168 }
169 if self.is_nan() {
170 return f64::NAN;
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 #[cfg(feature = "std")]
185 if !cfg!(target_arch = "riscv64") {
186 return self.floor();
187 }
188 if self.is_nan() {
189 return f64::NAN;
190 }
191 libm::floor(self)
192 }
193 #[inline]
194 fn wasm_ceil(self) -> f64 {
195 #[cfg(feature = "std")]
196 if !cfg!(target_arch = "riscv64") {
197 return self.ceil();
198 }
199 if self.is_nan() {
200 return f64::NAN;
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 #[cfg(feature = "std")]
223 if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
224 return self.round_ties_even();
225 }
226 if self.is_nan() {
227 return f64::NAN;
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}