usearch 2.21.4 → 2.25.1

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.
Files changed (604) hide show
  1. package/README.md +65 -69
  2. package/binding.gyp +15 -37
  3. package/c/CMakeLists.txt +4 -5
  4. package/c/README.md +8 -8
  5. package/c/lib.cpp +32 -14
  6. package/c/test.c +124 -1
  7. package/c/usearch.h +24 -3
  8. package/cpp/CMakeLists.txt +4 -0
  9. package/cpp/README.md +5 -5
  10. package/cpp/bench.cpp +97 -116
  11. package/cpp/test.cpp +117 -20
  12. package/include/usearch/index.hpp +224 -48
  13. package/include/usearch/index_dense.hpp +105 -40
  14. package/include/usearch/index_plugins.hpp +1387 -204
  15. package/javascript/README.md +1 -1
  16. package/javascript/dist/cjs/usearch.d.ts +8 -3
  17. package/javascript/dist/cjs/usearch.js +12 -4
  18. package/javascript/dist/esm/usearch.d.ts +8 -3
  19. package/javascript/dist/esm/usearch.js +12 -4
  20. package/javascript/lib.cpp +17 -0
  21. package/javascript/usearch.test.js +117 -94
  22. package/javascript/usearch.ts +14 -6
  23. package/numkong/.clang-tidy +30 -0
  24. package/{simsimd → numkong}/.cmake-format.py +18 -0
  25. package/numkong/.editorconfig +12 -0
  26. package/numkong/.git-blame-ignore-revs +123 -0
  27. package/numkong/.mailmap +15 -0
  28. package/numkong/.spi.yml +11 -0
  29. package/numkong/.swift-format +14 -0
  30. package/numkong/CITATION.cff +81 -0
  31. package/numkong/CONTRIBUTING.md +500 -0
  32. package/numkong/Cargo.toml +54 -0
  33. package/numkong/MANIFEST.in +8 -0
  34. package/numkong/Package.swift +84 -0
  35. package/numkong/README.md +569 -0
  36. package/numkong/bench/README.md +217 -0
  37. package/numkong/bench/bench-browser.html +323 -0
  38. package/numkong/bench/bench.cpp +344 -0
  39. package/numkong/bench/bench.hpp +816 -0
  40. package/numkong/bench/bench.js +148 -0
  41. package/numkong/bench/bench.mjs +616 -0
  42. package/numkong/bench/bench_attention.cpp +113 -0
  43. package/numkong/bench/bench_cast.cpp +264 -0
  44. package/numkong/bench/bench_cross_amx.cpp +62 -0
  45. package/numkong/bench/bench_cross_arm.cpp +245 -0
  46. package/numkong/bench/bench_cross_blas.cpp +309 -0
  47. package/numkong/bench/bench_cross_loongarch.cpp +106 -0
  48. package/numkong/bench/bench_cross_power.cpp +84 -0
  49. package/numkong/bench/bench_cross_rvv.cpp +121 -0
  50. package/numkong/bench/bench_cross_serial.cpp +151 -0
  51. package/numkong/bench/bench_cross_sme.cpp +163 -0
  52. package/numkong/bench/bench_cross_wasm.cpp +142 -0
  53. package/numkong/bench/bench_cross_x86.cpp +455 -0
  54. package/numkong/bench/bench_curved.cpp +210 -0
  55. package/numkong/bench/bench_dot.cpp +315 -0
  56. package/numkong/bench/bench_each.cpp +503 -0
  57. package/numkong/bench/bench_geospatial.cpp +112 -0
  58. package/numkong/bench/bench_maxsim.cpp +154 -0
  59. package/numkong/bench/bench_mesh.cpp +148 -0
  60. package/numkong/bench/bench_probability.cpp +60 -0
  61. package/numkong/bench/bench_reduce.cpp +371 -0
  62. package/numkong/bench/bench_set.cpp +73 -0
  63. package/numkong/bench/bench_sparse.cpp +198 -0
  64. package/numkong/bench/bench_spatial.cpp +347 -0
  65. package/numkong/bench/bench_trigonometry.cpp +137 -0
  66. package/numkong/bench/swift/Bench.swift +506 -0
  67. package/numkong/binding.gyp +169 -0
  68. package/numkong/build.rs +484 -0
  69. package/numkong/c/dispatch.h +512 -0
  70. package/numkong/c/dispatch_bf16.c +447 -0
  71. package/numkong/c/dispatch_bf16c.c +52 -0
  72. package/numkong/c/dispatch_e2m3.c +296 -0
  73. package/numkong/c/dispatch_e3m2.c +284 -0
  74. package/numkong/c/dispatch_e4m3.c +318 -0
  75. package/numkong/c/dispatch_e5m2.c +316 -0
  76. package/numkong/c/dispatch_f16.c +452 -0
  77. package/numkong/c/dispatch_f16c.c +58 -0
  78. package/numkong/c/dispatch_f32.c +434 -0
  79. package/numkong/c/dispatch_f32c.c +99 -0
  80. package/numkong/c/dispatch_f64.c +348 -0
  81. package/numkong/c/dispatch_f64c.c +98 -0
  82. package/numkong/c/dispatch_i16.c +96 -0
  83. package/numkong/c/dispatch_i32.c +89 -0
  84. package/numkong/c/dispatch_i4.c +153 -0
  85. package/numkong/c/dispatch_i64.c +86 -0
  86. package/numkong/c/dispatch_i8.c +348 -0
  87. package/numkong/c/dispatch_other.c +348 -0
  88. package/numkong/c/dispatch_u1.c +193 -0
  89. package/numkong/c/dispatch_u16.c +124 -0
  90. package/numkong/c/dispatch_u32.c +118 -0
  91. package/numkong/c/dispatch_u4.c +153 -0
  92. package/numkong/c/dispatch_u64.c +102 -0
  93. package/numkong/c/dispatch_u8.c +364 -0
  94. package/numkong/c/numkong.c +940 -0
  95. package/numkong/cmake/nk_arm_isa_probes.cmake +61 -0
  96. package/numkong/cmake/nk_isa_probe.cmake +90 -0
  97. package/numkong/cmake/nk_loongarch_isa_probes.cmake +15 -0
  98. package/numkong/cmake/nk_math_lib.cmake +46 -0
  99. package/numkong/cmake/nk_power_isa_probes.cmake +15 -0
  100. package/numkong/cmake/nk_riscv_isa_probes.cmake +19 -0
  101. package/numkong/cmake/nk_x86_isa_probes.cmake +35 -0
  102. package/numkong/cmake/toolchain-aarch64-gnu.cmake +86 -0
  103. package/numkong/cmake/toolchain-android-arm64.cmake +25 -0
  104. package/numkong/cmake/toolchain-android-armv7.cmake +25 -0
  105. package/numkong/cmake/toolchain-loongarch64-gnu.cmake +68 -0
  106. package/numkong/cmake/toolchain-ppc64le-gnu.cmake +74 -0
  107. package/numkong/cmake/toolchain-riscv64-gnu.cmake +107 -0
  108. package/numkong/cmake/toolchain-riscv64-llvm.cmake +114 -0
  109. package/numkong/cmake/toolchain-wasi.cmake +77 -0
  110. package/numkong/cmake/toolchain-wasm.cmake +70 -0
  111. package/numkong/cmake/toolchain-wasm64.cmake +62 -0
  112. package/numkong/cmake/toolchain-x86_64-llvm.cmake +47 -0
  113. package/numkong/include/README.md +643 -0
  114. package/numkong/include/module.modulemap +129 -0
  115. package/numkong/include/numkong/attention/sapphireamx.h +1363 -0
  116. package/numkong/include/numkong/attention/sme.h +2075 -0
  117. package/numkong/include/numkong/attention.h +49 -0
  118. package/numkong/include/numkong/capabilities.h +930 -0
  119. package/numkong/include/numkong/cast/README.md +262 -0
  120. package/numkong/include/numkong/cast/diamond.h +64 -0
  121. package/numkong/include/numkong/cast/haswell.h +823 -0
  122. package/numkong/include/numkong/cast/icelake.h +475 -0
  123. package/numkong/include/numkong/cast/loongsonasx.h +252 -0
  124. package/numkong/include/numkong/cast/neon.h +1174 -0
  125. package/numkong/include/numkong/cast/powervsx.h +449 -0
  126. package/numkong/include/numkong/cast/rvv.h +970 -0
  127. package/numkong/include/numkong/cast/sapphire.h +262 -0
  128. package/numkong/include/numkong/cast/serial.h +2336 -0
  129. package/numkong/include/numkong/cast/skylake.h +915 -0
  130. package/numkong/include/numkong/cast/v128relaxed.h +537 -0
  131. package/numkong/include/numkong/cast.h +254 -0
  132. package/numkong/include/numkong/cast.hpp +44 -0
  133. package/numkong/include/numkong/curved/README.md +223 -0
  134. package/numkong/include/numkong/curved/genoa.h +182 -0
  135. package/numkong/include/numkong/curved/haswell.h +276 -0
  136. package/numkong/include/numkong/curved/neon.h +329 -0
  137. package/numkong/include/numkong/curved/neonbfdot.h +211 -0
  138. package/numkong/include/numkong/curved/rvv.h +305 -0
  139. package/numkong/include/numkong/curved/serial.h +207 -0
  140. package/numkong/include/numkong/curved/skylake.h +457 -0
  141. package/numkong/include/numkong/curved/smef64.h +530 -0
  142. package/numkong/include/numkong/curved.h +513 -0
  143. package/numkong/include/numkong/curved.hpp +144 -0
  144. package/numkong/include/numkong/dot/README.md +442 -0
  145. package/numkong/include/numkong/dot/alder.h +563 -0
  146. package/numkong/include/numkong/dot/diamond.h +158 -0
  147. package/numkong/include/numkong/dot/genoa.h +289 -0
  148. package/numkong/include/numkong/dot/haswell.h +1723 -0
  149. package/numkong/include/numkong/dot/icelake.h +997 -0
  150. package/numkong/include/numkong/dot/loongsonasx.h +671 -0
  151. package/numkong/include/numkong/dot/neon.h +869 -0
  152. package/numkong/include/numkong/dot/neonbfdot.h +243 -0
  153. package/numkong/include/numkong/dot/neonfhm.h +358 -0
  154. package/numkong/include/numkong/dot/neonfp8.h +323 -0
  155. package/numkong/include/numkong/dot/neonsdot.h +622 -0
  156. package/numkong/include/numkong/dot/powervsx.h +752 -0
  157. package/numkong/include/numkong/dot/rvv.h +722 -0
  158. package/numkong/include/numkong/dot/rvvbb.h +72 -0
  159. package/numkong/include/numkong/dot/rvvbf16.h +123 -0
  160. package/numkong/include/numkong/dot/rvvhalf.h +129 -0
  161. package/numkong/include/numkong/dot/sapphire.h +141 -0
  162. package/numkong/include/numkong/dot/serial.h +874 -0
  163. package/numkong/include/numkong/dot/sierra.h +405 -0
  164. package/numkong/include/numkong/dot/skylake.h +1116 -0
  165. package/numkong/include/numkong/dot/sve.h +420 -0
  166. package/numkong/include/numkong/dot/svebfdot.h +75 -0
  167. package/numkong/include/numkong/dot/svehalf.h +168 -0
  168. package/numkong/include/numkong/dot/svesdot.h +90 -0
  169. package/numkong/include/numkong/dot/v128relaxed.h +1293 -0
  170. package/numkong/include/numkong/dot.h +1136 -0
  171. package/numkong/include/numkong/dot.hpp +94 -0
  172. package/numkong/include/numkong/dots/README.md +496 -0
  173. package/numkong/include/numkong/dots/alder.h +117 -0
  174. package/numkong/include/numkong/dots/diamond.h +86 -0
  175. package/numkong/include/numkong/dots/genoa.h +100 -0
  176. package/numkong/include/numkong/dots/graniteamx.h +733 -0
  177. package/numkong/include/numkong/dots/haswell.h +310 -0
  178. package/numkong/include/numkong/dots/icelake.h +180 -0
  179. package/numkong/include/numkong/dots/loongsonasx.h +176 -0
  180. package/numkong/include/numkong/dots/neon.h +123 -0
  181. package/numkong/include/numkong/dots/neonbfdot.h +59 -0
  182. package/numkong/include/numkong/dots/neonfhm.h +96 -0
  183. package/numkong/include/numkong/dots/neonfp8.h +99 -0
  184. package/numkong/include/numkong/dots/neonsdot.h +144 -0
  185. package/numkong/include/numkong/dots/powervsx.h +194 -0
  186. package/numkong/include/numkong/dots/rvv.h +2593 -0
  187. package/numkong/include/numkong/dots/sapphireamx.h +4017 -0
  188. package/numkong/include/numkong/dots/serial.h +2867 -0
  189. package/numkong/include/numkong/dots/sierra.h +100 -0
  190. package/numkong/include/numkong/dots/skylake.h +207 -0
  191. package/numkong/include/numkong/dots/sme.h +5041 -0
  192. package/numkong/include/numkong/dots/smebi32.h +477 -0
  193. package/numkong/include/numkong/dots/smef64.h +1328 -0
  194. package/numkong/include/numkong/dots/smehalf.h +47 -0
  195. package/numkong/include/numkong/dots/v128relaxed.h +317 -0
  196. package/numkong/include/numkong/dots.h +3110 -0
  197. package/numkong/include/numkong/dots.hpp +641 -0
  198. package/numkong/include/numkong/each/README.md +465 -0
  199. package/numkong/include/numkong/each/haswell.h +1658 -0
  200. package/numkong/include/numkong/each/icelake.h +272 -0
  201. package/numkong/include/numkong/each/neon.h +1138 -0
  202. package/numkong/include/numkong/each/neonbfdot.h +211 -0
  203. package/numkong/include/numkong/each/neonhalf.h +318 -0
  204. package/numkong/include/numkong/each/rvv.h +1121 -0
  205. package/numkong/include/numkong/each/sapphire.h +343 -0
  206. package/numkong/include/numkong/each/serial.h +282 -0
  207. package/numkong/include/numkong/each/skylake.h +1562 -0
  208. package/numkong/include/numkong/each/v128relaxed.h +562 -0
  209. package/numkong/include/numkong/each.h +2232 -0
  210. package/numkong/include/numkong/each.hpp +434 -0
  211. package/numkong/include/numkong/geospatial/README.md +147 -0
  212. package/numkong/include/numkong/geospatial/haswell.h +633 -0
  213. package/numkong/include/numkong/geospatial/neon.h +615 -0
  214. package/numkong/include/numkong/geospatial/rvv.h +701 -0
  215. package/numkong/include/numkong/geospatial/serial.h +309 -0
  216. package/numkong/include/numkong/geospatial/skylake.h +613 -0
  217. package/numkong/include/numkong/geospatial/v128relaxed.h +652 -0
  218. package/numkong/include/numkong/geospatial.h +453 -0
  219. package/numkong/include/numkong/geospatial.hpp +235 -0
  220. package/numkong/include/numkong/matrix.hpp +336 -0
  221. package/numkong/include/numkong/maxsim/README.md +187 -0
  222. package/numkong/include/numkong/maxsim/alder.h +511 -0
  223. package/numkong/include/numkong/maxsim/genoa.h +115 -0
  224. package/numkong/include/numkong/maxsim/haswell.h +553 -0
  225. package/numkong/include/numkong/maxsim/icelake.h +480 -0
  226. package/numkong/include/numkong/maxsim/neonsdot.h +394 -0
  227. package/numkong/include/numkong/maxsim/sapphireamx.h +877 -0
  228. package/numkong/include/numkong/maxsim/serial.h +490 -0
  229. package/numkong/include/numkong/maxsim/sme.h +993 -0
  230. package/numkong/include/numkong/maxsim/v128relaxed.h +280 -0
  231. package/numkong/include/numkong/maxsim.h +571 -0
  232. package/numkong/include/numkong/maxsim.hpp +133 -0
  233. package/numkong/include/numkong/mesh/README.md +219 -0
  234. package/numkong/include/numkong/mesh/haswell.h +2013 -0
  235. package/numkong/include/numkong/mesh/neon.h +1821 -0
  236. package/numkong/include/numkong/mesh/neonbfdot.h +771 -0
  237. package/numkong/include/numkong/mesh/rvv.h +936 -0
  238. package/numkong/include/numkong/mesh/serial.h +721 -0
  239. package/numkong/include/numkong/mesh/skylake.h +2344 -0
  240. package/numkong/include/numkong/mesh/v128relaxed.h +1081 -0
  241. package/numkong/include/numkong/mesh.h +666 -0
  242. package/numkong/include/numkong/mesh.hpp +701 -0
  243. package/numkong/include/numkong/numkong.h +78 -0
  244. package/numkong/include/numkong/numkong.hpp +58 -0
  245. package/numkong/include/numkong/probability/README.md +177 -0
  246. package/numkong/include/numkong/probability/haswell.h +267 -0
  247. package/numkong/include/numkong/probability/neon.h +255 -0
  248. package/numkong/include/numkong/probability/rvv.h +414 -0
  249. package/numkong/include/numkong/probability/serial.h +181 -0
  250. package/numkong/include/numkong/probability/skylake.h +324 -0
  251. package/numkong/include/numkong/probability.h +380 -0
  252. package/numkong/include/numkong/probability.hpp +120 -0
  253. package/numkong/include/numkong/random.h +50 -0
  254. package/numkong/include/numkong/random.hpp +285 -0
  255. package/numkong/include/numkong/reduce/README.md +552 -0
  256. package/numkong/include/numkong/reduce/alder.h +636 -0
  257. package/numkong/include/numkong/reduce/genoa.h +201 -0
  258. package/numkong/include/numkong/reduce/haswell.h +3785 -0
  259. package/numkong/include/numkong/reduce/icelake.h +549 -0
  260. package/numkong/include/numkong/reduce/neon.h +3980 -0
  261. package/numkong/include/numkong/reduce/neonbfdot.h +142 -0
  262. package/numkong/include/numkong/reduce/neonfhm.h +293 -0
  263. package/numkong/include/numkong/reduce/neonsdot.h +357 -0
  264. package/numkong/include/numkong/reduce/rvv.h +3533 -0
  265. package/numkong/include/numkong/reduce/serial.h +753 -0
  266. package/numkong/include/numkong/reduce/sierra.h +338 -0
  267. package/numkong/include/numkong/reduce/skylake.h +3794 -0
  268. package/numkong/include/numkong/reduce/sve.h +52 -0
  269. package/numkong/include/numkong/reduce/v128relaxed.h +2302 -0
  270. package/numkong/include/numkong/reduce.h +1582 -0
  271. package/numkong/include/numkong/reduce.hpp +778 -0
  272. package/numkong/include/numkong/scalar/README.md +89 -0
  273. package/numkong/include/numkong/scalar/haswell.h +122 -0
  274. package/numkong/include/numkong/scalar/loongsonasx.h +74 -0
  275. package/numkong/include/numkong/scalar/neon.h +122 -0
  276. package/numkong/include/numkong/scalar/neonhalf.h +70 -0
  277. package/numkong/include/numkong/scalar/powervsx.h +96 -0
  278. package/numkong/include/numkong/scalar/rvv.h +211 -0
  279. package/numkong/include/numkong/scalar/sapphire.h +74 -0
  280. package/numkong/include/numkong/scalar/serial.h +332 -0
  281. package/numkong/include/numkong/scalar/v128relaxed.h +56 -0
  282. package/numkong/include/numkong/scalar.h +696 -0
  283. package/numkong/include/numkong/set/README.md +179 -0
  284. package/numkong/include/numkong/set/haswell.h +334 -0
  285. package/numkong/include/numkong/set/icelake.h +485 -0
  286. package/numkong/include/numkong/set/loongsonasx.h +181 -0
  287. package/numkong/include/numkong/set/neon.h +363 -0
  288. package/numkong/include/numkong/set/powervsx.h +326 -0
  289. package/numkong/include/numkong/set/rvv.h +226 -0
  290. package/numkong/include/numkong/set/rvvbb.h +117 -0
  291. package/numkong/include/numkong/set/serial.h +174 -0
  292. package/numkong/include/numkong/set/sve.h +187 -0
  293. package/numkong/include/numkong/set/v128relaxed.h +240 -0
  294. package/numkong/include/numkong/set.h +471 -0
  295. package/numkong/include/numkong/set.hpp +114 -0
  296. package/numkong/include/numkong/sets/README.md +149 -0
  297. package/numkong/include/numkong/sets/haswell.h +63 -0
  298. package/numkong/include/numkong/sets/icelake.h +66 -0
  299. package/numkong/include/numkong/sets/loongsonasx.h +52 -0
  300. package/numkong/include/numkong/sets/neon.h +61 -0
  301. package/numkong/include/numkong/sets/powervsx.h +65 -0
  302. package/numkong/include/numkong/sets/serial.h +43 -0
  303. package/numkong/include/numkong/sets/smebi32.h +1135 -0
  304. package/numkong/include/numkong/sets/v128relaxed.h +58 -0
  305. package/numkong/include/numkong/sets.h +382 -0
  306. package/numkong/include/numkong/sparse/README.md +156 -0
  307. package/numkong/include/numkong/sparse/icelake.h +463 -0
  308. package/numkong/include/numkong/sparse/neon.h +288 -0
  309. package/numkong/include/numkong/sparse/serial.h +117 -0
  310. package/numkong/include/numkong/sparse/sve2.h +504 -0
  311. package/numkong/include/numkong/sparse/turin.h +322 -0
  312. package/numkong/include/numkong/sparse.h +363 -0
  313. package/numkong/include/numkong/sparse.hpp +113 -0
  314. package/numkong/include/numkong/spatial/README.md +439 -0
  315. package/numkong/include/numkong/spatial/alder.h +604 -0
  316. package/numkong/include/numkong/spatial/diamond.h +240 -0
  317. package/numkong/include/numkong/spatial/genoa.h +222 -0
  318. package/numkong/include/numkong/spatial/haswell.h +979 -0
  319. package/numkong/include/numkong/spatial/icelake.h +1067 -0
  320. package/numkong/include/numkong/spatial/loongsonasx.h +483 -0
  321. package/numkong/include/numkong/spatial/neon.h +846 -0
  322. package/numkong/include/numkong/spatial/neonbfdot.h +164 -0
  323. package/numkong/include/numkong/spatial/neonfp8.h +258 -0
  324. package/numkong/include/numkong/spatial/neonsdot.h +429 -0
  325. package/numkong/include/numkong/spatial/powervsx.h +738 -0
  326. package/numkong/include/numkong/spatial/rvv.h +991 -0
  327. package/numkong/include/numkong/spatial/rvvbf16.h +128 -0
  328. package/numkong/include/numkong/spatial/rvvhalf.h +120 -0
  329. package/numkong/include/numkong/spatial/serial.h +347 -0
  330. package/numkong/include/numkong/spatial/sierra.h +516 -0
  331. package/numkong/include/numkong/spatial/skylake.h +605 -0
  332. package/numkong/include/numkong/spatial/sve.h +246 -0
  333. package/numkong/include/numkong/spatial/svebfdot.h +125 -0
  334. package/numkong/include/numkong/spatial/svehalf.h +136 -0
  335. package/numkong/include/numkong/spatial/svesdot.h +143 -0
  336. package/numkong/include/numkong/spatial/v128relaxed.h +969 -0
  337. package/numkong/include/numkong/spatial.h +1681 -0
  338. package/numkong/include/numkong/spatial.hpp +183 -0
  339. package/numkong/include/numkong/spatials/README.md +580 -0
  340. package/numkong/include/numkong/spatials/alder.h +94 -0
  341. package/numkong/include/numkong/spatials/diamond.h +82 -0
  342. package/numkong/include/numkong/spatials/genoa.h +94 -0
  343. package/numkong/include/numkong/spatials/graniteamx.h +173 -0
  344. package/numkong/include/numkong/spatials/haswell.h +219 -0
  345. package/numkong/include/numkong/spatials/icelake.h +113 -0
  346. package/numkong/include/numkong/spatials/loongsonasx.h +153 -0
  347. package/numkong/include/numkong/spatials/neon.h +109 -0
  348. package/numkong/include/numkong/spatials/neonbfdot.h +60 -0
  349. package/numkong/include/numkong/spatials/neonfhm.h +92 -0
  350. package/numkong/include/numkong/spatials/neonfp8.h +111 -0
  351. package/numkong/include/numkong/spatials/neonsdot.h +143 -0
  352. package/numkong/include/numkong/spatials/powervsx.h +153 -0
  353. package/numkong/include/numkong/spatials/rvv.h +1976 -0
  354. package/numkong/include/numkong/spatials/sapphireamx.h +1149 -0
  355. package/numkong/include/numkong/spatials/serial.h +248 -0
  356. package/numkong/include/numkong/spatials/sierra.h +96 -0
  357. package/numkong/include/numkong/spatials/skylake.h +184 -0
  358. package/numkong/include/numkong/spatials/sme.h +1927 -0
  359. package/numkong/include/numkong/spatials/smef64.h +483 -0
  360. package/numkong/include/numkong/spatials/v128relaxed.h +240 -0
  361. package/numkong/include/numkong/spatials.h +3374 -0
  362. package/numkong/include/numkong/spatials.hpp +509 -0
  363. package/numkong/include/numkong/tensor.hpp +1981 -0
  364. package/numkong/include/numkong/trigonometry/README.md +184 -0
  365. package/numkong/include/numkong/trigonometry/haswell.h +653 -0
  366. package/numkong/include/numkong/trigonometry/neon.h +638 -0
  367. package/numkong/include/numkong/trigonometry/rvv.h +700 -0
  368. package/numkong/include/numkong/trigonometry/serial.h +703 -0
  369. package/numkong/include/numkong/trigonometry/skylake.h +725 -0
  370. package/numkong/include/numkong/trigonometry/v128relaxed.h +667 -0
  371. package/numkong/include/numkong/trigonometry.h +467 -0
  372. package/numkong/include/numkong/trigonometry.hpp +166 -0
  373. package/numkong/include/numkong/types.h +1695 -0
  374. package/numkong/include/numkong/types.hpp +6027 -0
  375. package/numkong/include/numkong/vector.hpp +766 -0
  376. package/numkong/javascript/@numkong-darwin-arm64/package.json +26 -0
  377. package/numkong/javascript/@numkong-darwin-x64/package.json +26 -0
  378. package/numkong/javascript/@numkong-linux-arm64/package.json +25 -0
  379. package/numkong/javascript/@numkong-linux-x64/package.json +25 -0
  380. package/numkong/javascript/@numkong-win32-arm64/package.json +25 -0
  381. package/numkong/javascript/@numkong-win32-x64/package.json +25 -0
  382. package/numkong/javascript/README.md +254 -0
  383. package/numkong/javascript/node-gyp-build.d.ts +4 -0
  384. package/numkong/javascript/numkong-browser.ts +40 -0
  385. package/numkong/javascript/numkong-wasm.ts +750 -0
  386. package/numkong/javascript/numkong.c +712 -0
  387. package/numkong/javascript/numkong.ts +613 -0
  388. package/{simsimd → numkong}/javascript/tsconfig-base.json +6 -3
  389. package/numkong/javascript/tsconfig-cjs.json +13 -0
  390. package/{simsimd → numkong}/javascript/tsconfig-esm.json +1 -1
  391. package/numkong/javascript/types.ts +784 -0
  392. package/numkong/numkong.gypi +104 -0
  393. package/numkong/package.json +108 -0
  394. package/numkong/probes/arm_neon.c +8 -0
  395. package/numkong/probes/arm_neon_bfdot.c +9 -0
  396. package/numkong/probes/arm_neon_fhm.c +9 -0
  397. package/numkong/probes/arm_neon_half.c +8 -0
  398. package/numkong/probes/arm_neon_sdot.c +9 -0
  399. package/numkong/probes/arm_neonfp8.c +9 -0
  400. package/numkong/probes/arm_sme.c +16 -0
  401. package/numkong/probes/arm_sme2.c +16 -0
  402. package/numkong/probes/arm_sme2p1.c +16 -0
  403. package/numkong/probes/arm_sme_bf16.c +16 -0
  404. package/numkong/probes/arm_sme_bi32.c +16 -0
  405. package/numkong/probes/arm_sme_f64.c +16 -0
  406. package/numkong/probes/arm_sme_fa64.c +14 -0
  407. package/numkong/probes/arm_sme_half.c +16 -0
  408. package/numkong/probes/arm_sme_lut2.c +15 -0
  409. package/numkong/probes/arm_sve.c +18 -0
  410. package/numkong/probes/arm_sve2.c +20 -0
  411. package/numkong/probes/arm_sve2p1.c +18 -0
  412. package/numkong/probes/arm_sve_bfdot.c +20 -0
  413. package/numkong/probes/arm_sve_half.c +18 -0
  414. package/numkong/probes/arm_sve_sdot.c +21 -0
  415. package/numkong/probes/loongarch_lasx.c +12 -0
  416. package/numkong/probes/power_vsx.c +12 -0
  417. package/numkong/probes/probe.js +127 -0
  418. package/numkong/probes/riscv_rvv.c +14 -0
  419. package/numkong/probes/riscv_rvv_bb.c +15 -0
  420. package/numkong/probes/riscv_rvv_bf16.c +17 -0
  421. package/numkong/probes/riscv_rvv_half.c +14 -0
  422. package/numkong/probes/wasm_v128relaxed.c +11 -0
  423. package/numkong/probes/x86_alder.c +17 -0
  424. package/numkong/probes/x86_diamond.c +17 -0
  425. package/numkong/probes/x86_genoa.c +17 -0
  426. package/numkong/probes/x86_graniteamx.c +19 -0
  427. package/numkong/probes/x86_haswell.c +11 -0
  428. package/numkong/probes/x86_icelake.c +17 -0
  429. package/numkong/probes/x86_sapphire.c +16 -0
  430. package/numkong/probes/x86_sapphireamx.c +18 -0
  431. package/numkong/probes/x86_sierra.c +17 -0
  432. package/numkong/probes/x86_skylake.c +15 -0
  433. package/numkong/probes/x86_turin.c +17 -0
  434. package/numkong/rust/README.md +698 -0
  435. package/numkong/rust/capabilities.rs +96 -0
  436. package/numkong/rust/cast.rs +314 -0
  437. package/numkong/rust/curved.rs +391 -0
  438. package/numkong/rust/each.rs +2721 -0
  439. package/numkong/rust/geospatial.rs +343 -0
  440. package/numkong/rust/matrix.rs +5424 -0
  441. package/numkong/rust/maxsim.rs +540 -0
  442. package/numkong/rust/mesh.rs +837 -0
  443. package/numkong/rust/numkong.rs +409 -0
  444. package/numkong/rust/probability.rs +272 -0
  445. package/numkong/rust/reduce.rs +1249 -0
  446. package/numkong/rust/set.rs +194 -0
  447. package/numkong/rust/sparse.rs +513 -0
  448. package/numkong/rust/spatial.rs +1815 -0
  449. package/numkong/rust/tensor.rs +7565 -0
  450. package/numkong/rust/types.rs +3666 -0
  451. package/numkong/rust/vector.rs +1899 -0
  452. package/numkong/rustfmt.toml +2 -0
  453. package/numkong/swift/Matrix.swift +1388 -0
  454. package/numkong/swift/MaxSim.swift +151 -0
  455. package/numkong/swift/NumKong.swift +283 -0
  456. package/numkong/swift/Numerics.swift +329 -0
  457. package/numkong/swift/README.md +433 -0
  458. package/numkong/swift/Scalar.swift +741 -0
  459. package/numkong/swift/Tensor.swift +209 -0
  460. package/numkong/test/README.md +315 -0
  461. package/numkong/test/playwright.config.ts +16 -0
  462. package/numkong/test/swift/Test.swift +534 -0
  463. package/numkong/test/test-browser-bundle-runner.mjs +36 -0
  464. package/numkong/test/test-browser-bundle.html +188 -0
  465. package/numkong/test/test-browser-runner.mjs +43 -0
  466. package/numkong/test/test-browser.html +305 -0
  467. package/numkong/test/test-dtypes.mjs +453 -0
  468. package/numkong/test/test-wasm.mjs +267 -0
  469. package/numkong/test/test.cpp +442 -0
  470. package/numkong/test/test.hpp +580 -0
  471. package/numkong/test/test.mjs +363 -0
  472. package/numkong/test/test_base.py +1041 -0
  473. package/numkong/test/test_cast.cpp +242 -0
  474. package/numkong/test/test_cross.hpp +551 -0
  475. package/numkong/test/test_cross.py +467 -0
  476. package/numkong/test/test_cross_amx.cpp +50 -0
  477. package/numkong/test/test_cross_arm.cpp +225 -0
  478. package/numkong/test/test_cross_blas.cpp +354 -0
  479. package/numkong/test/test_cross_loongarch.cpp +90 -0
  480. package/numkong/test/test_cross_power.cpp +73 -0
  481. package/numkong/test/test_cross_rvv.cpp +109 -0
  482. package/numkong/test/test_cross_serial.cpp +181 -0
  483. package/numkong/test/test_cross_sme.cpp +148 -0
  484. package/numkong/test/test_cross_wasm.cpp +141 -0
  485. package/numkong/test/test_cross_x86.cpp +442 -0
  486. package/numkong/test/test_curved.cpp +182 -0
  487. package/numkong/test/test_curved.py +207 -0
  488. package/numkong/test/test_dot.cpp +353 -0
  489. package/numkong/test/test_dot.py +296 -0
  490. package/numkong/test/test_each.cpp +437 -0
  491. package/numkong/test/test_each.py +756 -0
  492. package/numkong/test/test_geospatial.cpp +155 -0
  493. package/numkong/test/test_geospatial.py +241 -0
  494. package/numkong/test/test_maxsim.cpp +138 -0
  495. package/numkong/test/test_maxsim.py +209 -0
  496. package/numkong/test/test_mesh.cpp +203 -0
  497. package/numkong/test/test_mesh.py +394 -0
  498. package/numkong/test/test_probability.cpp +136 -0
  499. package/numkong/test/test_probability.py +166 -0
  500. package/numkong/test/test_reduce.cpp +563 -0
  501. package/numkong/test/test_reduce.py +781 -0
  502. package/numkong/test/test_set.cpp +151 -0
  503. package/numkong/test/test_set.py +120 -0
  504. package/numkong/test/test_similarities.py +579 -0
  505. package/numkong/test/test_sparse.cpp +121 -0
  506. package/numkong/test/test_sparse.py +118 -0
  507. package/numkong/test/test_spatial.cpp +518 -0
  508. package/numkong/test/test_spatial.py +269 -0
  509. package/numkong/test/test_tensor.cpp +884 -0
  510. package/numkong/test/test_tensor.py +1417 -0
  511. package/numkong/test/test_trigonometry.cpp +156 -0
  512. package/numkong/test/test_trigonometry.py +180 -0
  513. package/package.json +7 -8
  514. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  515. package/prebuilds/linux-arm64/usearch.node +0 -0
  516. package/prebuilds/linux-x64/usearch.node +0 -0
  517. package/fp16/CMakeLists.txt +0 -176
  518. package/fp16/LICENSE +0 -11
  519. package/fp16/README.md +0 -20
  520. package/fp16/bench/alt-element.cc +0 -89
  521. package/fp16/bench/from-alt-array.cc +0 -175
  522. package/fp16/bench/from-ieee-array.cc +0 -399
  523. package/fp16/bench/ieee-element.cc +0 -272
  524. package/fp16/bench/to-alt-array.cc +0 -91
  525. package/fp16/bench/to-ieee-array.cc +0 -303
  526. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  527. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  528. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  529. package/fp16/configure.py +0 -65
  530. package/fp16/confu.yaml +0 -8
  531. package/fp16/include/fp16/__init__.py +0 -0
  532. package/fp16/include/fp16/avx.py +0 -50
  533. package/fp16/include/fp16/avx2.py +0 -53
  534. package/fp16/include/fp16/bitcasts.h +0 -92
  535. package/fp16/include/fp16/fp16.h +0 -451
  536. package/fp16/include/fp16/psimd.h +0 -131
  537. package/fp16/include/fp16.h +0 -11
  538. package/fp16/jni/Android.mk +0 -6
  539. package/fp16/jni/Application.mk +0 -4
  540. package/fp16/test/alt-from-fp32-value.cc +0 -498
  541. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  542. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  543. package/fp16/test/alt-to-fp32-value.cc +0 -348
  544. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  545. package/fp16/test/bitcasts.cc +0 -56
  546. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  547. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  548. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  549. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  550. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  551. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  552. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  553. package/fp16/test/peachpy/stubs.py +0 -38
  554. package/fp16/test/tables.cc +0 -530
  555. package/fp16/test/tables.h +0 -13
  556. package/fp16/third-party/THHalf.h +0 -92
  557. package/fp16/third-party/eigen-half.h +0 -170
  558. package/fp16/third-party/float16-compressor.h +0 -80
  559. package/fp16/third-party/half.hpp +0 -2916
  560. package/fp16/third-party/npy-halffloat.h +0 -328
  561. package/simsimd/.git-blame-ignore-revs +0 -2
  562. package/simsimd/CONTRIBUTING.md +0 -321
  563. package/simsimd/Cargo.toml +0 -49
  564. package/simsimd/MANIFEST.in +0 -4
  565. package/simsimd/Package.swift +0 -28
  566. package/simsimd/README.md +0 -1493
  567. package/simsimd/binding.gyp +0 -35
  568. package/simsimd/build.rs +0 -70
  569. package/simsimd/c/lib.c +0 -374
  570. package/simsimd/include/module.modulemap +0 -4
  571. package/simsimd/include/simsimd/binary.h +0 -486
  572. package/simsimd/include/simsimd/curved.h +0 -1541
  573. package/simsimd/include/simsimd/dot.h +0 -1853
  574. package/simsimd/include/simsimd/elementwise.h +0 -2465
  575. package/simsimd/include/simsimd/geospatial.h +0 -43
  576. package/simsimd/include/simsimd/mesh.h +0 -69
  577. package/simsimd/include/simsimd/probability.h +0 -606
  578. package/simsimd/include/simsimd/simsimd.h +0 -2567
  579. package/simsimd/include/simsimd/sparse.h +0 -1384
  580. package/simsimd/include/simsimd/spatial.h +0 -2335
  581. package/simsimd/include/simsimd/types.h +0 -666
  582. package/simsimd/javascript/fallback.ts +0 -233
  583. package/simsimd/javascript/lib.c +0 -125
  584. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  585. package/simsimd/javascript/simsimd.ts +0 -179
  586. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  587. package/simsimd/package-lock.json +0 -1761
  588. package/simsimd/package.json +0 -61
  589. package/simsimd/rust/lib.rs +0 -1821
  590. package/simsimd/scripts/bench.cxx +0 -1170
  591. package/simsimd/scripts/bench.ipynb +0 -187
  592. package/simsimd/scripts/bench.js +0 -127
  593. package/simsimd/scripts/bench.rs +0 -876
  594. package/simsimd/scripts/bench_vectors.py +0 -734
  595. package/simsimd/scripts/bench_vectors_live.py +0 -213
  596. package/simsimd/scripts/test.c +0 -187
  597. package/simsimd/scripts/test.mjs +0 -220
  598. package/simsimd/scripts/test.py +0 -1505
  599. package/simsimd/swift/SimSIMD.swift +0 -149
  600. package/simsimd/swift/Test.swift +0 -128
  601. /package/{simsimd → numkong}/CODE_OF_CONDUCT.md +0 -0
  602. /package/{simsimd → numkong}/LICENSE +0 -0
  603. /package/{simsimd → numkong}/javascript/dist-package-cjs.json +0 -0
  604. /package/{simsimd → numkong}/javascript/dist-package-esm.json +0 -0
