numkong 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +495 -0
- package/binding.gyp +540 -0
- package/c/dispatch.h +512 -0
- package/c/dispatch_bf16.c +389 -0
- package/c/dispatch_bf16c.c +52 -0
- package/c/dispatch_e2m3.c +263 -0
- package/c/dispatch_e3m2.c +243 -0
- package/c/dispatch_e4m3.c +276 -0
- package/c/dispatch_e5m2.c +272 -0
- package/c/dispatch_f16.c +376 -0
- package/c/dispatch_f16c.c +58 -0
- package/c/dispatch_f32.c +378 -0
- package/c/dispatch_f32c.c +99 -0
- package/c/dispatch_f64.c +296 -0
- package/c/dispatch_f64c.c +98 -0
- package/c/dispatch_i16.c +96 -0
- package/c/dispatch_i32.c +89 -0
- package/c/dispatch_i4.c +150 -0
- package/c/dispatch_i64.c +86 -0
- package/c/dispatch_i8.c +289 -0
- package/c/dispatch_other.c +330 -0
- package/c/dispatch_u1.c +148 -0
- package/c/dispatch_u16.c +124 -0
- package/c/dispatch_u32.c +118 -0
- package/c/dispatch_u4.c +150 -0
- package/c/dispatch_u64.c +102 -0
- package/c/dispatch_u8.c +303 -0
- package/c/numkong.c +950 -0
- package/include/README.md +573 -0
- package/include/module.modulemap +129 -0
- package/include/numkong/attention/sapphireamx.h +1361 -0
- package/include/numkong/attention/sme.h +2066 -0
- package/include/numkong/attention.h +49 -0
- package/include/numkong/capabilities.h +748 -0
- package/include/numkong/cast/README.md +262 -0
- package/include/numkong/cast/haswell.h +975 -0
- package/include/numkong/cast/icelake.h +470 -0
- package/include/numkong/cast/neon.h +1192 -0
- package/include/numkong/cast/rvv.h +1021 -0
- package/include/numkong/cast/sapphire.h +262 -0
- package/include/numkong/cast/serial.h +2262 -0
- package/include/numkong/cast/skylake.h +856 -0
- package/include/numkong/cast/v128relaxed.h +180 -0
- package/include/numkong/cast.h +230 -0
- package/include/numkong/curved/README.md +223 -0
- package/include/numkong/curved/genoa.h +182 -0
- package/include/numkong/curved/haswell.h +276 -0
- package/include/numkong/curved/neon.h +205 -0
- package/include/numkong/curved/neonbfdot.h +212 -0
- package/include/numkong/curved/neonhalf.h +212 -0
- package/include/numkong/curved/rvv.h +305 -0
- package/include/numkong/curved/serial.h +207 -0
- package/include/numkong/curved/skylake.h +457 -0
- package/include/numkong/curved/smef64.h +506 -0
- package/include/numkong/curved.h +517 -0
- package/include/numkong/curved.hpp +144 -0
- package/include/numkong/dot/README.md +425 -0
- package/include/numkong/dot/alder.h +563 -0
- package/include/numkong/dot/genoa.h +315 -0
- package/include/numkong/dot/haswell.h +1688 -0
- package/include/numkong/dot/icelake.h +883 -0
- package/include/numkong/dot/neon.h +818 -0
- package/include/numkong/dot/neonbfdot.h +244 -0
- package/include/numkong/dot/neonfhm.h +360 -0
- package/include/numkong/dot/neonhalf.h +198 -0
- package/include/numkong/dot/neonsdot.h +508 -0
- package/include/numkong/dot/rvv.h +714 -0
- package/include/numkong/dot/rvvbb.h +72 -0
- package/include/numkong/dot/rvvbf16.h +123 -0
- package/include/numkong/dot/rvvhalf.h +129 -0
- package/include/numkong/dot/sapphire.h +141 -0
- package/include/numkong/dot/serial.h +838 -0
- package/include/numkong/dot/sierra.h +405 -0
- package/include/numkong/dot/skylake.h +1084 -0
- package/include/numkong/dot/sve.h +379 -0
- package/include/numkong/dot/svebfdot.h +74 -0
- package/include/numkong/dot/svehalf.h +123 -0
- package/include/numkong/dot/v128relaxed.h +1258 -0
- package/include/numkong/dot.h +1070 -0
- package/include/numkong/dot.hpp +94 -0
- package/include/numkong/dots/README.md +496 -0
- package/include/numkong/dots/alder.h +114 -0
- package/include/numkong/dots/genoa.h +94 -0
- package/include/numkong/dots/haswell.h +295 -0
- package/include/numkong/dots/icelake.h +171 -0
- package/include/numkong/dots/neon.h +120 -0
- package/include/numkong/dots/neonbfdot.h +58 -0
- package/include/numkong/dots/neonfhm.h +94 -0
- package/include/numkong/dots/neonhalf.h +57 -0
- package/include/numkong/dots/neonsdot.h +108 -0
- package/include/numkong/dots/rvv.h +2486 -0
- package/include/numkong/dots/sapphireamx.h +3973 -0
- package/include/numkong/dots/serial.h +2844 -0
- package/include/numkong/dots/sierra.h +97 -0
- package/include/numkong/dots/skylake.h +196 -0
- package/include/numkong/dots/sme.h +5372 -0
- package/include/numkong/dots/smebi32.h +461 -0
- package/include/numkong/dots/smef64.h +1318 -0
- package/include/numkong/dots/smehalf.h +47 -0
- package/include/numkong/dots/v128relaxed.h +294 -0
- package/include/numkong/dots.h +2804 -0
- package/include/numkong/dots.hpp +639 -0
- package/include/numkong/each/README.md +469 -0
- package/include/numkong/each/haswell.h +1658 -0
- package/include/numkong/each/icelake.h +272 -0
- package/include/numkong/each/neon.h +1104 -0
- package/include/numkong/each/neonbfdot.h +212 -0
- package/include/numkong/each/neonhalf.h +410 -0
- package/include/numkong/each/rvv.h +1121 -0
- package/include/numkong/each/sapphire.h +477 -0
- package/include/numkong/each/serial.h +260 -0
- package/include/numkong/each/skylake.h +1562 -0
- package/include/numkong/each.h +2146 -0
- package/include/numkong/each.hpp +434 -0
- package/include/numkong/geospatial/README.md +147 -0
- package/include/numkong/geospatial/haswell.h +593 -0
- package/include/numkong/geospatial/neon.h +571 -0
- package/include/numkong/geospatial/rvv.h +701 -0
- package/include/numkong/geospatial/serial.h +309 -0
- package/include/numkong/geospatial/skylake.h +577 -0
- package/include/numkong/geospatial/v128relaxed.h +613 -0
- package/include/numkong/geospatial.h +453 -0
- package/include/numkong/geospatial.hpp +235 -0
- package/include/numkong/matrix.hpp +336 -0
- package/include/numkong/maxsim/README.md +187 -0
- package/include/numkong/maxsim/alder.h +511 -0
- package/include/numkong/maxsim/genoa.h +115 -0
- package/include/numkong/maxsim/haswell.h +553 -0
- package/include/numkong/maxsim/icelake.h +480 -0
- package/include/numkong/maxsim/neonsdot.h +394 -0
- package/include/numkong/maxsim/sapphireamx.h +877 -0
- package/include/numkong/maxsim/serial.h +490 -0
- package/include/numkong/maxsim/sme.h +929 -0
- package/include/numkong/maxsim/v128relaxed.h +280 -0
- package/include/numkong/maxsim.h +571 -0
- package/include/numkong/maxsim.hpp +133 -0
- package/include/numkong/mesh/README.md +227 -0
- package/include/numkong/mesh/haswell.h +2235 -0
- package/include/numkong/mesh/neon.h +1329 -0
- package/include/numkong/mesh/neonbfdot.h +842 -0
- package/include/numkong/mesh/neonhalf.h +616 -0
- package/include/numkong/mesh/rvv.h +916 -0
- package/include/numkong/mesh/serial.h +742 -0
- package/include/numkong/mesh/skylake.h +1135 -0
- package/include/numkong/mesh/v128relaxed.h +1052 -0
- package/include/numkong/mesh.h +652 -0
- package/include/numkong/mesh.hpp +762 -0
- package/include/numkong/numkong.h +78 -0
- package/include/numkong/numkong.hpp +57 -0
- package/include/numkong/probability/README.md +173 -0
- package/include/numkong/probability/haswell.h +267 -0
- package/include/numkong/probability/neon.h +225 -0
- package/include/numkong/probability/rvv.h +409 -0
- package/include/numkong/probability/serial.h +169 -0
- package/include/numkong/probability/skylake.h +324 -0
- package/include/numkong/probability.h +383 -0
- package/include/numkong/probability.hpp +120 -0
- package/include/numkong/random.h +50 -0
- package/include/numkong/random.hpp +285 -0
- package/include/numkong/reduce/README.md +547 -0
- package/include/numkong/reduce/alder.h +632 -0
- package/include/numkong/reduce/genoa.h +201 -0
- package/include/numkong/reduce/haswell.h +3783 -0
- package/include/numkong/reduce/icelake.h +549 -0
- package/include/numkong/reduce/neon.h +3841 -0
- package/include/numkong/reduce/neonbfdot.h +353 -0
- package/include/numkong/reduce/neonfhm.h +665 -0
- package/include/numkong/reduce/neonhalf.h +157 -0
- package/include/numkong/reduce/neonsdot.h +357 -0
- package/include/numkong/reduce/rvv.h +3407 -0
- package/include/numkong/reduce/serial.h +757 -0
- package/include/numkong/reduce/sierra.h +338 -0
- package/include/numkong/reduce/skylake.h +3792 -0
- package/include/numkong/reduce/v128relaxed.h +2302 -0
- package/include/numkong/reduce.h +1597 -0
- package/include/numkong/reduce.hpp +633 -0
- package/include/numkong/scalar/README.md +89 -0
- package/include/numkong/scalar/haswell.h +113 -0
- package/include/numkong/scalar/neon.h +122 -0
- package/include/numkong/scalar/neonhalf.h +70 -0
- package/include/numkong/scalar/rvv.h +211 -0
- package/include/numkong/scalar/sapphire.h +63 -0
- package/include/numkong/scalar/serial.h +332 -0
- package/include/numkong/scalar/v128relaxed.h +56 -0
- package/include/numkong/scalar.h +683 -0
- package/include/numkong/set/README.md +179 -0
- package/include/numkong/set/haswell.h +334 -0
- package/include/numkong/set/icelake.h +485 -0
- package/include/numkong/set/neon.h +364 -0
- package/include/numkong/set/rvv.h +226 -0
- package/include/numkong/set/rvvbb.h +117 -0
- package/include/numkong/set/serial.h +174 -0
- package/include/numkong/set/sve.h +185 -0
- package/include/numkong/set/v128relaxed.h +240 -0
- package/include/numkong/set.h +457 -0
- package/include/numkong/set.hpp +114 -0
- package/include/numkong/sets/README.md +149 -0
- package/include/numkong/sets/haswell.h +63 -0
- package/include/numkong/sets/icelake.h +66 -0
- package/include/numkong/sets/neon.h +61 -0
- package/include/numkong/sets/serial.h +43 -0
- package/include/numkong/sets/smebi32.h +1099 -0
- package/include/numkong/sets/v128relaxed.h +58 -0
- package/include/numkong/sets.h +339 -0
- package/include/numkong/sparse/README.md +156 -0
- package/include/numkong/sparse/icelake.h +463 -0
- package/include/numkong/sparse/neon.h +288 -0
- package/include/numkong/sparse/serial.h +117 -0
- package/include/numkong/sparse/sve2.h +507 -0
- package/include/numkong/sparse/turin.h +322 -0
- package/include/numkong/sparse.h +363 -0
- package/include/numkong/sparse.hpp +113 -0
- package/include/numkong/spatial/README.md +435 -0
- package/include/numkong/spatial/alder.h +607 -0
- package/include/numkong/spatial/genoa.h +290 -0
- package/include/numkong/spatial/haswell.h +960 -0
- package/include/numkong/spatial/icelake.h +586 -0
- package/include/numkong/spatial/neon.h +773 -0
- package/include/numkong/spatial/neonbfdot.h +165 -0
- package/include/numkong/spatial/neonhalf.h +118 -0
- package/include/numkong/spatial/neonsdot.h +261 -0
- package/include/numkong/spatial/rvv.h +984 -0
- package/include/numkong/spatial/rvvbf16.h +123 -0
- package/include/numkong/spatial/rvvhalf.h +117 -0
- package/include/numkong/spatial/sapphire.h +343 -0
- package/include/numkong/spatial/serial.h +346 -0
- package/include/numkong/spatial/sierra.h +323 -0
- package/include/numkong/spatial/skylake.h +606 -0
- package/include/numkong/spatial/sve.h +224 -0
- package/include/numkong/spatial/svebfdot.h +122 -0
- package/include/numkong/spatial/svehalf.h +109 -0
- package/include/numkong/spatial/v128relaxed.h +717 -0
- package/include/numkong/spatial.h +1425 -0
- package/include/numkong/spatial.hpp +183 -0
- package/include/numkong/spatials/README.md +580 -0
- package/include/numkong/spatials/alder.h +94 -0
- package/include/numkong/spatials/genoa.h +94 -0
- package/include/numkong/spatials/haswell.h +219 -0
- package/include/numkong/spatials/icelake.h +113 -0
- package/include/numkong/spatials/neon.h +109 -0
- package/include/numkong/spatials/neonbfdot.h +60 -0
- package/include/numkong/spatials/neonfhm.h +92 -0
- package/include/numkong/spatials/neonhalf.h +58 -0
- package/include/numkong/spatials/neonsdot.h +109 -0
- package/include/numkong/spatials/rvv.h +1960 -0
- package/include/numkong/spatials/sapphireamx.h +1149 -0
- package/include/numkong/spatials/serial.h +226 -0
- package/include/numkong/spatials/sierra.h +96 -0
- package/include/numkong/spatials/skylake.h +184 -0
- package/include/numkong/spatials/sme.h +1901 -0
- package/include/numkong/spatials/smef64.h +465 -0
- package/include/numkong/spatials/v128relaxed.h +240 -0
- package/include/numkong/spatials.h +3021 -0
- package/include/numkong/spatials.hpp +508 -0
- package/include/numkong/tensor.hpp +1592 -0
- package/include/numkong/trigonometry/README.md +184 -0
- package/include/numkong/trigonometry/haswell.h +652 -0
- package/include/numkong/trigonometry/neon.h +639 -0
- package/include/numkong/trigonometry/rvv.h +699 -0
- package/include/numkong/trigonometry/serial.h +703 -0
- package/include/numkong/trigonometry/skylake.h +721 -0
- package/include/numkong/trigonometry/v128relaxed.h +666 -0
- package/include/numkong/trigonometry.h +467 -0
- package/include/numkong/trigonometry.hpp +166 -0
- package/include/numkong/types.h +1384 -0
- package/include/numkong/types.hpp +5603 -0
- package/include/numkong/vector.hpp +698 -0
- package/javascript/README.md +246 -0
- package/javascript/dist/cjs/numkong-wasm.d.ts +166 -0
- package/javascript/dist/cjs/numkong-wasm.js +617 -0
- package/javascript/dist/cjs/numkong.d.ts +343 -0
- package/javascript/dist/cjs/numkong.js +523 -0
- package/javascript/dist/cjs/package.json +3 -0
- package/javascript/dist/cjs/types.d.ts +284 -0
- package/javascript/dist/cjs/types.js +653 -0
- package/javascript/dist/esm/numkong-wasm.d.ts +166 -0
- package/javascript/dist/esm/numkong-wasm.js +595 -0
- package/javascript/dist/esm/numkong.d.ts +343 -0
- package/javascript/dist/esm/numkong.js +452 -0
- package/javascript/dist/esm/package.json +3 -0
- package/javascript/dist/esm/types.d.ts +284 -0
- package/javascript/dist/esm/types.js +630 -0
- package/javascript/dist-package-cjs.json +3 -0
- package/javascript/dist-package-esm.json +3 -0
- package/javascript/node-gyp-build.d.ts +1 -0
- package/javascript/numkong-wasm.ts +756 -0
- package/javascript/numkong.c +689 -0
- package/javascript/numkong.ts +575 -0
- package/javascript/tsconfig-base.json +39 -0
- package/javascript/tsconfig-cjs.json +8 -0
- package/javascript/tsconfig-esm.json +8 -0
- package/javascript/types.ts +674 -0
- package/package.json +87 -0
|
@@ -0,0 +1,639 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @brief SIMD-accelerated Trigonometric Functions for NEON.
|
|
3
|
+
* @file include/numkong/trigonometry/neon.h
|
|
4
|
+
* @author Ash Vardanian
|
|
5
|
+
* @date December 28, 2025
|
|
6
|
+
*
|
|
7
|
+
* @sa include/numkong/trigonometry.h
|
|
8
|
+
* @see https://sleef.org
|
|
9
|
+
*
|
|
10
|
+
* @section trigonometry_neon_instructions ARM NEON Instructions
|
|
11
|
+
*
|
|
12
|
+
* Intrinsic Instruction Latency Throughput
|
|
13
|
+
* A76 M4+/V1+/Oryon
|
|
14
|
+
* vfmaq_f32 FMLA (V.4S, V.4S, V.4S) 4cy 2/cy 4/cy
|
|
15
|
+
* vfmsq_f32 FMLS (V.4S, V.4S, V.4S) 4cy 2/cy 4/cy
|
|
16
|
+
* vmulq_f32 FMUL (V.4S, V.4S, V.4S) 3cy 2/cy 4/cy
|
|
17
|
+
* vaddq_f32 FADD (V.4S, V.4S, V.4S) 2cy 2/cy 4/cy
|
|
18
|
+
* vsubq_f32 FSUB (V.4S, V.4S, V.4S) 2cy 2/cy 4/cy
|
|
19
|
+
* vcvtnq_s32_f32 FCVTNS (V.4S, V.4S) 3cy 2/cy 2/cy
|
|
20
|
+
* vcvtq_f32_s32 SCVTF (V.4S, V.4S) 3cy 2/cy 2/cy
|
|
21
|
+
* vbslq_f32 BSL (V.16B, V.16B, V.16B) 2cy 2/cy 4/cy
|
|
22
|
+
* vrecpeq_f32 FRECPE (V.4S, V.4S) 2cy 2/cy 2/cy
|
|
23
|
+
* vrecpsq_f32 FRECPS (V.4S, V.4S, V.4S) 4cy 2/cy 4/cy
|
|
24
|
+
* vfmaq_f64 FMLA (V.2D, V.2D, V.2D) 4cy 2/cy 4/cy
|
|
25
|
+
* vdivq_f64 FDIV (V.2D, V.2D, V.2D) 15cy 0.5/cy 0.5/cy
|
|
26
|
+
*
|
|
27
|
+
* Polynomial approximations for sin/cos/atan are FMA-dominated. On 4-pipe cores (Apple M4+,
|
|
28
|
+
* Graviton3+, Oryon), FMA throughput is 4/cy with 4cy latency.
|
|
29
|
+
*
|
|
30
|
+
* Division (vdivq_f64) remains slow at 0.5/cy on all cores. For f32, use fast reciprocal
|
|
31
|
+
* (vrecpeq_f32 + Newton-Raphson) instead when precision allows.
|
|
32
|
+
*/
|
|
33
|
+
#ifndef NK_TRIGONOMETRY_NEON_H
|
|
34
|
+
#define NK_TRIGONOMETRY_NEON_H
|
|
35
|
+
|
|
36
|
+
#if NK_TARGET_ARM_
|
|
37
|
+
#if NK_TARGET_NEON
|
|
38
|
+
|
|
39
|
+
#include "numkong/types.h"
|
|
40
|
+
#include "numkong/reduce/neon.h"
|
|
41
|
+
|
|
42
|
+
#if defined(__cplusplus)
|
|
43
|
+
extern "C" {
|
|
44
|
+
#endif
|
|
45
|
+
|
|
46
|
+
#if defined(__clang__)
|
|
47
|
+
#pragma clang attribute push(__attribute__((target("arch=armv8-a+simd"))), apply_to = function)
|
|
48
|
+
#elif defined(__GNUC__)
|
|
49
|
+
#pragma GCC push_options
|
|
50
|
+
#pragma GCC target("arch=armv8-a+simd")
|
|
51
|
+
#endif
|
|
52
|
+
|
|
53
|
+
/* NEON trigonometry kernels (4-way f32, 2-way f64)
|
|
54
|
+
* These implement polynomial approximations using 128-bit NEON vectors.
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
NK_INTERNAL float32x4_t nk_sin_f32x4_neon_(float32x4_t const angles_radians) {
|
|
58
|
+
// Cody-Waite constants for argument reduction
|
|
59
|
+
float32x4_t const pi_hi_f32x4 = vdupq_n_f32(3.1415927f);
|
|
60
|
+
float32x4_t const pi_lo_f32x4 = vdupq_n_f32(-8.742278e-8f);
|
|
61
|
+
float32x4_t const pi_reciprocal = vdupq_n_f32(0.31830988618379067154f);
|
|
62
|
+
// Degree-9 minimax coefficients
|
|
63
|
+
float32x4_t const coeff_9 = vdupq_n_f32(+2.7557319224e-6f);
|
|
64
|
+
float32x4_t const coeff_7 = vdupq_n_f32(-1.9841269841e-4f);
|
|
65
|
+
float32x4_t const coeff_5 = vdupq_n_f32(+8.3333293855e-3f);
|
|
66
|
+
float32x4_t const coeff_3 = vdupq_n_f32(-1.6666666641e-1f);
|
|
67
|
+
|
|
68
|
+
// Compute (multiples_of_pi) = round(angle / π) using vcvtnq which rounds to nearest
|
|
69
|
+
float32x4_t quotients = vmulq_f32(angles_radians, pi_reciprocal);
|
|
70
|
+
int32x4_t multiples_of_pi = vcvtnq_s32_f32(quotients);
|
|
71
|
+
float32x4_t rounded_quotients = vcvtq_f32_s32(multiples_of_pi);
|
|
72
|
+
|
|
73
|
+
// Cody-Waite range reduction
|
|
74
|
+
float32x4_t angles = vfmsq_f32(angles_radians, rounded_quotients, pi_hi_f32x4);
|
|
75
|
+
angles = vfmsq_f32(angles, rounded_quotients, pi_lo_f32x4);
|
|
76
|
+
float32x4_t const angles_squared = vmulq_f32(angles, angles);
|
|
77
|
+
float32x4_t const angles_cubed = vmulq_f32(angles, angles_squared);
|
|
78
|
+
|
|
79
|
+
// Degree-9 polynomial via Horner's method
|
|
80
|
+
float32x4_t polynomials = coeff_9;
|
|
81
|
+
polynomials = vfmaq_f32(coeff_7, polynomials, angles_squared);
|
|
82
|
+
polynomials = vfmaq_f32(coeff_5, polynomials, angles_squared);
|
|
83
|
+
polynomials = vfmaq_f32(coeff_3, polynomials, angles_squared);
|
|
84
|
+
float32x4_t results = vfmaq_f32(angles, angles_cubed, polynomials);
|
|
85
|
+
|
|
86
|
+
// If multiples_of_pi is odd, flip the sign
|
|
87
|
+
int32x4_t parity = vandq_s32(multiples_of_pi, vdupq_n_s32(1));
|
|
88
|
+
uint32x4_t odd_mask = vceqq_s32(parity, vdupq_n_s32(1));
|
|
89
|
+
float32x4_t negated = vnegq_f32(results);
|
|
90
|
+
results = vbslq_f32(odd_mask, negated, results);
|
|
91
|
+
return results;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
NK_INTERNAL float32x4_t nk_cos_f32x4_neon_(float32x4_t const angles_radians) {
|
|
95
|
+
// Cody-Waite constants for argument reduction
|
|
96
|
+
float32x4_t const pi_hi_f32x4 = vdupq_n_f32(3.1415927f);
|
|
97
|
+
float32x4_t const pi_lo_f32x4 = vdupq_n_f32(-8.742278e-8f);
|
|
98
|
+
float32x4_t const pi_half = vdupq_n_f32(1.57079632679489661923f);
|
|
99
|
+
float32x4_t const pi_reciprocal = vdupq_n_f32(0.31830988618379067154f);
|
|
100
|
+
// Degree-9 minimax coefficients
|
|
101
|
+
float32x4_t const coeff_9 = vdupq_n_f32(+2.7557319224e-6f);
|
|
102
|
+
float32x4_t const coeff_7 = vdupq_n_f32(-1.9841269841e-4f);
|
|
103
|
+
float32x4_t const coeff_5 = vdupq_n_f32(+8.3333293855e-3f);
|
|
104
|
+
float32x4_t const coeff_3 = vdupq_n_f32(-1.6666666641e-1f);
|
|
105
|
+
|
|
106
|
+
// Compute round((angle / π) - 0.5)
|
|
107
|
+
float32x4_t quotients = vsubq_f32(vmulq_f32(angles_radians, pi_reciprocal), vdupq_n_f32(0.5f));
|
|
108
|
+
int32x4_t multiples_of_pi = vcvtnq_s32_f32(quotients);
|
|
109
|
+
float32x4_t rounded_quotients = vcvtq_f32_s32(multiples_of_pi);
|
|
110
|
+
|
|
111
|
+
// Cody-Waite range reduction: angle = (angle - pi/2) - rounded * (pi_hi + pi_lo)
|
|
112
|
+
float32x4_t shifted = vsubq_f32(angles_radians, pi_half);
|
|
113
|
+
float32x4_t angles = vfmsq_f32(shifted, rounded_quotients, pi_hi_f32x4);
|
|
114
|
+
angles = vfmsq_f32(angles, rounded_quotients, pi_lo_f32x4);
|
|
115
|
+
float32x4_t const angles_squared = vmulq_f32(angles, angles);
|
|
116
|
+
float32x4_t const angles_cubed = vmulq_f32(angles, angles_squared);
|
|
117
|
+
|
|
118
|
+
// Degree-9 polynomial via Horner's method
|
|
119
|
+
float32x4_t polynomials = coeff_9;
|
|
120
|
+
polynomials = vfmaq_f32(coeff_7, polynomials, angles_squared);
|
|
121
|
+
polynomials = vfmaq_f32(coeff_5, polynomials, angles_squared);
|
|
122
|
+
polynomials = vfmaq_f32(coeff_3, polynomials, angles_squared);
|
|
123
|
+
float32x4_t results = vfmaq_f32(angles, angles_cubed, polynomials);
|
|
124
|
+
|
|
125
|
+
// If multiples_of_pi is even, flip the sign
|
|
126
|
+
int32x4_t parity = vandq_s32(multiples_of_pi, vdupq_n_s32(1));
|
|
127
|
+
uint32x4_t even_mask = vceqq_s32(parity, vdupq_n_s32(0));
|
|
128
|
+
float32x4_t negated = vnegq_f32(results);
|
|
129
|
+
results = vbslq_f32(even_mask, negated, results);
|
|
130
|
+
return results;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
NK_INTERNAL float32x4_t nk_atan_f32x4_neon_(float32x4_t const inputs) {
|
|
134
|
+
// Polynomial coefficients for atan approximation (8 terms)
|
|
135
|
+
float32x4_t const coeff_8 = vdupq_n_f32(-0.333331018686294555664062f);
|
|
136
|
+
float32x4_t const coeff_7 = vdupq_n_f32(+0.199926957488059997558594f);
|
|
137
|
+
float32x4_t const coeff_6 = vdupq_n_f32(-0.142027363181114196777344f);
|
|
138
|
+
float32x4_t const coeff_5 = vdupq_n_f32(+0.106347933411598205566406f);
|
|
139
|
+
float32x4_t const coeff_4 = vdupq_n_f32(-0.0748900920152664184570312f);
|
|
140
|
+
float32x4_t const coeff_3 = vdupq_n_f32(+0.0425049886107444763183594f);
|
|
141
|
+
float32x4_t const coeff_2 = vdupq_n_f32(-0.0159569028764963150024414f);
|
|
142
|
+
float32x4_t const coeff_1 = vdupq_n_f32(+0.00282363896258175373077393f);
|
|
143
|
+
float32x4_t const half_pi = vdupq_n_f32(1.5707963267948966f);
|
|
144
|
+
|
|
145
|
+
// Detect negative values and take absolute value
|
|
146
|
+
float32x4_t const zeros = vdupq_n_f32(0);
|
|
147
|
+
uint32x4_t negative_mask = vcltq_f32(inputs, zeros);
|
|
148
|
+
float32x4_t values = vabsq_f32(inputs);
|
|
149
|
+
|
|
150
|
+
// Check if values > 1 (need reciprocal)
|
|
151
|
+
uint32x4_t reciprocal_mask = vcgtq_f32(values, vdupq_n_f32(1.0f));
|
|
152
|
+
|
|
153
|
+
// Fast reciprocal using vrecpeq + Newton-Raphson (faster than vdivq on many Arm cores)
|
|
154
|
+
float32x4_t recip = vrecpeq_f32(values);
|
|
155
|
+
recip = vmulq_f32(recip, vrecpsq_f32(values, recip));
|
|
156
|
+
recip = vmulq_f32(recip, vrecpsq_f32(values, recip));
|
|
157
|
+
values = vbslq_f32(reciprocal_mask, recip, values);
|
|
158
|
+
|
|
159
|
+
// Compute powers
|
|
160
|
+
float32x4_t const values_squared = vmulq_f32(values, values);
|
|
161
|
+
float32x4_t const values_cubed = vmulq_f32(values, values_squared);
|
|
162
|
+
|
|
163
|
+
// Polynomial evaluation using Horner's method
|
|
164
|
+
float32x4_t polynomials = coeff_1;
|
|
165
|
+
polynomials = vfmaq_f32(coeff_2, polynomials, values_squared);
|
|
166
|
+
polynomials = vfmaq_f32(coeff_3, polynomials, values_squared);
|
|
167
|
+
polynomials = vfmaq_f32(coeff_4, polynomials, values_squared);
|
|
168
|
+
polynomials = vfmaq_f32(coeff_5, polynomials, values_squared);
|
|
169
|
+
polynomials = vfmaq_f32(coeff_6, polynomials, values_squared);
|
|
170
|
+
polynomials = vfmaq_f32(coeff_7, polynomials, values_squared);
|
|
171
|
+
polynomials = vfmaq_f32(coeff_8, polynomials, values_squared);
|
|
172
|
+
|
|
173
|
+
// Compute result: atan(x) ≈ x + x³ * P(x²)
|
|
174
|
+
float32x4_t result = vfmaq_f32(values, values_cubed, polynomials);
|
|
175
|
+
|
|
176
|
+
// Adjust for reciprocal: result = π/2 - result
|
|
177
|
+
float32x4_t adjusted = vsubq_f32(half_pi, result);
|
|
178
|
+
result = vbslq_f32(reciprocal_mask, adjusted, result);
|
|
179
|
+
|
|
180
|
+
// Adjust for negative: result = -result
|
|
181
|
+
float32x4_t negated = vnegq_f32(result);
|
|
182
|
+
result = vbslq_f32(negative_mask, negated, result);
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
NK_INTERNAL float32x4_t nk_atan2_f32x4_neon_(float32x4_t const ys_inputs, float32x4_t const xs_inputs) {
|
|
187
|
+
// Polynomial coefficients (same as atan)
|
|
188
|
+
float32x4_t const coeff_8 = vdupq_n_f32(-0.333331018686294555664062f);
|
|
189
|
+
float32x4_t const coeff_7 = vdupq_n_f32(+0.199926957488059997558594f);
|
|
190
|
+
float32x4_t const coeff_6 = vdupq_n_f32(-0.142027363181114196777344f);
|
|
191
|
+
float32x4_t const coeff_5 = vdupq_n_f32(+0.106347933411598205566406f);
|
|
192
|
+
float32x4_t const coeff_4 = vdupq_n_f32(-0.0748900920152664184570312f);
|
|
193
|
+
float32x4_t const coeff_3 = vdupq_n_f32(+0.0425049886107444763183594f);
|
|
194
|
+
float32x4_t const coeff_2 = vdupq_n_f32(-0.0159569028764963150024414f);
|
|
195
|
+
float32x4_t const coeff_1 = vdupq_n_f32(+0.00282363896258175373077393f);
|
|
196
|
+
float32x4_t const half_pi = vdupq_n_f32(1.5707963267948966f);
|
|
197
|
+
float32x4_t const zeros = vdupq_n_f32(0);
|
|
198
|
+
|
|
199
|
+
// Quadrant adjustments - take absolute values
|
|
200
|
+
uint32x4_t xs_negative_mask = vcltq_f32(xs_inputs, zeros);
|
|
201
|
+
float32x4_t xs = vabsq_f32(xs_inputs);
|
|
202
|
+
float32x4_t ys = vabsq_f32(ys_inputs);
|
|
203
|
+
|
|
204
|
+
// Ensure proper fraction where numerator < denominator
|
|
205
|
+
uint32x4_t swap_mask = vcgtq_f32(ys, xs);
|
|
206
|
+
float32x4_t temps = xs;
|
|
207
|
+
xs = vbslq_f32(swap_mask, ys, xs);
|
|
208
|
+
ys = vbslq_f32(swap_mask, vnegq_f32(temps), ys);
|
|
209
|
+
|
|
210
|
+
// Fast reciprocal for division: ratio = ys / xs ≈ ys * recip(xs)
|
|
211
|
+
float32x4_t recip = vrecpeq_f32(xs);
|
|
212
|
+
recip = vmulq_f32(recip, vrecpsq_f32(xs, recip));
|
|
213
|
+
recip = vmulq_f32(recip, vrecpsq_f32(xs, recip));
|
|
214
|
+
float32x4_t const ratio = vmulq_f32(ys, recip);
|
|
215
|
+
float32x4_t const ratio_squared = vmulq_f32(ratio, ratio);
|
|
216
|
+
float32x4_t const ratio_cubed = vmulq_f32(ratio, ratio_squared);
|
|
217
|
+
|
|
218
|
+
// Polynomial evaluation using Horner's method
|
|
219
|
+
float32x4_t polynomials = coeff_1;
|
|
220
|
+
polynomials = vfmaq_f32(coeff_2, polynomials, ratio_squared);
|
|
221
|
+
polynomials = vfmaq_f32(coeff_3, polynomials, ratio_squared);
|
|
222
|
+
polynomials = vfmaq_f32(coeff_4, polynomials, ratio_squared);
|
|
223
|
+
polynomials = vfmaq_f32(coeff_5, polynomials, ratio_squared);
|
|
224
|
+
polynomials = vfmaq_f32(coeff_6, polynomials, ratio_squared);
|
|
225
|
+
polynomials = vfmaq_f32(coeff_7, polynomials, ratio_squared);
|
|
226
|
+
polynomials = vfmaq_f32(coeff_8, polynomials, ratio_squared);
|
|
227
|
+
|
|
228
|
+
// Compute the result
|
|
229
|
+
float32x4_t results = vfmaq_f32(ratio, ratio_cubed, polynomials);
|
|
230
|
+
|
|
231
|
+
// Compute quadrant value: 0 for x>=0 && !swap, 1 for x>=0 && swap,
|
|
232
|
+
// -2 for x<0 && !swap, -1 for x<0 && swap
|
|
233
|
+
float32x4_t quadrant = vdupq_n_f32(0.0f);
|
|
234
|
+
float32x4_t neg_two = vdupq_n_f32(-2.0f);
|
|
235
|
+
quadrant = vbslq_f32(xs_negative_mask, neg_two, quadrant);
|
|
236
|
+
float32x4_t quadrant_incremented = vaddq_f32(quadrant, vdupq_n_f32(1.0f));
|
|
237
|
+
quadrant = vbslq_f32(swap_mask, quadrant_incremented, quadrant);
|
|
238
|
+
|
|
239
|
+
// Adjust for quadrant: result += quadrant * π/2
|
|
240
|
+
results = vfmaq_f32(results, quadrant, half_pi);
|
|
241
|
+
|
|
242
|
+
// Transfer sign from x and y by XOR with sign bits
|
|
243
|
+
uint32x4_t sign_mask = vreinterpretq_u32_f32(vdupq_n_f32(-0.0f));
|
|
244
|
+
uint32x4_t xs_sign = vandq_u32(vreinterpretq_u32_f32(xs_inputs), sign_mask);
|
|
245
|
+
uint32x4_t ys_sign = vandq_u32(vreinterpretq_u32_f32(ys_inputs), sign_mask);
|
|
246
|
+
uint32x4_t result_bits = vreinterpretq_u32_f32(results);
|
|
247
|
+
result_bits = veorq_u32(result_bits, xs_sign);
|
|
248
|
+
result_bits = veorq_u32(result_bits, ys_sign);
|
|
249
|
+
results = vreinterpretq_f32_u32(result_bits);
|
|
250
|
+
|
|
251
|
+
return results;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
NK_INTERNAL float64x2_t nk_sin_f64x2_neon_(float64x2_t const angles_radians) {
|
|
255
|
+
// Constants for argument reduction
|
|
256
|
+
float64x2_t const pi_high = vdupq_n_f64(3.141592653589793116);
|
|
257
|
+
float64x2_t const pi_low = vdupq_n_f64(1.2246467991473532072e-16);
|
|
258
|
+
float64x2_t const pi_reciprocal = vdupq_n_f64(0.31830988618379067154);
|
|
259
|
+
|
|
260
|
+
// Polynomial coefficients for sine approximation
|
|
261
|
+
float64x2_t const coeff_0 = vdupq_n_f64(+0.00833333333333332974823815);
|
|
262
|
+
float64x2_t const coeff_1 = vdupq_n_f64(-0.000198412698412696162806809);
|
|
263
|
+
float64x2_t const coeff_2 = vdupq_n_f64(+2.75573192239198747630416e-06);
|
|
264
|
+
float64x2_t const coeff_3 = vdupq_n_f64(-2.50521083763502045810755e-08);
|
|
265
|
+
float64x2_t const coeff_4 = vdupq_n_f64(+1.60590430605664501629054e-10);
|
|
266
|
+
float64x2_t const coeff_5 = vdupq_n_f64(-7.64712219118158833288484e-13);
|
|
267
|
+
float64x2_t const coeff_6 = vdupq_n_f64(+2.81009972710863200091251e-15);
|
|
268
|
+
float64x2_t const coeff_7 = vdupq_n_f64(-7.97255955009037868891952e-18);
|
|
269
|
+
float64x2_t const coeff_8 = vdupq_n_f64(-0.166666666666666657414808);
|
|
270
|
+
|
|
271
|
+
// Compute round(angle / π)
|
|
272
|
+
float64x2_t const quotients = vmulq_f64(angles_radians, pi_reciprocal);
|
|
273
|
+
int64x2_t multiples_of_pi = vcvtnq_s64_f64(quotients);
|
|
274
|
+
float64x2_t rounded_quotients = vcvtq_f64_s64(multiples_of_pi);
|
|
275
|
+
|
|
276
|
+
// Two-step Cody-Waite reduction: angle - rounded * π_high - rounded * π_low
|
|
277
|
+
float64x2_t angles = angles_radians;
|
|
278
|
+
angles = vfmsq_f64(angles, rounded_quotients, pi_high);
|
|
279
|
+
angles = vfmsq_f64(angles, rounded_quotients, pi_low);
|
|
280
|
+
|
|
281
|
+
// If multiples_of_pi is odd, negate the angle
|
|
282
|
+
int64x2_t parity = vandq_s64(multiples_of_pi, vdupq_n_s64(1));
|
|
283
|
+
uint64x2_t odd_mask = vceqq_s64(parity, vdupq_n_s64(1));
|
|
284
|
+
float64x2_t negated_angles = vnegq_f64(angles);
|
|
285
|
+
angles = vbslq_f64(odd_mask, negated_angles, angles);
|
|
286
|
+
|
|
287
|
+
float64x2_t const angles_squared = vmulq_f64(angles, angles);
|
|
288
|
+
float64x2_t const angles_cubed = vmulq_f64(angles, angles_squared);
|
|
289
|
+
float64x2_t const angles_quadratic = vmulq_f64(angles_squared, angles_squared);
|
|
290
|
+
float64x2_t const angles_octic = vmulq_f64(angles_quadratic, angles_quadratic);
|
|
291
|
+
|
|
292
|
+
// Compute polynomial terms using Estrin's scheme for better ILP
|
|
293
|
+
float64x2_t const poly_67 = vfmaq_f64(coeff_6, angles_squared, coeff_7);
|
|
294
|
+
float64x2_t const poly_45 = vfmaq_f64(coeff_4, angles_squared, coeff_5);
|
|
295
|
+
float64x2_t const poly_4567 = vfmaq_f64(poly_45, angles_quadratic, poly_67);
|
|
296
|
+
|
|
297
|
+
float64x2_t const poly_23 = vfmaq_f64(coeff_2, angles_squared, coeff_3);
|
|
298
|
+
float64x2_t const poly_01 = vfmaq_f64(coeff_0, angles_squared, coeff_1);
|
|
299
|
+
float64x2_t const poly_0123 = vfmaq_f64(poly_01, angles_quadratic, poly_23);
|
|
300
|
+
|
|
301
|
+
// Combine polynomial terms
|
|
302
|
+
float64x2_t results = vfmaq_f64(poly_0123, angles_octic, poly_4567);
|
|
303
|
+
results = vfmaq_f64(coeff_8, results, angles_squared);
|
|
304
|
+
results = vfmaq_f64(angles, results, angles_cubed);
|
|
305
|
+
|
|
306
|
+
// Handle zero input (preserve sign of zero)
|
|
307
|
+
uint64x2_t const non_zero_mask = vceqq_f64(angles_radians, vdupq_n_f64(0));
|
|
308
|
+
results = vbslq_f64(non_zero_mask, angles_radians, results);
|
|
309
|
+
return results;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
NK_INTERNAL float64x2_t nk_cos_f64x2_neon_(float64x2_t const angles_radians) {
|
|
313
|
+
// Constants for argument reduction
|
|
314
|
+
float64x2_t const pi_high_half = vdupq_n_f64(3.141592653589793116 * 0.5);
|
|
315
|
+
float64x2_t const pi_low_half = vdupq_n_f64(1.2246467991473532072e-16 * 0.5);
|
|
316
|
+
float64x2_t const pi_reciprocal = vdupq_n_f64(0.31830988618379067154);
|
|
317
|
+
|
|
318
|
+
// Polynomial coefficients for cosine approximation
|
|
319
|
+
float64x2_t const coeff_0 = vdupq_n_f64(+0.00833333333333332974823815);
|
|
320
|
+
float64x2_t const coeff_1 = vdupq_n_f64(-0.000198412698412696162806809);
|
|
321
|
+
float64x2_t const coeff_2 = vdupq_n_f64(+2.75573192239198747630416e-06);
|
|
322
|
+
float64x2_t const coeff_3 = vdupq_n_f64(-2.50521083763502045810755e-08);
|
|
323
|
+
float64x2_t const coeff_4 = vdupq_n_f64(+1.60590430605664501629054e-10);
|
|
324
|
+
float64x2_t const coeff_5 = vdupq_n_f64(-7.64712219118158833288484e-13);
|
|
325
|
+
float64x2_t const coeff_6 = vdupq_n_f64(+2.81009972710863200091251e-15);
|
|
326
|
+
float64x2_t const coeff_7 = vdupq_n_f64(-7.97255955009037868891952e-18);
|
|
327
|
+
float64x2_t const coeff_8 = vdupq_n_f64(-0.166666666666666657414808);
|
|
328
|
+
|
|
329
|
+
// Compute 2 * round(angle / π - 0.5) + 1
|
|
330
|
+
float64x2_t const quotients = vsubq_f64(vmulq_f64(angles_radians, pi_reciprocal), vdupq_n_f64(0.5));
|
|
331
|
+
float64x2_t const rounded = vcvtq_f64_s64(vcvtnq_s64_f64(quotients));
|
|
332
|
+
float64x2_t const rounded_quotients = vfmaq_f64(vdupq_n_f64(1.0), vdupq_n_f64(2.0), rounded);
|
|
333
|
+
int64x2_t quotients_i64 = vcvtnq_s64_f64(rounded_quotients);
|
|
334
|
+
|
|
335
|
+
// Two-step Cody-Waite reduction
|
|
336
|
+
float64x2_t angles = angles_radians;
|
|
337
|
+
angles = vfmsq_f64(angles, rounded_quotients, pi_high_half);
|
|
338
|
+
angles = vfmsq_f64(angles, rounded_quotients, pi_low_half);
|
|
339
|
+
|
|
340
|
+
// If (rounded_quotients & 2) == 0, negate the angle
|
|
341
|
+
int64x2_t bit2 = vandq_s64(quotients_i64, vdupq_n_s64(2));
|
|
342
|
+
uint64x2_t flip_mask = vceqq_s64(bit2, vdupq_n_s64(0));
|
|
343
|
+
float64x2_t negated_angles = vnegq_f64(angles);
|
|
344
|
+
angles = vbslq_f64(flip_mask, negated_angles, angles);
|
|
345
|
+
|
|
346
|
+
float64x2_t const angles_squared = vmulq_f64(angles, angles);
|
|
347
|
+
float64x2_t const angles_cubed = vmulq_f64(angles, angles_squared);
|
|
348
|
+
float64x2_t const angles_quadratic = vmulq_f64(angles_squared, angles_squared);
|
|
349
|
+
float64x2_t const angles_octic = vmulq_f64(angles_quadratic, angles_quadratic);
|
|
350
|
+
|
|
351
|
+
// Compute polynomial terms using Estrin's scheme
|
|
352
|
+
float64x2_t const poly_67 = vfmaq_f64(coeff_6, angles_squared, coeff_7);
|
|
353
|
+
float64x2_t const poly_45 = vfmaq_f64(coeff_4, angles_squared, coeff_5);
|
|
354
|
+
float64x2_t const poly_4567 = vfmaq_f64(poly_45, angles_quadratic, poly_67);
|
|
355
|
+
|
|
356
|
+
float64x2_t const poly_23 = vfmaq_f64(coeff_2, angles_squared, coeff_3);
|
|
357
|
+
float64x2_t const poly_01 = vfmaq_f64(coeff_0, angles_squared, coeff_1);
|
|
358
|
+
float64x2_t const poly_0123 = vfmaq_f64(poly_01, angles_quadratic, poly_23);
|
|
359
|
+
|
|
360
|
+
// Combine polynomial terms
|
|
361
|
+
float64x2_t results = vfmaq_f64(poly_0123, angles_octic, poly_4567);
|
|
362
|
+
results = vfmaq_f64(coeff_8, results, angles_squared);
|
|
363
|
+
results = vfmaq_f64(angles, results, angles_cubed);
|
|
364
|
+
return results;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
NK_INTERNAL float64x2_t nk_atan_f64x2_neon_(float64x2_t const inputs) {
|
|
368
|
+
// Polynomial coefficients for atan approximation (19 terms)
|
|
369
|
+
float64x2_t const coeff_19 = vdupq_n_f64(-1.88796008463073496563746e-05);
|
|
370
|
+
float64x2_t const coeff_18 = vdupq_n_f64(+0.000209850076645816976906797);
|
|
371
|
+
float64x2_t const coeff_17 = vdupq_n_f64(-0.00110611831486672482563471);
|
|
372
|
+
float64x2_t const coeff_16 = vdupq_n_f64(+0.00370026744188713119232403);
|
|
373
|
+
float64x2_t const coeff_15 = vdupq_n_f64(-0.00889896195887655491740809);
|
|
374
|
+
float64x2_t const coeff_14 = vdupq_n_f64(+0.016599329773529201970117);
|
|
375
|
+
float64x2_t const coeff_13 = vdupq_n_f64(-0.0254517624932312641616861);
|
|
376
|
+
float64x2_t const coeff_12 = vdupq_n_f64(+0.0337852580001353069993897);
|
|
377
|
+
float64x2_t const coeff_11 = vdupq_n_f64(-0.0407629191276836500001934);
|
|
378
|
+
float64x2_t const coeff_10 = vdupq_n_f64(+0.0466667150077840625632675);
|
|
379
|
+
float64x2_t const coeff_9 = vdupq_n_f64(-0.0523674852303482457616113);
|
|
380
|
+
float64x2_t const coeff_8 = vdupq_n_f64(+0.0587666392926673580854313);
|
|
381
|
+
float64x2_t const coeff_7 = vdupq_n_f64(-0.0666573579361080525984562);
|
|
382
|
+
float64x2_t const coeff_6 = vdupq_n_f64(+0.0769219538311769618355029);
|
|
383
|
+
float64x2_t const coeff_5 = vdupq_n_f64(-0.090908995008245008229153);
|
|
384
|
+
float64x2_t const coeff_4 = vdupq_n_f64(+0.111111105648261418443745);
|
|
385
|
+
float64x2_t const coeff_3 = vdupq_n_f64(-0.14285714266771329383765);
|
|
386
|
+
float64x2_t const coeff_2 = vdupq_n_f64(+0.199999999996591265594148);
|
|
387
|
+
float64x2_t const coeff_1 = vdupq_n_f64(-0.333333333333311110369124);
|
|
388
|
+
float64x2_t const half_pi = vdupq_n_f64(1.5707963267948966);
|
|
389
|
+
float64x2_t const zeros = vdupq_n_f64(0);
|
|
390
|
+
|
|
391
|
+
// Detect negative and take absolute value
|
|
392
|
+
uint64x2_t negative_mask = vcltq_f64(inputs, zeros);
|
|
393
|
+
float64x2_t values = vabsq_f64(inputs);
|
|
394
|
+
|
|
395
|
+
// Check if values > 1 (need reciprocal) - use division for f64 precision
|
|
396
|
+
uint64x2_t reciprocal_mask = vcgtq_f64(values, vdupq_n_f64(1.0));
|
|
397
|
+
float64x2_t reciprocal_values = vdivq_f64(vdupq_n_f64(1.0), values);
|
|
398
|
+
values = vbslq_f64(reciprocal_mask, reciprocal_values, values);
|
|
399
|
+
|
|
400
|
+
// Compute powers
|
|
401
|
+
float64x2_t const values_squared = vmulq_f64(values, values);
|
|
402
|
+
float64x2_t const values_cubed = vmulq_f64(values, values_squared);
|
|
403
|
+
|
|
404
|
+
// Polynomial evaluation using Horner's method
|
|
405
|
+
float64x2_t polynomials = coeff_19;
|
|
406
|
+
polynomials = vfmaq_f64(coeff_18, polynomials, values_squared);
|
|
407
|
+
polynomials = vfmaq_f64(coeff_17, polynomials, values_squared);
|
|
408
|
+
polynomials = vfmaq_f64(coeff_16, polynomials, values_squared);
|
|
409
|
+
polynomials = vfmaq_f64(coeff_15, polynomials, values_squared);
|
|
410
|
+
polynomials = vfmaq_f64(coeff_14, polynomials, values_squared);
|
|
411
|
+
polynomials = vfmaq_f64(coeff_13, polynomials, values_squared);
|
|
412
|
+
polynomials = vfmaq_f64(coeff_12, polynomials, values_squared);
|
|
413
|
+
polynomials = vfmaq_f64(coeff_11, polynomials, values_squared);
|
|
414
|
+
polynomials = vfmaq_f64(coeff_10, polynomials, values_squared);
|
|
415
|
+
polynomials = vfmaq_f64(coeff_9, polynomials, values_squared);
|
|
416
|
+
polynomials = vfmaq_f64(coeff_8, polynomials, values_squared);
|
|
417
|
+
polynomials = vfmaq_f64(coeff_7, polynomials, values_squared);
|
|
418
|
+
polynomials = vfmaq_f64(coeff_6, polynomials, values_squared);
|
|
419
|
+
polynomials = vfmaq_f64(coeff_5, polynomials, values_squared);
|
|
420
|
+
polynomials = vfmaq_f64(coeff_4, polynomials, values_squared);
|
|
421
|
+
polynomials = vfmaq_f64(coeff_3, polynomials, values_squared);
|
|
422
|
+
polynomials = vfmaq_f64(coeff_2, polynomials, values_squared);
|
|
423
|
+
polynomials = vfmaq_f64(coeff_1, polynomials, values_squared);
|
|
424
|
+
|
|
425
|
+
// Compute result
|
|
426
|
+
float64x2_t result = vfmaq_f64(values, values_cubed, polynomials);
|
|
427
|
+
|
|
428
|
+
// Adjust for reciprocal: result = π/2 - result
|
|
429
|
+
float64x2_t adjusted = vsubq_f64(half_pi, result);
|
|
430
|
+
result = vbslq_f64(reciprocal_mask, adjusted, result);
|
|
431
|
+
|
|
432
|
+
// Adjust for negative: result = -result
|
|
433
|
+
float64x2_t negated = vnegq_f64(result);
|
|
434
|
+
result = vbslq_f64(negative_mask, negated, result);
|
|
435
|
+
return result;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
NK_INTERNAL float64x2_t nk_atan2_f64x2_neon_(float64x2_t const ys_inputs, float64x2_t const xs_inputs) {
|
|
439
|
+
// Polynomial coefficients (same as atan)
|
|
440
|
+
float64x2_t const coeff_19 = vdupq_n_f64(-1.88796008463073496563746e-05);
|
|
441
|
+
float64x2_t const coeff_18 = vdupq_n_f64(+0.000209850076645816976906797);
|
|
442
|
+
float64x2_t const coeff_17 = vdupq_n_f64(-0.00110611831486672482563471);
|
|
443
|
+
float64x2_t const coeff_16 = vdupq_n_f64(+0.00370026744188713119232403);
|
|
444
|
+
float64x2_t const coeff_15 = vdupq_n_f64(-0.00889896195887655491740809);
|
|
445
|
+
float64x2_t const coeff_14 = vdupq_n_f64(+0.016599329773529201970117);
|
|
446
|
+
float64x2_t const coeff_13 = vdupq_n_f64(-0.0254517624932312641616861);
|
|
447
|
+
float64x2_t const coeff_12 = vdupq_n_f64(+0.0337852580001353069993897);
|
|
448
|
+
float64x2_t const coeff_11 = vdupq_n_f64(-0.0407629191276836500001934);
|
|
449
|
+
float64x2_t const coeff_10 = vdupq_n_f64(+0.0466667150077840625632675);
|
|
450
|
+
float64x2_t const coeff_9 = vdupq_n_f64(-0.0523674852303482457616113);
|
|
451
|
+
float64x2_t const coeff_8 = vdupq_n_f64(+0.0587666392926673580854313);
|
|
452
|
+
float64x2_t const coeff_7 = vdupq_n_f64(-0.0666573579361080525984562);
|
|
453
|
+
float64x2_t const coeff_6 = vdupq_n_f64(+0.0769219538311769618355029);
|
|
454
|
+
float64x2_t const coeff_5 = vdupq_n_f64(-0.090908995008245008229153);
|
|
455
|
+
float64x2_t const coeff_4 = vdupq_n_f64(+0.111111105648261418443745);
|
|
456
|
+
float64x2_t const coeff_3 = vdupq_n_f64(-0.14285714266771329383765);
|
|
457
|
+
float64x2_t const coeff_2 = vdupq_n_f64(+0.199999999996591265594148);
|
|
458
|
+
float64x2_t const coeff_1 = vdupq_n_f64(-0.333333333333311110369124);
|
|
459
|
+
float64x2_t const half_pi = vdupq_n_f64(1.5707963267948966);
|
|
460
|
+
float64x2_t const zeros = vdupq_n_f64(0);
|
|
461
|
+
|
|
462
|
+
// Quadrant adjustments - take absolute values
|
|
463
|
+
uint64x2_t xs_negative_mask = vcltq_f64(xs_inputs, zeros);
|
|
464
|
+
float64x2_t xs = vabsq_f64(xs_inputs);
|
|
465
|
+
float64x2_t ys = vabsq_f64(ys_inputs);
|
|
466
|
+
|
|
467
|
+
// Ensure proper fraction where numerator < denominator
|
|
468
|
+
uint64x2_t swap_mask = vcgtq_f64(ys, xs);
|
|
469
|
+
float64x2_t temps = xs;
|
|
470
|
+
xs = vbslq_f64(swap_mask, ys, xs);
|
|
471
|
+
ys = vbslq_f64(swap_mask, vnegq_f64(temps), ys);
|
|
472
|
+
|
|
473
|
+
// Division for f64 precision
|
|
474
|
+
float64x2_t const ratio = vdivq_f64(ys, xs);
|
|
475
|
+
float64x2_t const ratio_squared = vmulq_f64(ratio, ratio);
|
|
476
|
+
float64x2_t const ratio_cubed = vmulq_f64(ratio, ratio_squared);
|
|
477
|
+
|
|
478
|
+
// Polynomial evaluation using Horner's method
|
|
479
|
+
float64x2_t polynomials = coeff_19;
|
|
480
|
+
polynomials = vfmaq_f64(coeff_18, polynomials, ratio_squared);
|
|
481
|
+
polynomials = vfmaq_f64(coeff_17, polynomials, ratio_squared);
|
|
482
|
+
polynomials = vfmaq_f64(coeff_16, polynomials, ratio_squared);
|
|
483
|
+
polynomials = vfmaq_f64(coeff_15, polynomials, ratio_squared);
|
|
484
|
+
polynomials = vfmaq_f64(coeff_14, polynomials, ratio_squared);
|
|
485
|
+
polynomials = vfmaq_f64(coeff_13, polynomials, ratio_squared);
|
|
486
|
+
polynomials = vfmaq_f64(coeff_12, polynomials, ratio_squared);
|
|
487
|
+
polynomials = vfmaq_f64(coeff_11, polynomials, ratio_squared);
|
|
488
|
+
polynomials = vfmaq_f64(coeff_10, polynomials, ratio_squared);
|
|
489
|
+
polynomials = vfmaq_f64(coeff_9, polynomials, ratio_squared);
|
|
490
|
+
polynomials = vfmaq_f64(coeff_8, polynomials, ratio_squared);
|
|
491
|
+
polynomials = vfmaq_f64(coeff_7, polynomials, ratio_squared);
|
|
492
|
+
polynomials = vfmaq_f64(coeff_6, polynomials, ratio_squared);
|
|
493
|
+
polynomials = vfmaq_f64(coeff_5, polynomials, ratio_squared);
|
|
494
|
+
polynomials = vfmaq_f64(coeff_4, polynomials, ratio_squared);
|
|
495
|
+
polynomials = vfmaq_f64(coeff_3, polynomials, ratio_squared);
|
|
496
|
+
polynomials = vfmaq_f64(coeff_2, polynomials, ratio_squared);
|
|
497
|
+
polynomials = vfmaq_f64(coeff_1, polynomials, ratio_squared);
|
|
498
|
+
|
|
499
|
+
// Compute the result
|
|
500
|
+
float64x2_t results = vfmaq_f64(ratio, ratio_cubed, polynomials);
|
|
501
|
+
|
|
502
|
+
// Compute quadrant value: 0 for x>=0 && !swap, 1 for x>=0 && swap,
|
|
503
|
+
// -2 for x<0 && !swap, -1 for x<0 && swap
|
|
504
|
+
float64x2_t quadrant = vdupq_n_f64(0.0);
|
|
505
|
+
float64x2_t neg_two = vdupq_n_f64(-2.0);
|
|
506
|
+
quadrant = vbslq_f64(xs_negative_mask, neg_two, quadrant);
|
|
507
|
+
float64x2_t quadrant_incremented = vaddq_f64(quadrant, vdupq_n_f64(1.0));
|
|
508
|
+
quadrant = vbslq_f64(swap_mask, quadrant_incremented, quadrant);
|
|
509
|
+
|
|
510
|
+
// Adjust for quadrant: result += quadrant * π/2
|
|
511
|
+
results = vfmaq_f64(results, quadrant, half_pi);
|
|
512
|
+
|
|
513
|
+
// Transfer sign from x and y by XOR with sign bits
|
|
514
|
+
uint64x2_t sign_mask = vreinterpretq_u64_f64(vdupq_n_f64(-0.0));
|
|
515
|
+
uint64x2_t xs_sign = vandq_u64(vreinterpretq_u64_f64(xs_inputs), sign_mask);
|
|
516
|
+
uint64x2_t ys_sign = vandq_u64(vreinterpretq_u64_f64(ys_inputs), sign_mask);
|
|
517
|
+
uint64x2_t result_bits = vreinterpretq_u64_f64(results);
|
|
518
|
+
result_bits = veorq_u64(result_bits, xs_sign);
|
|
519
|
+
result_bits = veorq_u64(result_bits, ys_sign);
|
|
520
|
+
results = vreinterpretq_f64_u64(result_bits);
|
|
521
|
+
|
|
522
|
+
return results;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
NK_PUBLIC void nk_each_sin_f32_neon(nk_f32_t const *ins, nk_size_t n, nk_f32_t *outs) {
|
|
526
|
+
nk_size_t i = 0;
|
|
527
|
+
for (; i + 4 <= n; i += 4) {
|
|
528
|
+
float32x4_t angles = vld1q_f32(ins + i);
|
|
529
|
+
float32x4_t results = nk_sin_f32x4_neon_(angles);
|
|
530
|
+
vst1q_f32(outs + i, results);
|
|
531
|
+
}
|
|
532
|
+
if (i < n) {
|
|
533
|
+
nk_size_t remaining = n - i;
|
|
534
|
+
nk_b128_vec_t angles_vec;
|
|
535
|
+
nk_partial_load_b32x4_serial_(ins + i, &angles_vec, remaining);
|
|
536
|
+
nk_b128_vec_t results_vec;
|
|
537
|
+
results_vec.f32x4 = nk_sin_f32x4_neon_(angles_vec.f32x4);
|
|
538
|
+
nk_partial_store_b32x4_serial_(&results_vec, outs + i, remaining);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
NK_PUBLIC void nk_each_cos_f32_neon(nk_f32_t const *ins, nk_size_t n, nk_f32_t *outs) {
|
|
543
|
+
nk_size_t i = 0;
|
|
544
|
+
for (; i + 4 <= n; i += 4) {
|
|
545
|
+
float32x4_t angles = vld1q_f32(ins + i);
|
|
546
|
+
float32x4_t results = nk_cos_f32x4_neon_(angles);
|
|
547
|
+
vst1q_f32(outs + i, results);
|
|
548
|
+
}
|
|
549
|
+
if (i < n) {
|
|
550
|
+
nk_size_t remaining = n - i;
|
|
551
|
+
nk_b128_vec_t angles_vec;
|
|
552
|
+
nk_partial_load_b32x4_serial_(ins + i, &angles_vec, remaining);
|
|
553
|
+
nk_b128_vec_t results_vec;
|
|
554
|
+
results_vec.f32x4 = nk_cos_f32x4_neon_(angles_vec.f32x4);
|
|
555
|
+
nk_partial_store_b32x4_serial_(&results_vec, outs + i, remaining);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
NK_PUBLIC void nk_each_atan_f32_neon(nk_f32_t const *ins, nk_size_t n, nk_f32_t *outs) {
|
|
560
|
+
nk_size_t i = 0;
|
|
561
|
+
for (; i + 4 <= n; i += 4) {
|
|
562
|
+
float32x4_t values = vld1q_f32(ins + i);
|
|
563
|
+
float32x4_t results = nk_atan_f32x4_neon_(values);
|
|
564
|
+
vst1q_f32(outs + i, results);
|
|
565
|
+
}
|
|
566
|
+
if (i < n) {
|
|
567
|
+
nk_size_t remaining = n - i;
|
|
568
|
+
nk_b128_vec_t values_vec;
|
|
569
|
+
nk_partial_load_b32x4_serial_(ins + i, &values_vec, remaining);
|
|
570
|
+
nk_b128_vec_t results_vec;
|
|
571
|
+
results_vec.f32x4 = nk_atan_f32x4_neon_(values_vec.f32x4);
|
|
572
|
+
nk_partial_store_b32x4_serial_(&results_vec, outs + i, remaining);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
NK_PUBLIC void nk_each_sin_f64_neon(nk_f64_t const *ins, nk_size_t n, nk_f64_t *outs) {
|
|
577
|
+
nk_size_t i = 0;
|
|
578
|
+
for (; i + 2 <= n; i += 2) {
|
|
579
|
+
float64x2_t angles = vld1q_f64(ins + i);
|
|
580
|
+
float64x2_t results = nk_sin_f64x2_neon_(angles);
|
|
581
|
+
vst1q_f64(outs + i, results);
|
|
582
|
+
}
|
|
583
|
+
if (i < n) {
|
|
584
|
+
nk_size_t remaining = n - i;
|
|
585
|
+
nk_b128_vec_t angles_vec;
|
|
586
|
+
nk_partial_load_b64x2_serial_(ins + i, &angles_vec, remaining);
|
|
587
|
+
nk_b128_vec_t results_vec;
|
|
588
|
+
results_vec.f64x2 = nk_sin_f64x2_neon_(angles_vec.f64x2);
|
|
589
|
+
nk_partial_store_b64x2_serial_(&results_vec, outs + i, remaining);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
NK_PUBLIC void nk_each_cos_f64_neon(nk_f64_t const *ins, nk_size_t n, nk_f64_t *outs) {
|
|
594
|
+
nk_size_t i = 0;
|
|
595
|
+
for (; i + 2 <= n; i += 2) {
|
|
596
|
+
float64x2_t angles = vld1q_f64(ins + i);
|
|
597
|
+
float64x2_t results = nk_cos_f64x2_neon_(angles);
|
|
598
|
+
vst1q_f64(outs + i, results);
|
|
599
|
+
}
|
|
600
|
+
if (i < n) {
|
|
601
|
+
nk_size_t remaining = n - i;
|
|
602
|
+
nk_b128_vec_t angles_vec;
|
|
603
|
+
nk_partial_load_b64x2_serial_(ins + i, &angles_vec, remaining);
|
|
604
|
+
nk_b128_vec_t results_vec;
|
|
605
|
+
results_vec.f64x2 = nk_cos_f64x2_neon_(angles_vec.f64x2);
|
|
606
|
+
nk_partial_store_b64x2_serial_(&results_vec, outs + i, remaining);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
NK_PUBLIC void nk_each_atan_f64_neon(nk_f64_t const *ins, nk_size_t n, nk_f64_t *outs) {
|
|
611
|
+
nk_size_t i = 0;
|
|
612
|
+
for (; i + 2 <= n; i += 2) {
|
|
613
|
+
float64x2_t values = vld1q_f64(ins + i);
|
|
614
|
+
float64x2_t results = nk_atan_f64x2_neon_(values);
|
|
615
|
+
vst1q_f64(outs + i, results);
|
|
616
|
+
}
|
|
617
|
+
if (i < n) {
|
|
618
|
+
nk_size_t remaining = n - i;
|
|
619
|
+
nk_b128_vec_t values_vec;
|
|
620
|
+
nk_partial_load_b64x2_serial_(ins + i, &values_vec, remaining);
|
|
621
|
+
nk_b128_vec_t results_vec;
|
|
622
|
+
results_vec.f64x2 = nk_atan_f64x2_neon_(values_vec.f64x2);
|
|
623
|
+
nk_partial_store_b64x2_serial_(&results_vec, outs + i, remaining);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
#if defined(__clang__)
|
|
628
|
+
#pragma clang attribute pop
|
|
629
|
+
#elif defined(__GNUC__)
|
|
630
|
+
#pragma GCC pop_options
|
|
631
|
+
#endif
|
|
632
|
+
|
|
633
|
+
#if defined(__cplusplus)
|
|
634
|
+
} // extern "C"
|
|
635
|
+
#endif
|
|
636
|
+
|
|
637
|
+
#endif // NK_TARGET_NEON
|
|
638
|
+
#endif // NK_TARGET_ARM_
|
|
639
|
+
#endif // NK_TRIGONOMETRY_NEON_H
|