Skip to content

Commit b878d8a

Browse files
lntueyuxuanchen1997
authored andcommitted
[libc][math] Implement double precision cbrt correctly rounded to all rounding modes. (#99262)
Division-less Newton iterations algorithm for cube roots. 1. **Range reduction** For `x = (-1)^s * 2^e * (1.m)`, we get 2 reduced arguments `x_r` and `a` as: ``` x_r = 1.m a = (-1)^s * 2^(e % 3) * (1.m) ``` Then `cbrt(x) = x^(1/3)` can be computed as: ``` x^(1/3) = 2^(e / 3) * a^(1/3). ``` In order to avoid division, we compute `a^(-2/3)` using Newton method and then multiply the results by a: ``` a^(1/3) = a * a^(-2/3). ``` 2. **First approximation to a^(-2/3)** First, we use a degree-7 minimax polynomial generated by Sollya to approximate `x_r^(-2/3)` for `1 <= x_r < 2`. ``` p = P(x_r) ~ x_r^(-2/3), ``` with relative errors bounded by: ``` | p / x_r^(-2/3) - 1 | < 1.16 * 2^-21. ``` Then we multiply with `2^(e % 3)` from a small lookup table to get: ``` x_0 = 2^(-2*(e % 3)/3) * p ~ 2^(-2*(e % 3)/3) * x_r^(-2/3) = a^(-2/3) ``` with relative errors: ``` | x_0 / a^(-2/3) - 1 | < 1.16 * 2^-21. ``` This step is done in double precision. 3. **First Newton iteration** We follow the method described in: Sibidanov, A. and Zimmermann, P., "Correctly rounded cubic root evaluation in double precision", https://core-math.gitlabpages.inria.fr/cbrt64.pdf to derive multiplicative Newton iterations as below: Let `x_n` be the nth approximation to `a^(-2/3)`. Define the n^th error as: ``` h_n = x_n^3 * a^2 - 1 ``` Then: ``` a^(-2/3) = x_n / (1 + h_n)^(1/3) = x_n * (1 - (1/3) * h_n + (2/9) * h_n^2 - (14/81) * h_n^3 + ...) ``` using the Taylor series expansion of `(1 + h_n)^(-1/3)`. Apply to `x_0` above: ``` h_0 = x_0^3 * a^2 - 1 = a^2 * (x_0 - a^(-2/3)) * (x_0^2 + x_0 * a^(-2/3) + a^(-4/3)), ``` it's bounded by: ``` |h_0| < 4 * 3 * 1.16 * 2^-21 * 4 < 2^-17. ``` So in the first iteration step, we use: ``` x_1 = x_0 * (1 - (1/3) * h_n + (2/9) * h_n^2 - (14/81) * h_n^3) ``` Its relative error is bounded by: ``` | x_1 / a^(-2/3) - 1 | < 35/242 * |h_0|^4 < 2^-70. ``` Then we perform Ziv's rounding test and check if the answer is exact. This step is done in double-double precision. 4. **Second Newton iteration** If the Ziv's rounding test from the previous step fails, we define the error term: ``` h_1 = x_1^3 * a^2 - 1, ``` And perform another iteration: ``` x_2 = x_1 * (1 - h_1 / 3) ``` with the relative errors exceed the precision of double-double. We then check the Ziv's accuracy test with relative errors < 2^-102 to compensate for rounding errors. 5. **Final iteration** If the Ziv's accuracy test from the previous step fails, we perform another iteration in 128-bit precision and check for exact outputs.
1 parent 849b964 commit b878d8a

File tree

17 files changed

+548
-1
lines changed

17 files changed

+548
-1
lines changed

libc/config/darwin/arm/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ set(TARGET_LIBM_ENTRYPOINTS
123123
libc.src.math.atan2f
124124
libc.src.math.atanf
125125
libc.src.math.atanhf
126+
libc.src.math.cbrt
126127
libc.src.math.cbrtf
127128
libc.src.math.copysign
128129
libc.src.math.copysignf

libc/config/gpu/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ set(TARGET_LIBM_ENTRYPOINTS
245245
libc.src.math.atanf
246246
libc.src.math.atanh
247247
libc.src.math.atanhf
248+
libc.src.math.cbrt
248249
libc.src.math.cbrtf
249250
libc.src.math.ceil
250251
libc.src.math.ceilf

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ set(TARGET_LIBM_ENTRYPOINTS
345345
libc.src.math.atan2f
346346
libc.src.math.atanf
347347
libc.src.math.atanhf
348+
libc.src.math.cbrt
348349
libc.src.math.cbrtf
349350
libc.src.math.ceil
350351
libc.src.math.ceilf

libc/config/linux/arm/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ set(TARGET_LIBM_ENTRYPOINTS
216216
libc.src.math.atan2f
217217
libc.src.math.atanf
218218
libc.src.math.atanhf
219+
libc.src.math.cbrt
219220
libc.src.math.cbrtf
220221
libc.src.math.ceil
221222
libc.src.math.ceilf

libc/config/linux/riscv/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ set(TARGET_LIBM_ENTRYPOINTS
347347
libc.src.math.atan2f
348348
libc.src.math.atanf
349349
libc.src.math.atanhf
350+
libc.src.math.cbrt
350351
libc.src.math.cbrtf
351352
libc.src.math.ceil
352353
libc.src.math.ceilf

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ set(TARGET_LIBM_ENTRYPOINTS
370370
libc.src.math.canonicalize
371371
libc.src.math.canonicalizef
372372
libc.src.math.canonicalizel
373+
libc.src.math.cbrt
373374
libc.src.math.cbrtf
374375
libc.src.math.ceil
375376
libc.src.math.ceilf

libc/config/windows/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ set(TARGET_LIBM_ENTRYPOINTS
121121
libc.src.math.atan2f
122122
libc.src.math.atanf
123123
libc.src.math.atanhf
124+
libc.src.math.cbrt
124125
libc.src.math.cbrtf
125126
libc.src.math.copysign
126127
libc.src.math.copysignf

libc/docs/math/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ Higher Math Functions
266266
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
267267
| atanpi | | | | | | 7.12.4.10 | F.10.1.10 |
268268
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
269-
| cbrt | |check| | | | | | 7.12.7.1 | F.10.4.1 |
269+
| cbrt | |check| | |check| | | | | 7.12.7.1 | F.10.4.1 |
270270
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
271271
| compoundn | | | | | | 7.12.7.2 | F.10.4.2 |
272272
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+

libc/spec/stdc.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ def StdC : StandardSpec<"stdc"> {
382382
],
383383
[], // Enumerations
384384
[
385+
FunctionSpec<"cbrt", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
385386
FunctionSpec<"cbrtf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
386387

387388
FunctionSpec<"copysign", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,

libc/src/math/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ add_math_entrypoint_object(canonicalizel)
6565
add_math_entrypoint_object(canonicalizef16)
6666
add_math_entrypoint_object(canonicalizef128)
6767

68+
add_math_entrypoint_object(cbrt)
6869
add_math_entrypoint_object(cbrtf)
6970

7071
add_math_entrypoint_object(ceil)

libc/src/math/cbrt.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- Implementation header for cbrt --------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_MATH_CBRT_H
10+
#define LLVM_LIBC_SRC_MATH_CBRT_H
11+
12+
namespace LIBC_NAMESPACE {
13+
14+
double cbrt(double x);
15+
16+
} // namespace LIBC_NAMESPACE
17+
18+
#endif // LLVM_LIBC_SRC_MATH_CBRT_H

libc/src/math/generic/CMakeLists.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4180,3 +4180,23 @@ add_entrypoint_object(
41804180
libc.src.__support.FPUtil.multiply_add
41814181
libc.src.__support.macros.optimization
41824182
)
4183+
4184+
add_entrypoint_object(
4185+
cbrt
4186+
SRCS
4187+
cbrt.cpp
4188+
HDRS
4189+
../cbrt.h
4190+
COMPILE_OPTIONS
4191+
-O3
4192+
DEPENDS
4193+
libc.hdr.fenv_macros
4194+
libc.src.__support.FPUtil.double_double
4195+
libc.src.__support.FPUtil.dyadic_float
4196+
libc.src.__support.FPUtil.fenv_impl
4197+
libc.src.__support.FPUtil.fp_bits
4198+
libc.src.__support.FPUtil.multiply_add
4199+
libc.src.__support.FPUtil.polyeval
4200+
libc.src.__support.macros.optimization
4201+
libc.src.__support.integer_literals
4202+
)

0 commit comments

Comments
 (0)