@@ -0,0 +1,653 @@
1
+ /**
2
+ * @brief SIMD-accelerated Trigonometric Functions for Haswell.
3
+ * @file include/numkong/trigonometry/haswell.h
4
+ * @author Ash Vardanian
5
+ * @date December 27, 2025
6
+ *
7
+ * @sa include/numkong/trigonometry.h
8
+ * @see https://sleef.org
9
+ *
10
+ * @section haswell_trig_instructions Key AVX2 Trigonometry Instructions
11
+ *
12
+ * Intrinsic Instruction Haswell Genoa
13
+ * _mm256_fmadd_ps/pd VFMADD (YMM, YMM, YMM) 5cy @ p01 4cy @ p01
14
+ * _mm256_mul_ps/pd VMULPS/PD (YMM, YMM, YMM) 5cy @ p01 3cy @ p01
15
+ * _mm256_blendv_ps/pd VBLENDVPS/PD (YMM, YMM, YMM) 2cy @ p015 1cy @ p01
16
+ * _mm256_round_ps/pd VROUNDPS/PD (YMM, YMM, I8) 6cy @ p01 3cy @ p23
17
+ * _mm256_div_ps VDIVPS (YMM, YMM, YMM) 13cy @ p0 11cy @ p01
18
+ *
19
+ * Polynomial evaluation uses Horner's method with FMA for sin/cos/atan approximation. For large
20
+ * arrays, out-of-order execution across loop iterations hides FMA latency better than Estrin's
21
+ * scheme. Range reduction uses argument folding modulo pi with high/low precision constants.
22
+ */
23
+ #ifndef NK_TRIGONOMETRY_HASWELL_H
24
+ #define NK_TRIGONOMETRY_HASWELL_H
25
+
26
+ #if NK_TARGET_X8664_
27
+ #if NK_TARGET_HASWELL
28
+
29
+ #include "numkong/types.h"
30
+ #include "numkong/reduce/haswell.h"
31
+
32
+ #if defined(__cplusplus)
33
+ extern "C" {
34
+ #endif
35
+
36
+ #if defined(__clang__)
37
+ #pragma clang attribute push(__attribute__((target("avx2,f16c,fma,bmi,bmi2"))), apply_to = function)
38
+ #elif defined(__GNUC__)
39
+ #pragma GCC push_options
40
+ #pragma GCC target("avx2", "f16c", "fma", "bmi", "bmi2")
41
+ #endif
42
+
43
+ /* Haswell AVX2 trigonometry kernels (8-way f32, 4-way f64)
44
+ * These implement the same polynomial approximations as Skylake but with 256-bit vectors.
45
+ */
46
+
47
+ NK_INTERNAL __m256 nk_sin_f32x8_haswell_(__m256 const angles_radians) {
48
+ // Cody-Waite constants for argument reduction
49
+ __m256 const pi_high_f32x8 = _mm256_set1_ps(3.1415927f);
50
+ __m256 const pi_low_f32x8 = _mm256_set1_ps(-8.742278e-8f);
51
+ __m256 const pi_reciprocal_f32x8 = _mm256_set1_ps(0.31830988618379067154f); // 1/π
52
+ // Degree-9 minimax coefficients
53
+ __m256 const coeff_9_f32x8 = _mm256_set1_ps(+2.7557319224e-6f);
54
+ __m256 const coeff_7_f32x8 = _mm256_set1_ps(-1.9841269841e-4f);
55
+ __m256 const coeff_5_f32x8 = _mm256_set1_ps(+8.3333293855e-3f);
56
+ __m256 const coeff_3_f32x8 = _mm256_set1_ps(-1.6666666641e-1f);
57
+
58
+ // Compute (multiples_of_pi_i32x8) = round(angle / π)
59
+ __m256 quotients_f32x8 = _mm256_mul_ps(angles_radians, pi_reciprocal_f32x8);
60
+ __m256 rounded_quotients_f32x8 = _mm256_round_ps(quotients_f32x8, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
61
+ // Use truncation (MXCSR-independent) since rounded_quotients_f32x8 is already integer-valued
62
+ __m256i multiples_of_pi_i32x8 = _mm256_cvttps_epi32(rounded_quotients_f32x8);
63
+
64
+ // Cody-Waite range reduction
65
+ __m256 angles_f32x8 = _mm256_fnmadd_ps(rounded_quotients_f32x8, pi_high_f32x8, angles_radians);
66
+ angles_f32x8 = _mm256_fnmadd_ps(rounded_quotients_f32x8, pi_low_f32x8, angles_f32x8);
67
+ __m256 const angles_squared_f32x8 = _mm256_mul_ps(angles_f32x8, angles_f32x8);
68
+ __m256 const angles_cubed_f32x8 = _mm256_mul_ps(angles_f32x8, angles_squared_f32x8);
69
+
70
+ // Degree-9 polynomial via Horner's method
71
+ __m256 polynomials_f32x8 = coeff_9_f32x8;
72
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, angles_squared_f32x8, coeff_7_f32x8);
73
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, angles_squared_f32x8, coeff_5_f32x8);
74
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, angles_squared_f32x8, coeff_3_f32x8);
75
+ __m256 results_f32x8 = _mm256_fmadd_ps(angles_cubed_f32x8, polynomials_f32x8, angles_f32x8);
76
+
77
+ // If multiples_of_pi_i32x8 is odd, flip the sign of the results_f32x8
78
+ __m256i parity_i32x8 = _mm256_and_si256(multiples_of_pi_i32x8, _mm256_set1_epi32(1));
79
+ __m256i odd_mask_i32x8 = _mm256_cmpeq_epi32(parity_i32x8, _mm256_set1_epi32(1));
80
+ __m256 float_mask_f32x8 = _mm256_castsi256_ps(odd_mask_i32x8);
81
+ __m256 negated_f32x8 = _mm256_sub_ps(_mm256_setzero_ps(), results_f32x8);
82
+ results_f32x8 = _mm256_blendv_ps(results_f32x8, negated_f32x8, float_mask_f32x8);
83
+ return results_f32x8;
84
+ }
85
+
86
+ NK_INTERNAL __m256 nk_cos_f32x8_haswell_(__m256 const angles_radians) {
87
+ // Cody-Waite constants for argument reduction
88
+ __m256 const pi_high_f32x8 = _mm256_set1_ps(3.1415927f);
89
+ __m256 const pi_low_f32x8 = _mm256_set1_ps(-8.742278e-8f);
90
+ __m256 const pi_half_f32x8 = _mm256_set1_ps(1.57079632679489661923f); // π/2
91
+ __m256 const pi_reciprocal_f32x8 = _mm256_set1_ps(0.31830988618379067154f); // 1/π
92
+ // Degree-9 minimax coefficients
93
+ __m256 const coeff_9_f32x8 = _mm256_set1_ps(+2.7557319224e-6f);
94
+ __m256 const coeff_7_f32x8 = _mm256_set1_ps(-1.9841269841e-4f);
95
+ __m256 const coeff_5_f32x8 = _mm256_set1_ps(+8.3333293855e-3f);
96
+ __m256 const coeff_3_f32x8 = _mm256_set1_ps(-1.6666666641e-1f);
97
+
98
+ // Compute (multiples_of_pi_i32x8) = round((angle / π) - 0.5)
99
+ __m256 quotients_f32x8 = _mm256_fmsub_ps(angles_radians, pi_reciprocal_f32x8, _mm256_set1_ps(0.5f));
100
+ __m256 rounded_quotients_f32x8 = _mm256_round_ps(quotients_f32x8, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
101
+ // Use truncation (MXCSR-independent) since rounded_quotients_f32x8 is already integer-valued
102
+ __m256i multiples_of_pi_i32x8 = _mm256_cvttps_epi32(rounded_quotients_f32x8);
103
+
104
+ // Cody-Waite range reduction: angle = angle_radians - (multiples * pi + pi/2)
105
+ __m256 const offset_f32x8 = _mm256_fmadd_ps(rounded_quotients_f32x8, pi_high_f32x8, pi_half_f32x8);
106
+ __m256 angles_f32x8 = _mm256_sub_ps(angles_radians, offset_f32x8);
107
+ angles_f32x8 = _mm256_fnmadd_ps(rounded_quotients_f32x8, pi_low_f32x8, angles_f32x8);
108
+ __m256 const angles_squared_f32x8 = _mm256_mul_ps(angles_f32x8, angles_f32x8);
109
+ __m256 const angles_cubed_f32x8 = _mm256_mul_ps(angles_f32x8, angles_squared_f32x8);
110
+
111
+ // Degree-9 polynomial via Horner's method
112
+ __m256 polynomials_f32x8 = coeff_9_f32x8;
113
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, angles_squared_f32x8, coeff_7_f32x8);
114
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, angles_squared_f32x8, coeff_5_f32x8);
115
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, angles_squared_f32x8, coeff_3_f32x8);
116
+ __m256 results_f32x8 = _mm256_fmadd_ps(angles_cubed_f32x8, polynomials_f32x8, angles_f32x8);
117
+
118
+ // If multiples_of_pi_i32x8 is even, flip the sign of the results_f32x8
119
+ __m256i parity_i32x8 = _mm256_and_si256(multiples_of_pi_i32x8, _mm256_set1_epi32(1));
120
+ __m256i even_mask_i32x8 = _mm256_cmpeq_epi32(parity_i32x8, _mm256_setzero_si256());
121
+ __m256 float_mask_f32x8 = _mm256_castsi256_ps(even_mask_i32x8);
122
+ __m256 negated_f32x8 = _mm256_sub_ps(_mm256_setzero_ps(), results_f32x8);
123
+ results_f32x8 = _mm256_blendv_ps(results_f32x8, negated_f32x8, float_mask_f32x8);
124
+ return results_f32x8;
125
+ }
126
+
127
+ NK_INTERNAL __m256 nk_atan_f32x8_haswell_(__m256 const inputs) {
128
+ // Polynomial coefficients for atan approximation (8 terms)
129
+ // These coefficients approximate: atan(x) ≈ x + c8 × x³ + c7 × x⁵ + c6 × x⁷ + ... + c1 × x¹⁵
130
+ __m256 const coeff_8_f32x8 = _mm256_set1_ps(-0.333331018686294555664062f);
131
+ __m256 const coeff_7_f32x8 = _mm256_set1_ps(+0.199926957488059997558594f);
132
+ __m256 const coeff_6_f32x8 = _mm256_set1_ps(-0.142027363181114196777344f);
133
+ __m256 const coeff_5_f32x8 = _mm256_set1_ps(+0.106347933411598205566406f);
134
+ __m256 const coeff_4_f32x8 = _mm256_set1_ps(-0.0748900920152664184570312f);
135
+ __m256 const coeff_3_f32x8 = _mm256_set1_ps(+0.0425049886107444763183594f);
136
+ __m256 const coeff_2_f32x8 = _mm256_set1_ps(-0.0159569028764963150024414f);
137
+ __m256 const coeff_1_f32x8 = _mm256_set1_ps(+0.00282363896258175373077393f);
138
+ __m256 const sign_mask_f32x8 = _mm256_set1_ps(-0.0f);
139
+
140
+ // Adjust for quadrant - detect negative values_f32x8
141
+ __m256 values_f32x8 = inputs;
142
+ __m256 negative_mask_f32x8 = _mm256_cmp_ps(values_f32x8, _mm256_setzero_ps(), _CMP_LT_OS);
143
+ values_f32x8 = _mm256_andnot_ps(sign_mask_f32x8, values_f32x8); // abs(values_f32x8)
144
+
145
+ // Check if values_f32x8 > 1 (need reciprocal)
146
+ __m256 reciprocal_mask_f32x8 = _mm256_cmp_ps(values_f32x8, _mm256_set1_ps(1.0f), _CMP_GT_OS);
147
+ __m256 reciprocal_values_f32x8 = _mm256_div_ps(_mm256_set1_ps(1.0f), values_f32x8);
148
+ values_f32x8 = _mm256_blendv_ps(values_f32x8, reciprocal_values_f32x8, reciprocal_mask_f32x8);
149
+
150
+ // Argument reduction
151
+ __m256 const values_squared_f32x8 = _mm256_mul_ps(values_f32x8, values_f32x8);
152
+ __m256 const values_cubed_f32x8 = _mm256_mul_ps(values_f32x8, values_squared_f32x8);
153
+
154
+ // Polynomial evaluation using Horner's method.
155
+ // For large arrays, out-of-order execution across loop iterations already hides
156
+ // FMA latency. Estrin's scheme was tested but showed ~20% regression because
157
+ // the extra power computations (y², y⁴) hurt throughput more than the reduced
158
+ // dependency depth helps latency.
159
+ __m256 polynomials_f32x8 = coeff_1_f32x8;
160
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, values_squared_f32x8, coeff_2_f32x8);
161
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, values_squared_f32x8, coeff_3_f32x8);
162
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, values_squared_f32x8, coeff_4_f32x8);
163
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, values_squared_f32x8, coeff_5_f32x8);
164
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, values_squared_f32x8, coeff_6_f32x8);
165
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, values_squared_f32x8, coeff_7_f32x8);
166
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, values_squared_f32x8, coeff_8_f32x8);
167
+
168
+ // Compute result_f32x8: atan(x) ≈ x + x³ * P(x²)
169
+ __m256 result_f32x8 = _mm256_fmadd_ps(values_cubed_f32x8, polynomials_f32x8, values_f32x8);
170
+
171
+ // Adjust for reciprocal: result_f32x8 = π/2 - result_f32x8
172
+ __m256 adjusted_f32x8 = _mm256_sub_ps(_mm256_set1_ps(1.5707963267948966f), result_f32x8);
173
+ result_f32x8 = _mm256_blendv_ps(result_f32x8, adjusted_f32x8, reciprocal_mask_f32x8);
174
+
175
+ // Adjust for negative: result_f32x8 = -result_f32x8
176
+ __m256 negated_f32x8 = _mm256_sub_ps(_mm256_setzero_ps(), result_f32x8);
177
+ result_f32x8 = _mm256_blendv_ps(result_f32x8, negated_f32x8, negative_mask_f32x8);
178
+ return result_f32x8;
179
+ }
180
+
181
+ NK_INTERNAL __m256 nk_atan2_f32x8_haswell_(__m256 const ys_inputs, __m256 const xs_inputs) {
182
+ // Polynomial coefficients (same as atan)
183
+ __m256 const coeff_8_f32x8 = _mm256_set1_ps(-0.333331018686294555664062f);
184
+ __m256 const coeff_7_f32x8 = _mm256_set1_ps(+0.199926957488059997558594f);
185
+ __m256 const coeff_6_f32x8 = _mm256_set1_ps(-0.142027363181114196777344f);
186
+ __m256 const coeff_5_f32x8 = _mm256_set1_ps(+0.106347933411598205566406f);
187
+ __m256 const coeff_4_f32x8 = _mm256_set1_ps(-0.0748900920152664184570312f);
188
+ __m256 const coeff_3_f32x8 = _mm256_set1_ps(+0.0425049886107444763183594f);
189
+ __m256 const coeff_2_f32x8 = _mm256_set1_ps(-0.0159569028764963150024414f);
190
+ __m256 const coeff_1_f32x8 = _mm256_set1_ps(+0.00282363896258175373077393f);
191
+ __m256 const sign_mask_f32x8 = _mm256_set1_ps(-0.0f);
192
+
193
+ // Quadrant adjustments normalizing to absolute values of x and y
194
+ __m256 xs_negative_mask_f32x8 = _mm256_cmp_ps(xs_inputs, _mm256_setzero_ps(), _CMP_LT_OS);
195
+ __m256 xs_f32x8 = _mm256_andnot_ps(sign_mask_f32x8, xs_inputs); // abs(xs_inputs)
196
+ __m256 ys_f32x8 = _mm256_andnot_ps(sign_mask_f32x8, ys_inputs); // abs(ys_inputs)
197
+
198
+ // Ensure proper fraction where the numerator is smaller than the denominator
199
+ __m256 swap_mask_f32x8 = _mm256_cmp_ps(ys_f32x8, xs_f32x8, _CMP_GT_OS);
200
+ __m256 temps_f32x8 = xs_f32x8;
201
+ xs_f32x8 = _mm256_blendv_ps(xs_f32x8, ys_f32x8, swap_mask_f32x8);
202
+ __m256 neg_temps_f32x8 = _mm256_sub_ps(_mm256_setzero_ps(), temps_f32x8);
203
+ ys_f32x8 = _mm256_blendv_ps(ys_f32x8, neg_temps_f32x8, swap_mask_f32x8);
204
+
205
+ // Compute ratio_f32x8 and powers
206
+ __m256 const ratio_f32x8 = _mm256_div_ps(ys_f32x8, xs_f32x8);
207
+ __m256 const ratio_squared_f32x8 = _mm256_mul_ps(ratio_f32x8, ratio_f32x8);
208
+ __m256 const ratio_cubed_f32x8 = _mm256_mul_ps(ratio_f32x8, ratio_squared_f32x8);
209
+
210
+ // Polynomial evaluation using Horner's method
211
+ __m256 polynomials_f32x8 = coeff_1_f32x8;
212
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, ratio_squared_f32x8, coeff_2_f32x8);
213
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, ratio_squared_f32x8, coeff_3_f32x8);
214
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, ratio_squared_f32x8, coeff_4_f32x8);
215
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, ratio_squared_f32x8, coeff_5_f32x8);
216
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, ratio_squared_f32x8, coeff_6_f32x8);
217
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, ratio_squared_f32x8, coeff_7_f32x8);
218
+ polynomials_f32x8 = _mm256_fmadd_ps(polynomials_f32x8, ratio_squared_f32x8, coeff_8_f32x8);
219
+
220
+ // Compute the result using masks for quadrant_f32x8 adjustments
221
+ __m256 results_f32x8 = _mm256_fmadd_ps(ratio_cubed_f32x8, polynomials_f32x8, ratio_f32x8);
222
+
223
+ // Compute quadrant_f32x8 value: 0 for x>=0 && !swap, 1 for x>=0 && swap,
224
+ // -2 for x<0 && !swap, -1 for x<0 && swap
225
+ __m256 quadrant_f32x8 = _mm256_setzero_ps();
226
+ __m256 neg_two_f32x8 = _mm256_set1_ps(-2.0f);
227
+ quadrant_f32x8 = _mm256_blendv_ps(quadrant_f32x8, neg_two_f32x8, xs_negative_mask_f32x8);
228
+ __m256 one_f32x8 = _mm256_set1_ps(1.0f);
229
+ __m256 quadrant_incremented_f32x8 = _mm256_add_ps(quadrant_f32x8, one_f32x8);
230
+ quadrant_f32x8 = _mm256_blendv_ps(quadrant_f32x8, quadrant_incremented_f32x8, swap_mask_f32x8);
231
+
232
+ // Adjust for quadrant_f32x8: result += quadrant_f32x8 * π/2
233
+ __m256 pi_half_f32x8 = _mm256_set1_ps(1.5707963267948966f);
234
+ results_f32x8 = _mm256_fmadd_ps(quadrant_f32x8, pi_half_f32x8, results_f32x8);
235
+
236
+ // Transfer sign from x (XOR with sign bit of x_input)
237
+ __m256 xs_sign_bits_f32x8 = _mm256_and_ps(xs_inputs, sign_mask_f32x8);
238
+ results_f32x8 = _mm256_xor_ps(results_f32x8, xs_sign_bits_f32x8);
239
+
240
+ // Transfer sign from y (XOR with sign bit of y_input)
241
+ __m256 ys_sign_bits_f32x8 = _mm256_and_ps(ys_inputs, sign_mask_f32x8);
242
+ results_f32x8 = _mm256_xor_ps(results_f32x8, ys_sign_bits_f32x8);
243
+
244
+ return results_f32x8;
245
+ }
246
+
247
+ NK_INTERNAL __m256d nk_sin_f64x4_haswell_(__m256d const angles_radians) {
248
+ // Constants for argument reduction
249
+ __m256d const pi_high_f64x4 = _mm256_set1_pd(3.141592653589793116); // High-digits part of π
250
+ __m256d const pi_low_f64x4 = _mm256_set1_pd(1.2246467991473532072e-16); // Low-digits part of π
251
+ __m256d const pi_reciprocal_f64x4 = _mm256_set1_pd(0.31830988618379067154); // 1/π
252
+
253
+ // Polynomial coefficients for sine approximation (minimax polynomial)
254
+ __m256d const coeff_0_f64x4 = _mm256_set1_pd(+0.00833333333333332974823815);
255
+ __m256d const coeff_1_f64x4 = _mm256_set1_pd(-0.000198412698412696162806809);
256
+ __m256d const coeff_2_f64x4 = _mm256_set1_pd(+2.75573192239198747630416e-06);
257
+ __m256d const coeff_3_f64x4 = _mm256_set1_pd(-2.50521083763502045810755e-08);
258
+ __m256d const coeff_4_f64x4 = _mm256_set1_pd(+1.60590430605664501629054e-10);
259
+ __m256d const coeff_5_f64x4 = _mm256_set1_pd(-7.64712219118158833288484e-13);
260
+ __m256d const coeff_6_f64x4 = _mm256_set1_pd(+2.81009972710863200091251e-15);
261
+ __m256d const coeff_7_f64x4 = _mm256_set1_pd(-7.97255955009037868891952e-18);
262
+ __m256d const coeff_8_f64x4 = _mm256_set1_pd(-0.166666666666666657414808);
263
+
264
+ // Compute (rounded_quotients_f64x4) = round(angle / π)
265
+ __m256d const quotients_f64x4 = _mm256_mul_pd(angles_radians, pi_reciprocal_f64x4);
266
+ __m256d const rounded_quotients_f64x4 = _mm256_round_pd(quotients_f64x4,
267
+ _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
268
+
269
+ // Reduce the angle: angle - (rounded_quotients_f64x4 * π_high + rounded_quotients_f64x4 * π_low)
270
+ __m256d angles_f64x4 = angles_radians;
271
+ angles_f64x4 = _mm256_fnmadd_pd(rounded_quotients_f64x4, pi_high_f64x4, angles_f64x4);
272
+ angles_f64x4 = _mm256_fnmadd_pd(rounded_quotients_f64x4, pi_low_f64x4, angles_f64x4);
273
+
274
+ // If rounded_quotients_f64x4 is odd (bit 0 set), negate the angle
275
+ // Convert to 32-bit int (returns __m128i with 4 x 32-bit ints)
276
+ // Use truncation (MXCSR-independent) since rounded_quotients_f64x4 is already integer-valued
277
+ __m128i quotients_i32_i32x4 = _mm256_cvttpd_epi32(rounded_quotients_f64x4);
278
+ __m128i parity_i32x4 = _mm_and_si128(quotients_i32_i32x4, _mm_set1_epi32(1));
279
+ __m128i odd_mask_i32_i32x4 = _mm_cmpeq_epi32(parity_i32x4, _mm_set1_epi32(1));
280
+ // Expand 32-bit mask to 64-bit by shuffling
281
+ __m256i odd_mask_i64_i32x8 = _mm256_cvtepi32_epi64(odd_mask_i32_i32x4);
282
+ __m256d float_mask_f64x4 = _mm256_castsi256_pd(odd_mask_i64_i32x8);
283
+ __m256d negated_angles_f64x4 = _mm256_sub_pd(_mm256_setzero_pd(), angles_f64x4);
284
+ angles_f64x4 = _mm256_blendv_pd(angles_f64x4, negated_angles_f64x4, float_mask_f64x4);
285
+
286
+ __m256d const angles_squared_f64x4 = _mm256_mul_pd(angles_f64x4, angles_f64x4);
287
+ __m256d const angles_cubed_f64x4 = _mm256_mul_pd(angles_f64x4, angles_squared_f64x4);
288
+ __m256d const angles_quadratic_f64x4 = _mm256_mul_pd(angles_squared_f64x4, angles_squared_f64x4);
289
+ __m256d const angles_octic_f64x4 = _mm256_mul_pd(angles_quadratic_f64x4, angles_quadratic_f64x4);
290
+
291
+ // Compute higher-degree polynomial terms
292
+ __m256d const poly_67_f64x4 = _mm256_fmadd_pd(angles_squared_f64x4, coeff_7_f64x4, coeff_6_f64x4);
293
+ __m256d const poly_45_f64x4 = _mm256_fmadd_pd(angles_squared_f64x4, coeff_5_f64x4, coeff_4_f64x4);
294
+ __m256d const poly_4567_f64x4 = _mm256_fmadd_pd(angles_quadratic_f64x4, poly_67_f64x4, poly_45_f64x4);
295
+
296
+ // Compute lower-degree polynomial terms
297
+ __m256d const poly_23_f64x4 = _mm256_fmadd_pd(angles_squared_f64x4, coeff_3_f64x4, coeff_2_f64x4);
298
+ __m256d const poly_01_f64x4 = _mm256_fmadd_pd(angles_squared_f64x4, coeff_1_f64x4, coeff_0_f64x4);
299
+ __m256d const poly_0123_f64x4 = _mm256_fmadd_pd(angles_quadratic_f64x4, poly_23_f64x4, poly_01_f64x4);
300
+
301
+ // Combine polynomial terms
302
+ __m256d results_f64x4 = _mm256_fmadd_pd(angles_octic_f64x4, poly_4567_f64x4, poly_0123_f64x4);
303
+ results_f64x4 = _mm256_fmadd_pd(results_f64x4, angles_squared_f64x4, coeff_8_f64x4);
304
+ results_f64x4 = _mm256_fmadd_pd(results_f64x4, angles_cubed_f64x4, angles_f64x4);
305
+
306
+ // Handle the special case of negative zero input
307
+ __m256d const non_zero_mask_f64x4 = _mm256_cmp_pd(angles_radians, _mm256_setzero_pd(), _CMP_NEQ_UQ);
308
+ results_f64x4 = _mm256_and_pd(results_f64x4, non_zero_mask_f64x4);
309
+ return results_f64x4;
310
+ }
311
+
312
+ NK_INTERNAL __m256d nk_cos_f64x4_haswell_(__m256d const angles_radians) {
313
+ // Constants for argument reduction
314
+ __m256d const pi_high_half_f64x4 = _mm256_set1_pd(3.141592653589793116 * 0.5); // High-digits part of π/2
315
+ __m256d const pi_low_half_f64x4 = _mm256_set1_pd(1.2246467991473532072e-16 * 0.5); // Low-digits part of π/2
316
+ __m256d const pi_reciprocal_f64x4 = _mm256_set1_pd(0.31830988618379067154); // 1/π
317
+
318
+ // Polynomial coefficients for cosine approximation
319
+ __m256d const coeff_0_f64x4 = _mm256_set1_pd(+0.00833333333333332974823815);
320
+ __m256d const coeff_1_f64x4 = _mm256_set1_pd(-0.000198412698412696162806809);
321
+ __m256d const coeff_2_f64x4 = _mm256_set1_pd(+2.75573192239198747630416e-06);
322
+ __m256d const coeff_3_f64x4 = _mm256_set1_pd(-2.50521083763502045810755e-08);
323
+ __m256d const coeff_4_f64x4 = _mm256_set1_pd(+1.60590430605664501629054e-10);
324
+ __m256d const coeff_5_f64x4 = _mm256_set1_pd(-7.64712219118158833288484e-13);
325
+ __m256d const coeff_6_f64x4 = _mm256_set1_pd(+2.81009972710863200091251e-15);
326
+ __m256d const coeff_7_f64x4 = _mm256_set1_pd(-7.97255955009037868891952e-18);
327
+ __m256d const coeff_8_f64x4 = _mm256_set1_pd(-0.166666666666666657414808);
328
+
329
+ // Compute (rounded_quotients_f64x4) = 2 * round(angle / π - 0.5) + 1
330
+ // Use fmsub: a*b - c = angles_f64x4 * (1/π) - 0.5
331
+ __m256d const quotients_f64x4 = _mm256_fmsub_pd(angles_radians, pi_reciprocal_f64x4, _mm256_set1_pd(0.5));
332
+ __m256d const rounded_quotients_f64x4 = _mm256_fmadd_pd( //
333
+ _mm256_set1_pd(2.0), //
334
+ _mm256_round_pd(quotients_f64x4, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC), //
335
+ _mm256_set1_pd(1.0));
336
+
337
+ // Reduce the angle: angle - (rounded_quotients_f64x4 * π_high_half + rounded_quotients_f64x4 * π_low_half)
338
+ __m256d angles_f64x4 = angles_radians;
339
+ angles_f64x4 = _mm256_fnmadd_pd(rounded_quotients_f64x4, pi_high_half_f64x4, angles_f64x4);
340
+ angles_f64x4 = _mm256_fnmadd_pd(rounded_quotients_f64x4, pi_low_half_f64x4, angles_f64x4);
341
+
342
+ // If (rounded_quotients_f64x4 & 2) == 0, negate the angle
343
+ // Use truncation (MXCSR-independent) since rounded_quotients_f64x4 is already integer-valued
344
+ __m128i quotients_i32_i32x4 = _mm256_cvttpd_epi32(rounded_quotients_f64x4);
345
+ __m128i bit2_i32x4 = _mm_and_si128(quotients_i32_i32x4, _mm_set1_epi32(2));
346
+ __m128i flip_mask_i32_i32x4 = _mm_cmpeq_epi32(bit2_i32x4, _mm_setzero_si128());
347
+ __m256i flip_mask_i64_i32x8 = _mm256_cvtepi32_epi64(flip_mask_i32_i32x4);
348
+ __m256d float_mask_f64x4 = _mm256_castsi256_pd(flip_mask_i64_i32x8);
349
+ __m256d negated_angles_f64x4 = _mm256_sub_pd(_mm256_setzero_pd(), angles_f64x4);
350
+ angles_f64x4 = _mm256_blendv_pd(angles_f64x4, negated_angles_f64x4, float_mask_f64x4);
351
+
352
+ __m256d const angles_squared_f64x4 = _mm256_mul_pd(angles_f64x4, angles_f64x4);
353
+ __m256d const angles_cubed_f64x4 = _mm256_mul_pd(angles_f64x4, angles_squared_f64x4);
354
+ __m256d const angles_quadratic_f64x4 = _mm256_mul_pd(angles_squared_f64x4, angles_squared_f64x4);
355
+ __m256d const angles_octic_f64x4 = _mm256_mul_pd(angles_quadratic_f64x4, angles_quadratic_f64x4);
356
+
357
+ // Compute higher-degree polynomial terms
358
+ __m256d const poly_67_f64x4 = _mm256_fmadd_pd(angles_squared_f64x4, coeff_7_f64x4, coeff_6_f64x4);
359
+ __m256d const poly_45_f64x4 = _mm256_fmadd_pd(angles_squared_f64x4, coeff_5_f64x4, coeff_4_f64x4);
360
+ __m256d const poly_4567_f64x4 = _mm256_fmadd_pd(angles_quadratic_f64x4, poly_67_f64x4, poly_45_f64x4);
361
+
362
+ // Compute lower-degree polynomial terms
363
+ __m256d const poly_23_f64x4 = _mm256_fmadd_pd(angles_squared_f64x4, coeff_3_f64x4, coeff_2_f64x4);
364
+ __m256d const poly_01_f64x4 = _mm256_fmadd_pd(angles_squared_f64x4, coeff_1_f64x4, coeff_0_f64x4);
365
+ __m256d const poly_0123_f64x4 = _mm256_fmadd_pd(angles_quadratic_f64x4, poly_23_f64x4, poly_01_f64x4);
366
+
367
+ // Combine polynomial terms
368
+ __m256d results_f64x4 = _mm256_fmadd_pd(angles_octic_f64x4, poly_4567_f64x4, poly_0123_f64x4);
369
+ results_f64x4 = _mm256_fmadd_pd(results_f64x4, angles_squared_f64x4, coeff_8_f64x4);
370
+ results_f64x4 = _mm256_fmadd_pd(results_f64x4, angles_cubed_f64x4, angles_f64x4);
371
+ return results_f64x4;
372
+ }
373
+
374
+ NK_INTERNAL __m256d nk_atan_f64x4_haswell_(__m256d const inputs) {
375
+ // Polynomial coefficients for atan approximation (19 coefficients)
376
+ // The polynomial approximates: atan(x) ≈ x + x³ * P(x²) where P has 19 terms
377
+ __m256d const coeff_19_f64x4 = _mm256_set1_pd(-1.88796008463073496563746e-05);
378
+ __m256d const coeff_18_f64x4 = _mm256_set1_pd(+0.000209850076645816976906797);
379
+ __m256d const coeff_17_f64x4 = _mm256_set1_pd(-0.00110611831486672482563471);
380
+ __m256d const coeff_16_f64x4 = _mm256_set1_pd(+0.00370026744188713119232403);
381
+ __m256d const coeff_15_f64x4 = _mm256_set1_pd(-0.00889896195887655491740809);
382
+ __m256d const coeff_14_f64x4 = _mm256_set1_pd(+0.016599329773529201970117);
383
+ __m256d const coeff_13_f64x4 = _mm256_set1_pd(-0.0254517624932312641616861);
384
+ __m256d const coeff_12_f64x4 = _mm256_set1_pd(+0.0337852580001353069993897);
385
+ __m256d const coeff_11_f64x4 = _mm256_set1_pd(-0.0407629191276836500001934);
386
+ __m256d const coeff_10_f64x4 = _mm256_set1_pd(+0.0466667150077840625632675);
387
+ __m256d const coeff_9_f64x4 = _mm256_set1_pd(-0.0523674852303482457616113);
388
+ __m256d const coeff_8_f64x4 = _mm256_set1_pd(+0.0587666392926673580854313);
389
+ __m256d const coeff_7_f64x4 = _mm256_set1_pd(-0.0666573579361080525984562);
390
+ __m256d const coeff_6_f64x4 = _mm256_set1_pd(+0.0769219538311769618355029);
391
+ __m256d const coeff_5_f64x4 = _mm256_set1_pd(-0.090908995008245008229153);
392
+ __m256d const coeff_4_f64x4 = _mm256_set1_pd(+0.111111105648261418443745);
393
+ __m256d const coeff_3_f64x4 = _mm256_set1_pd(-0.14285714266771329383765);
394
+ __m256d const coeff_2_f64x4 = _mm256_set1_pd(+0.199999999996591265594148);
395
+ __m256d const coeff_1_f64x4 = _mm256_set1_pd(-0.333333333333311110369124);
396
+ __m256d const sign_mask_f64x4 = _mm256_set1_pd(-0.0);
397
+
398
+ // Adjust for quadrant - detect negative values_f64x4
399
+ __m256d values_f64x4 = inputs;
400
+ __m256d negative_mask_f64x4 = _mm256_cmp_pd(values_f64x4, _mm256_setzero_pd(), _CMP_LT_OS);
401
+ values_f64x4 = _mm256_andnot_pd(sign_mask_f64x4, values_f64x4); // abs(values_f64x4)
402
+
403
+ // Check if values_f64x4 > 1 (need reciprocal)
404
+ // Note: For f64, we keep VDIVPD since RCPPD doesn't exist and Newton-Raphson
405
+ // would need 2 iterations for sufficient precision (~44 bits needed for f64)
406
+ __m256d reciprocal_mask_f64x4 = _mm256_cmp_pd(values_f64x4, _mm256_set1_pd(1.0), _CMP_GT_OS);
407
+ __m256d reciprocal_values_f64x4 = _mm256_div_pd(_mm256_set1_pd(1.0), values_f64x4);
408
+ values_f64x4 = _mm256_blendv_pd(values_f64x4, reciprocal_values_f64x4, reciprocal_mask_f64x4);
409
+
410
+ // Argument reduction
411
+ __m256d const values_squared_f64x4 = _mm256_mul_pd(values_f64x4, values_f64x4);
412
+ __m256d const values_cubed_f64x4 = _mm256_mul_pd(values_f64x4, values_squared_f64x4);
413
+
414
+ // Polynomial evaluation using Horner's method.
415
+ // For large arrays, out-of-order execution across loop iterations already hides
416
+ // FMA latency. Estrin's scheme was tested but showed minimal improvement (~1%)
417
+ // while adding complexity. Keeping Horner for maintainability.
418
+ __m256d polynomials_f64x4 = coeff_19_f64x4;
419
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_18_f64x4);
420
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_17_f64x4);
421
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_16_f64x4);
422
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_15_f64x4);
423
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_14_f64x4);
424
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_13_f64x4);
425
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_12_f64x4);
426
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_11_f64x4);
427
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_10_f64x4);
428
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_9_f64x4);
429
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_8_f64x4);
430
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_7_f64x4);
431
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_6_f64x4);
432
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_5_f64x4);
433
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_4_f64x4);
434
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_3_f64x4);
435
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_2_f64x4);
436
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, values_squared_f64x4, coeff_1_f64x4);
437
+
438
+ // Compute result_f64x4
439
+ __m256d result_f64x4 = _mm256_fmadd_pd(values_cubed_f64x4, polynomials_f64x4, values_f64x4);
440
+
441
+ // Adjust for reciprocal: result_f64x4 = π/2 - result_f64x4
442
+ __m256d adjusted_f64x4 = _mm256_sub_pd(_mm256_set1_pd(1.5707963267948966), result_f64x4);
443
+ result_f64x4 = _mm256_blendv_pd(result_f64x4, adjusted_f64x4, reciprocal_mask_f64x4);
444
+
445
+ // Adjust for negative: result_f64x4 = -result_f64x4
446
+ __m256d negated_f64x4 = _mm256_sub_pd(_mm256_setzero_pd(), result_f64x4);
447
+ result_f64x4 = _mm256_blendv_pd(result_f64x4, negated_f64x4, negative_mask_f64x4);
448
+ return result_f64x4;
449
+ }
450
+
451
+ NK_INTERNAL __m256d nk_atan2_f64x4_haswell_(__m256d const ys_inputs, __m256d const xs_inputs) {
452
+ // Polynomial coefficients for atan approximation (19 coefficients, same as atan)
453
+ __m256d const coeff_19_f64x4 = _mm256_set1_pd(-1.88796008463073496563746e-05);
454
+ __m256d const coeff_18_f64x4 = _mm256_set1_pd(+0.000209850076645816976906797);
455
+ __m256d const coeff_17_f64x4 = _mm256_set1_pd(-0.00110611831486672482563471);
456
+ __m256d const coeff_16_f64x4 = _mm256_set1_pd(+0.00370026744188713119232403);
457
+ __m256d const coeff_15_f64x4 = _mm256_set1_pd(-0.00889896195887655491740809);
458
+ __m256d const coeff_14_f64x4 = _mm256_set1_pd(+0.016599329773529201970117);
459
+ __m256d const coeff_13_f64x4 = _mm256_set1_pd(-0.0254517624932312641616861);
460
+ __m256d const coeff_12_f64x4 = _mm256_set1_pd(+0.0337852580001353069993897);
461
+ __m256d const coeff_11_f64x4 = _mm256_set1_pd(-0.0407629191276836500001934);
462
+ __m256d const coeff_10_f64x4 = _mm256_set1_pd(+0.0466667150077840625632675);
463
+ __m256d const coeff_9_f64x4 = _mm256_set1_pd(-0.0523674852303482457616113);
464
+ __m256d const coeff_8_f64x4 = _mm256_set1_pd(+0.0587666392926673580854313);
465
+ __m256d const coeff_7_f64x4 = _mm256_set1_pd(-0.0666573579361080525984562);
466
+ __m256d const coeff_6_f64x4 = _mm256_set1_pd(+0.0769219538311769618355029);
467
+ __m256d const coeff_5_f64x4 = _mm256_set1_pd(-0.090908995008245008229153);
468
+ __m256d const coeff_4_f64x4 = _mm256_set1_pd(+0.111111105648261418443745);
469
+ __m256d const coeff_3_f64x4 = _mm256_set1_pd(-0.14285714266771329383765);
470
+ __m256d const coeff_2_f64x4 = _mm256_set1_pd(+0.199999999996591265594148);
471
+ __m256d const coeff_1_f64x4 = _mm256_set1_pd(-0.333333333333311110369124);
472
+ __m256d const sign_mask_f64x4 = _mm256_set1_pd(-0.0);
473
+
474
+ // Quadrant adjustments normalizing to absolute values of x and y
475
+ __m256d xs_negative_mask_f64x4 = _mm256_cmp_pd(xs_inputs, _mm256_setzero_pd(), _CMP_LT_OS);
476
+ __m256d xs_f64x4 = _mm256_andnot_pd(sign_mask_f64x4, xs_inputs); // abs(xs_inputs)
477
+ __m256d ys_f64x4 = _mm256_andnot_pd(sign_mask_f64x4, ys_inputs); // abs(ys_inputs)
478
+
479
+ // Ensure proper fraction where the numerator is smaller than the denominator
480
+ __m256d swap_mask_f64x4 = _mm256_cmp_pd(ys_f64x4, xs_f64x4, _CMP_GT_OS);
481
+ __m256d temps_f64x4 = xs_f64x4;
482
+ xs_f64x4 = _mm256_blendv_pd(xs_f64x4, ys_f64x4, swap_mask_f64x4);
483
+ __m256d neg_temps_f64x4 = _mm256_sub_pd(_mm256_setzero_pd(), temps_f64x4);
484
+ ys_f64x4 = _mm256_blendv_pd(ys_f64x4, neg_temps_f64x4, swap_mask_f64x4);
485
+
486
+ // Compute ratio_f64x4 and powers
487
+ __m256d const ratio_f64x4 = _mm256_div_pd(ys_f64x4, xs_f64x4);
488
+ __m256d const ratio_squared_f64x4 = _mm256_mul_pd(ratio_f64x4, ratio_f64x4);
489
+ __m256d const ratio_cubed_f64x4 = _mm256_mul_pd(ratio_f64x4, ratio_squared_f64x4);
490
+
491
+ // Polynomial evaluation using Horner's method
492
+ __m256d polynomials_f64x4 = coeff_19_f64x4;
493
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_18_f64x4);
494
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_17_f64x4);
495
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_16_f64x4);
496
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_15_f64x4);
497
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_14_f64x4);
498
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_13_f64x4);
499
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_12_f64x4);
500
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_11_f64x4);
501
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_10_f64x4);
502
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_9_f64x4);
503
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_8_f64x4);
504
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_7_f64x4);
505
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_6_f64x4);
506
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_5_f64x4);
507
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_4_f64x4);
508
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_3_f64x4);
509
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_2_f64x4);
510
+ polynomials_f64x4 = _mm256_fmadd_pd(polynomials_f64x4, ratio_squared_f64x4, coeff_1_f64x4);
511
+
512
+ // Compute the result using masks for quadrant_f64x4 adjustments
513
+ __m256d results_f64x4 = _mm256_fmadd_pd(ratio_cubed_f64x4, polynomials_f64x4, ratio_f64x4);
514
+
515
+ // Compute quadrant_f64x4 value: 0 for x>=0 && !swap, 1 for x>=0 && swap,
516
+ // -2 for x<0 && !swap, -1 for x<0 && swap
517
+ __m256d quadrant_f64x4 = _mm256_setzero_pd();
518
+ __m256d neg_two_f64x4 = _mm256_set1_pd(-2.0);
519
+ quadrant_f64x4 = _mm256_blendv_pd(quadrant_f64x4, neg_two_f64x4, xs_negative_mask_f64x4);
520
+ __m256d one_f64x4 = _mm256_set1_pd(1.0);
521
+ __m256d quadrant_incremented_f64x4 = _mm256_add_pd(quadrant_f64x4, one_f64x4);
522
+ quadrant_f64x4 = _mm256_blendv_pd(quadrant_f64x4, quadrant_incremented_f64x4, swap_mask_f64x4);
523
+
524
+ // Adjust for quadrant_f64x4: result += quadrant_f64x4 * π/2
525
+ __m256d pi_half_f64x4 = _mm256_set1_pd(1.5707963267948966);
526
+ results_f64x4 = _mm256_fmadd_pd(quadrant_f64x4, pi_half_f64x4, results_f64x4);
527
+
528
+ // Transfer sign from x (XOR with sign bit of x_input)
529
+ __m256d xs_sign_bits_f64x4 = _mm256_and_pd(xs_inputs, sign_mask_f64x4);
530
+ results_f64x4 = _mm256_xor_pd(results_f64x4, xs_sign_bits_f64x4);
531
+
532
+ // Transfer sign from y (XOR with sign bit of y_input)
533
+ __m256d ys_sign_bits_f64x4 = _mm256_and_pd(ys_inputs, sign_mask_f64x4);
534
+ results_f64x4 = _mm256_xor_pd(results_f64x4, ys_sign_bits_f64x4);
535
+
536
+ return results_f64x4;
537
+ }
538
+
539
+ NK_PUBLIC void nk_each_sin_f32_haswell(nk_f32_t const *ins, nk_size_t n, nk_f32_t *outs) {
540
+ nk_size_t i = 0;
541
+ for (; i + 8 <= n; i += 8) {
542
+ __m256 angles_f32x8 = _mm256_loadu_ps(ins + i);
543
+ __m256 results_f32x8 = nk_sin_f32x8_haswell_(angles_f32x8);
544
+ _mm256_storeu_ps(outs + i, results_f32x8);
545
+ }
546
+ if (i < n) {
547
+ nk_size_t remaining = n - i;
548
+ nk_b256_vec_t angles_vec;
549
+ nk_partial_load_b32x8_serial_(ins + i, &angles_vec, remaining);
550
+ nk_b256_vec_t results_vec;
551
+ results_vec.ymm_ps = nk_sin_f32x8_haswell_(angles_vec.ymm_ps);
552
+ nk_partial_store_b32x8_serial_(&results_vec, outs + i, remaining);
553
+ }
554
+ }
555
+
556
+ NK_PUBLIC void nk_each_cos_f32_haswell(nk_f32_t const *ins, nk_size_t n, nk_f32_t *outs) {
557
+ nk_size_t i = 0;
558
+ for (; i + 8 <= n; i += 8) {
559
+ __m256 angles_f32x8 = _mm256_loadu_ps(ins + i);
560
+ __m256 results_f32x8 = nk_cos_f32x8_haswell_(angles_f32x8);
561
+ _mm256_storeu_ps(outs + i, results_f32x8);
562
+ }
563
+ if (i < n) {
564
+ nk_size_t remaining = n - i;
565
+ nk_b256_vec_t angles_vec;
566
+ nk_partial_load_b32x8_serial_(ins + i, &angles_vec, remaining);
567
+ nk_b256_vec_t results_vec;
568
+ results_vec.ymm_ps = nk_cos_f32x8_haswell_(angles_vec.ymm_ps);
569
+ nk_partial_store_b32x8_serial_(&results_vec, outs + i, remaining);
570
+ }
571
+ }
572
+
573
+ NK_PUBLIC void nk_each_atan_f32_haswell(nk_f32_t const *ins, nk_size_t n, nk_f32_t *outs) {
574
+ nk_size_t i = 0;
575
+ for (; i + 8 <= n; i += 8) {
576
+ __m256 values_f32x8 = _mm256_loadu_ps(ins + i);
577
+ __m256 results_f32x8 = nk_atan_f32x8_haswell_(values_f32x8);
578
+ _mm256_storeu_ps(outs + i, results_f32x8);
579
+ }
580
+ if (i < n) {
581
+ nk_size_t remaining = n - i;
582
+ nk_b256_vec_t values_vec;
583
+ nk_partial_load_b32x8_serial_(ins + i, &values_vec, remaining);
584
+ nk_b256_vec_t results_vec;
585
+ results_vec.ymm_ps = nk_atan_f32x8_haswell_(values_vec.ymm_ps);
586
+ nk_partial_store_b32x8_serial_(&results_vec, outs + i, remaining);
587
+ }
588
+ }
589
+
590
+ NK_PUBLIC void nk_each_sin_f64_haswell(nk_f64_t const *ins, nk_size_t n, nk_f64_t *outs) {
591
+ nk_size_t i = 0;
592
+ for (; i + 4 <= n; i += 4) {
593
+ __m256d angles_f64x4 = _mm256_loadu_pd(ins + i);
594
+ __m256d results_f64x4 = nk_sin_f64x4_haswell_(angles_f64x4);
595
+ _mm256_storeu_pd(outs + i, results_f64x4);
596
+ }
597
+ if (i < n) {
598
+ nk_size_t remaining = n - i;
599
+ nk_b256_vec_t angles_vec;
600
+ nk_partial_load_b64x4_haswell_(ins + i, &angles_vec, remaining);
601
+ nk_b256_vec_t results_vec;
602
+ results_vec.ymm_pd = nk_sin_f64x4_haswell_(angles_vec.ymm_pd);
603
+ nk_partial_store_b64x4_haswell_(&results_vec, outs + i, remaining);
604
+ }
605
+ }
606
+
607
+ NK_PUBLIC void nk_each_cos_f64_haswell(nk_f64_t const *ins, nk_size_t n, nk_f64_t *outs) {
608
+ nk_size_t i = 0;
609
+ for (; i + 4 <= n; i += 4) {
610
+ __m256d angles_f64x4 = _mm256_loadu_pd(ins + i);
611
+ __m256d results_f64x4 = nk_cos_f64x4_haswell_(angles_f64x4);
612
+ _mm256_storeu_pd(outs + i, results_f64x4);
613
+ }
614
+ if (i < n) {
615
+ nk_size_t remaining = n - i;
616
+ nk_b256_vec_t angles_vec;
617
+ nk_partial_load_b64x4_haswell_(ins + i, &angles_vec, remaining);
618
+ nk_b256_vec_t results_vec;
619
+ results_vec.ymm_pd = nk_cos_f64x4_haswell_(angles_vec.ymm_pd);
620
+ nk_partial_store_b64x4_haswell_(&results_vec, outs + i, remaining);
621
+ }
622
+ }
623
+
624
+ NK_PUBLIC void nk_each_atan_f64_haswell(nk_f64_t const *ins, nk_size_t n, nk_f64_t *outs) {
625
+ nk_size_t i = 0;
626
+ for (; i + 4 <= n; i += 4) {
627
+ __m256d values_f64x4 = _mm256_loadu_pd(ins + i);
628
+ __m256d results_f64x4 = nk_atan_f64x4_haswell_(values_f64x4);
629
+ _mm256_storeu_pd(outs + i, results_f64x4);
630
+ }
631
+ if (i < n) {
632
+ nk_size_t remaining = n - i;
633
+ nk_b256_vec_t values_vec;
634
+ nk_partial_load_b64x4_haswell_(ins + i, &values_vec, remaining);
635
+ nk_b256_vec_t results_vec;
636
+ results_vec.ymm_pd = nk_atan_f64x4_haswell_(values_vec.ymm_pd);
637
+ nk_partial_store_b64x4_haswell_(&results_vec, outs + i, remaining);
638
+ }
639
+ }
640
+
641
+ #if defined(__clang__)
642
+ #pragma clang attribute pop
643
+ #elif defined(__GNUC__)
644
+ #pragma GCC pop_options
645
+ #endif
646
+
647
+ #if defined(__cplusplus)
648
+ } // extern "C"
649
+ #endif
650
+
651
+ #endif // NK_TARGET_HASWELL
652
+ #endif // NK_TARGET_X8664_
653
+ #endif // NK_TRIGONOMETRY_HASWELL_H