1use core::arch::asm;
16
17static POW10: [f64; 23] = [
18 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17,
19 1e18, 1e19, 1e20, 1e21, 1e22,
20];
21
22pub fn scale(m: u64, e: i32) -> f64 {
24 let mi = m as i64;
25 let mut out = 0f64;
26 let mut cw = [0u16; 2];
27 unsafe {
30 asm!(
31 "fnstcw word ptr [{cw}]",
32 "movzx {t:e}, word ptr [{cw}]",
33 "and {t:e}, 0xF3FF",
34 "or {t:e}, 0x0300",
35 "mov word ptr [{cw} + 2], {t:x}",
36 "fldcw word ptr [{cw} + 2]",
37 "fld1",
38 "2:",
39 "cmp {n:e}, 22",
40 "jbe 3f",
41 "fmul qword ptr [{tab} + 176]",
42 "sub {n:e}, 22",
43 "jmp 2b",
44 "3:",
45 "fmul qword ptr [{tab} + {n} * 8]",
46 "fild qword ptr [{m}]",
47 "test {neg:e}, {neg:e}",
48 "jnz 4f",
49 "fmul st(0), st(1)",
50 "jmp 5f",
51 "4:",
52 "fdiv st(0), st(1)",
53 "5:",
54 "fstp st(1)",
55 "fstp qword ptr [{out}]",
56 "fldcw word ptr [{cw}]",
57 cw = in(reg) cw.as_mut_ptr(),
58 t = out(reg) _,
59 n = inout(reg) e.clamp(-5000, 5000).unsigned_abs() as u64 => _,
60 tab = in(reg) POW10.as_ptr(),
61 m = in(reg) &mi,
62 neg = in(reg) (e < 0) as u32,
63 out = in(reg) &mut out,
64 out("st(0)") _, out("st(1)") _, out("st(2)") _, out("st(3)") _,
65 out("st(4)") _, out("st(5)") _, out("st(6)") _, out("st(7)") _,
66 );
67 }
68 out
69}
70
71pub fn scale_round(v: f64, k: i32) -> i64 {
73 let mut out = 0i64;
74 let mut cw = [0u16; 2];
75 unsafe {
77 asm!(
78 "fnstcw word ptr [{cw}]",
79 "movzx {t:e}, word ptr [{cw}]",
80 "and {t:e}, 0xF3FF",
81 "or {t:e}, 0x0300",
82 "mov word ptr [{cw} + 2], {t:x}",
83 "fldcw word ptr [{cw} + 2]",
84 "fld1",
85 "2:",
86 "cmp {n:e}, 22",
87 "jbe 3f",
88 "fmul qword ptr [{tab} + 176]",
89 "sub {n:e}, 22",
90 "jmp 2b",
91 "3:",
92 "fmul qword ptr [{tab} + {n} * 8]",
93 "fld qword ptr [{v}]",
94 "test {neg:e}, {neg:e}",
95 "jnz 4f",
96 "fmul st(0), st(1)",
97 "jmp 5f",
98 "4:",
99 "fdiv st(0), st(1)",
100 "5:",
101 "fstp st(1)",
102 "frndint",
103 "fistp qword ptr [{out}]",
104 "fldcw word ptr [{cw}]",
105 cw = in(reg) cw.as_mut_ptr(),
106 t = out(reg) _,
107 n = inout(reg) k.clamp(-5000, 5000).unsigned_abs() as u64 => _,
108 tab = in(reg) POW10.as_ptr(),
109 v = in(reg) &v,
110 neg = in(reg) (k < 0) as u32,
111 out = in(reg) &mut out,
112 out("st(0)") _, out("st(1)") _, out("st(2)") _, out("st(3)") _,
113 out("st(4)") _, out("st(5)") _, out("st(6)") _, out("st(7)") _,
114 );
115 }
116 out
117}
118
119pub fn log10_round(v: f64) -> i32 {
121 let mut out = 0i32;
122 let mut cw = [0u16; 2];
123 unsafe {
125 asm!(
126 "fnstcw word ptr [{cw}]",
127 "movzx {t:e}, word ptr [{cw}]",
128 "and {t:e}, 0xF3FF",
129 "or {t:e}, 0x0300",
130 "mov word ptr [{cw} + 2], {t:x}",
131 "fldcw word ptr [{cw} + 2]",
132 "fldlg2",
133 "fld qword ptr [{v}]",
134 "fyl2x",
135 "fistp dword ptr [{out}]",
136 "fldcw word ptr [{cw}]",
137 cw = in(reg) cw.as_mut_ptr(),
138 t = out(reg) _,
139 v = in(reg) &v,
140 out = in(reg) &mut out,
141 out("st(0)") _, out("st(1)") _, out("st(2)") _, out("st(3)") _,
142 out("st(4)") _, out("st(5)") _, out("st(6)") _, out("st(7)") _,
143 );
144 }
145 out
146}
147
148pub fn atan2(y: f64, x: f64) -> f64 {
151 let mut out = 0f64;
152 unsafe {
154 asm!(
155 "fld qword ptr [{y}]",
156 "fld qword ptr [{x}]",
157 "fpatan",
158 "fstp qword ptr [{out}]",
159 y = in(reg) &y,
160 x = in(reg) &x,
161 out = in(reg) &mut out,
162 out("st(0)") _, out("st(1)") _, out("st(2)") _, out("st(3)") _,
163 out("st(4)") _, out("st(5)") _, out("st(6)") _, out("st(7)") _,
164 );
165 }
166 out
167}
168
169pub fn sincos(x: f64) -> (f64, f64) {
173 let mut c = 0f64;
174 let mut s = 0f64;
175 unsafe {
177 asm!(
178 "fld qword ptr [{x}]",
179 "fsincos",
180 "fstp qword ptr [{c}]",
181 "fstp qword ptr [{s}]",
182 x = in(reg) &x,
183 c = in(reg) &mut c,
184 s = in(reg) &mut s,
185 out("st(0)") _, out("st(1)") _, out("st(2)") _, out("st(3)") _,
186 out("st(4)") _, out("st(5)") _, out("st(6)") _, out("st(7)") _,
187 );
188 }
189 (c, s)
190}
191
192pub fn pow(x: f64, y: f64) -> f64 {
197 const NAN: u64 = 0x7FF8000000000000;
198 if y.is_nan() {
199 return f64::from_bits(NAN);
200 }
201 if y == 0.0 {
202 return 1.0;
203 }
204 if x.is_nan() {
205 return f64::from_bits(NAN);
206 }
207 if x <= 0.0 {
208 return 0.0;
209 }
210 if y == 1.0 {
211 return x;
212 }
213 let mut out = 0f64;
214 let mut cw = [0u16; 2];
215 unsafe {
218 asm!(
219 "fnstcw word ptr [{cw}]",
220 "movzx {t:e}, word ptr [{cw}]",
221 "and {t:e}, 0xF3FF",
222 "or {t:e}, 0x0300",
223 "mov word ptr [{cw} + 2], {t:x}",
224 "fldcw word ptr [{cw} + 2]",
225 "fld qword ptr [{y}]",
226 "fld qword ptr [{x}]",
227 "fyl2x",
228 "fld st(0)",
229 "frndint",
230 "fsub st(1), st(0)",
231 "fxch",
232 "f2xm1",
233 "fld1",
234 "faddp",
235 "fscale",
236 "fstp st(1)",
237 "fstp qword ptr [{out}]",
238 "fldcw word ptr [{cw}]",
239 cw = in(reg) cw.as_mut_ptr(),
240 t = out(reg) _,
241 x = in(reg) &x,
242 y = in(reg) &y,
243 out = in(reg) &mut out,
244 out("st(0)") _, out("st(1)") _, out("st(2)") _, out("st(3)") _,
245 out("st(4)") _, out("st(5)") _, out("st(6)") _, out("st(7)") _,
246 );
247 }
248 out
249}
250
251pub fn rz_log2(x: f64) -> f64 {
255 let mut out = 0f64;
256 unsafe {
258 asm!(
259 "fld1",
260 "fld qword ptr [{x}]",
261 "fyl2x",
262 "fstp qword ptr [{out}]",
263 x = in(reg) &x,
264 out = in(reg) &mut out,
265 out("st(0)") _, out("st(1)") _, out("st(2)") _, out("st(3)") _,
266 out("st(4)") _, out("st(5)") _, out("st(6)") _, out("st(7)") _,
267 );
268 }
269 out
270}
271
272pub fn rz_exp2(x: f64) -> f64 {
277 let i = crate::fx::cvtd(x);
278 let f = x - i as f64;
279 let mut out = 0f64;
280 unsafe {
282 asm!(
283 "fild dword ptr [{i}]",
284 "fld qword ptr [{f}]",
285 "f2xm1",
286 "fld1",
287 "faddp",
288 "fscale",
289 "fstp qword ptr [{out}]",
290 "fstp st(0)",
291 i = in(reg) &i,
292 f = in(reg) &f,
293 out = in(reg) &mut out,
294 out("st(0)") _, out("st(1)") _, out("st(2)") _, out("st(3)") _,
295 out("st(4)") _, out("st(5)") _, out("st(6)") _, out("st(7)") _,
296 );
297 }
298 out
299}
300
301macro_rules! x87_unary {
305 ($(#[$m:meta])* $name:ident, $($ins:literal),*) => {
306 $(#[$m])*
307 pub fn $name(x: f64) -> f64 {
308 let mut out = 0f64;
309 let mut cw = [0u16; 2];
310 unsafe {
313 asm!(
314 "fnstcw word ptr [{cw}]",
315 "movzx {t:e}, word ptr [{cw}]",
316 "and {t:e}, 0xF3FF",
317 "or {t:e}, 0x0300",
318 "mov word ptr [{cw} + 2], {t:x}",
319 "fldcw word ptr [{cw} + 2]",
320 $($ins,)*
321 "fstp qword ptr [{out}]",
322 "fldcw word ptr [{cw}]",
323 cw = in(reg) cw.as_mut_ptr(),
324 t = out(reg) _,
325 x = in(reg) &x,
326 out = in(reg) &mut out,
327 out("st(0)") _, out("st(1)") _, out("st(2)") _, out("st(3)") _,
328 out("st(4)") _, out("st(5)") _, out("st(6)") _, out("st(7)") _,
329 );
330 }
331 out
332 }
333 };
334}
335
336x87_unary!(
337 exp2, "fld qword ptr [{x}]", "fld st(0)", "frndint", "fsub st(1), st(0)", "fxch", "f2xm1", "fld1",
339 "faddp", "fscale", "fstp st(1)"
340);
341x87_unary!(
342 log2, "fld1", "fld qword ptr [{x}]", "fyl2x"
344);
345x87_unary!(
346 cos, "fld qword ptr [{x}]", "fcos"
348);
349x87_unary!(
350 sin, "fld qword ptr [{x}]", "fsin"
352);