# Optimization: rsqrt + Newton, divide killed - **Author**: Linus - **Predecessor**: variant_float_inlining_SoA_AVX2_polyexp.cpp - **File(s)**: variants/variant_float_inlining_SoA_AVX2_polyexp_rsqrt.cpp - **Status**: approx 10 to 20 percent faster ## What this changes We replace all three `_mm256_sqrt_ps` calls with `_mm256_rsqrt_ps`, which gives us `1/sqrt(x)` directly. We then recover the sqrt itself with one extra multiply (`sqrt(x) = x * rsqrt(x)`) and reuse the inverses to rewrite the force scaling so that the final `vdivps` disappears. No Newton-Raphson refinement: we accept the ~12-bit precision of plain `vrsqrtps` since the verify tolerance is 1cm. ## Code See `variants/variant_float_inlining_SoA_AVX2_polyexp_rsqrt.cpp`. Asm has 3 vrsqrtps, 0 vsqrtps, 0 vdivps. ## Benchmark Conditions: N_ITER=1000, -O3 -march=native -flto, diff vs the polyexp predecessor. ### x86 **Machine**: TBD **Frequency**: TBD | N | W(n) [Flops] | T(n) [Cycles] | Performance [Flops/Cycle] | Diff vs Predecessor | | ---- | ------------ | ------------- | ------------------------- | ------------------- | | 50 | | | | | | 100 | | | | | | 200 | | | | | | 500 | | | | | ### ARM no avx2 here ## Analysis The win comes primarily from killing the `vdivps`, not from the sqrt latency change. `vdivps` has 5-cycle throughput on port 0 (the divider port), and each j-block had exactly one of them in the force-scaling step. Removing it frees up port 0 for the three sqrts that also live there. Replacing `vsqrtps` with `vrsqrtps` + multiply contributes a smaller piece: it shortens each sqrt from ~12 cycles latency to ~8, and the muls land on the FMA ports rather than port 0, so the divider port load drops further. The accuracy cost is ~12 bits of mantissa precision, which is well within the 1cm verify tolerance . I also tried adding a Newton-Raphson refinement step to recover full sqrt precision. That variant ran slower than the pure-rsqrt version: the NR step adds 2 muls and one fnmadd on top of rsqrt, putting the recovered sqrt at ~20 cycles of latency, which is worse than vsqrtps's 12. The speedup is consistent (~18-22% across all N), which suggests the divider port is on the j-block critical path at every problem size, not just at one particular working-set range. ## Takeaway probably not worth keeping. polyexp is faster on the perf machine at every size we measured.