[PATCH 3/4] math: Make rsqrtf correctly rounded
Adhemerval Zanella
adhemerval.zanella@linaro.org
Tue Sep 22 14:28:37 GMT 2026
The generic implementation computes 1.0f / sqrtf (x), which rounds twice
and shows up to 1 ulp for rounding to nearest (for about 26% of the
inputs) and up to 2 ulp for the directed roundings.
Using double precision is a straightforward way to get the correctly
rounded resuls, and it was exhaustively tested for all possible inputs
on different machines (x86_64, aarch64, powerpc, loongarch64).
The performacne results shows a performance hit, since to use the
double version requires extra single to double rounding. Benchtests on
x86_64 (Ryzen 9 5900X), aarch64 (Neoverse-N1), powerpc (POWER10, built
for power8), and loongarch64 (Loongson-3C5000L-LL) shows:
* latency
- input: [0.5,2)
master patched improvement
x86_64 23.8349 35.2275 -32.34%
x86_64-v2 24.0356 35.2532 -31.82%
x86_64-v3 22.7667 34.0389 -33.12%
aarch64 7.7400 13.4675 -42.53%
powerpc 7.1457 9.7876 -26.99%
loongarch64 2.1518 3.4530 -37.68%
- input: normal
master patched improvement
x86_64 23.6777 35.1879 -32.71%
x86_64-v2 24.0492 35.7858 -32.80%
x86_64-v3 22.7498 33.9989 -33.09%
aarch64 7.7401 13.4679 -42.53%
powerpc 7.1465 9.7657 -26.82%
loongarch64 2.1519 3.4527 -37.68%
- input: subnormal
master patched improvement
x86_64 35.6423 35.1984 1.26%
x86_64-v2 35.5350 35.4863 0.14%
x86_64-v3 32.1197 33.9955 -5.52%
aarch64 8.0830 13.4669 -39.98%
powerpc 7.1431 9.7794 -26.96%
loongarch64 2.2020 3.4524 -36.22%
* reciprocal-throughput
- input: [0.5,2)
master patched improvement
x86_64 8.4902 10.8043 -21.42%
x86_64-v2 9.3151 10.5439 -11.65%
x86_64-v3 8.4450 10.8503 -22.17%
aarch64 3.8338 5.8337 -34.28%
powerpc 1.7494 2.4880 -29.69%
loongarch64 1.7027 1.8515 -8.04%
- input: normal
master patched improvement
x86_64 8.4228 10.7892 -21.93%
x86_64-v2 9.2843 10.6977 -13.21%
x86_64-v3 8.4090 10.8325 -22.37%
aarch64 3.8345 5.8413 -34.36%
powerpc 1.7454 2.4812 -29.66%
loongarch64 1.7026 1.8514 -8.04%
- input: subnormal
master patched improvement
x86_64 15.0495 10.7866 39.52%
x86_64-v2 14.2217 10.6250 33.85%
x86_64-v3 14.2447 10.8250 31.59%
aarch64 3.9800 5.8460 -31.92%
powerpc 1.7488 2.4808 -29.51%
loongarch64 1.7026 1.8514 -8.04%
Checked on aarch64-linux-gnu, x86_64-linux-gnu, powerpc64le-linux-gnu,
and loongarch64-linux-gnuf64.
---
sysdeps/ieee754/flt-32/libm-test-ulps | 12 +++++++++++
sysdeps/ieee754/flt-32/s_rsqrtf.c | 30 +++++++++++++++++++++++++++
2 files changed, 42 insertions(+)
create mode 100644 sysdeps/ieee754/flt-32/s_rsqrtf.c
diff --git a/sysdeps/ieee754/flt-32/libm-test-ulps b/sysdeps/ieee754/flt-32/libm-test-ulps
index 15a7248d8b4..52a9238c828 100644
--- a/sysdeps/ieee754/flt-32/libm-test-ulps
+++ b/sysdeps/ieee754/flt-32/libm-test-ulps
@@ -251,6 +251,18 @@ float: 0
Function: "log2p1_upward":
float: 0
+Function: "rsqrt":
+float: 0
+
+Function: "rsqrt_downward":
+float: 0
+
+Function: "rsqrt_towardzero":
+float: 0
+
+Function: "rsqrt_upward":
+float: 0
+
Function: "sinh":
float: 0
diff --git a/sysdeps/ieee754/flt-32/s_rsqrtf.c b/sysdeps/ieee754/flt-32/s_rsqrtf.c
new file mode 100644
index 00000000000..112b024794d
--- /dev/null
+++ b/sysdeps/ieee754/flt-32/s_rsqrtf.c
@@ -0,0 +1,30 @@
+/* Correctly rounded reciprocal square root of binary32 value.
+ Copyright (C) 2026 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <math.h>
+#include <libm-alias-float.h>
+
+float
+__rsqrtf (float x)
+{
+ if (islessequal (x, 0.0f))
+ __set_errno (x < 0 ? EDOM : ERANGE);
+ return 1.0 / sqrt ((double) x);
+}
+libm_alias_float (__rsqrt, rsqrt)
--
2.53.0
More information about the Libc-alpha
mailing list