Skip to content

Commit 7d68d9d

Browse files
authored
[libc][math] Implement correctly rounded double precision tan (#97489)
Using the same range reduction as `sin`, `cos`, and `sincos`: 1) Reducing `x = k*pi/128 + u`, with `|u| <= pi/256`, and `u` is in double-double. 2) Approximate `tan(u)` using degree-9 Taylor polynomial. 3) Compute ``` tan(x) ~ (sin(k*pi/128) + tan(u) * cos(k*pi/128)) / (cos(k*pi/128) - tan(u) * sin(k*pi/128)) ``` using the fast double-double division algorithm in [the CORE-MATH project](https://gitlab.inria.fr/core-math/core-math/-/blob/master/src/binary64/tan/tan.c#L1855). 4) Perform relative-error Ziv's accuracy test 5) If the accuracy tests failed, we redo the computations using 128-bit precision `DyadicFloat`. Fixes #96930
1 parent 5828b04 commit 7d68d9d

File tree

13 files changed

+518
-46
lines changed

13 files changed

+518
-46
lines changed

libc/config/darwin/arm/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ set(TARGET_LIBM_ENTRYPOINTS
234234
libc.src.math.sqrt
235235
libc.src.math.sqrtf
236236
libc.src.math.sqrtl
237+
libc.src.math.tan
237238
libc.src.math.tanf
238239
libc.src.math.tanhf
239240
libc.src.math.trunc

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@ set(TARGET_LIBM_ENTRYPOINTS
489489
libc.src.math.sqrt
490490
libc.src.math.sqrtf
491491
libc.src.math.sqrtl
492+
libc.src.math.tan
492493
libc.src.math.tanf
493494
libc.src.math.tanhf
494495
libc.src.math.trunc

libc/config/linux/arm/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ set(TARGET_LIBM_ENTRYPOINTS
366366
libc.src.math.sqrt
367367
libc.src.math.sqrtf
368368
libc.src.math.sqrtl
369+
libc.src.math.tan
369370
libc.src.math.tanf
370371
libc.src.math.tanhf
371372
libc.src.math.trunc

libc/config/linux/riscv/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ set(TARGET_LIBM_ENTRYPOINTS
497497
libc.src.math.sqrt
498498
libc.src.math.sqrtf
499499
libc.src.math.sqrtl
500+
libc.src.math.tan
500501
libc.src.math.tanf
501502
libc.src.math.tanhf
502503
libc.src.math.trunc

libc/docs/math/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ Higher Math Functions
338338
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
339339
| sqrt | |check| | |check| | |check| | | |check| | 7.12.7.10 | F.10.4.10 |
340340
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
341-
| tan | |check| | | | | | 7.12.4.7 | F.10.1.7 |
341+
| tan | |check| | |check| | | | | 7.12.4.7 | F.10.1.7 |
342342
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
343343
| tanh | |check| | | | | | 7.12.5.6 | F.10.2.6 |
344344
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+

libc/src/__support/FPUtil/double_double.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,42 @@ LIBC_INLINE DoubleDouble multiply_add<DoubleDouble>(const DoubleDouble &a,
129129
return add(c, quick_mult(a, b));
130130
}
131131

132+
// Accurate double-double division, following Karp-Markstein's trick for
133+
// division, implemented in the CORE-MATH project at:
134+
// https://gitlab.inria.fr/core-math/core-math/-/blob/master/src/binary64/tan/tan.c#L1855
135+
//
136+
// Error bounds:
137+
// Let a = ah + al, b = bh + bl.
138+
// Let r = rh + rl be the approximation of (ah + al) / (bh + bl).
139+
// Then:
140+
// (ah + al) / (bh + bl) - rh =
141+
// = ((ah - bh * rh) + (al - bl * rh)) / (bh + bl)
142+
// = (1 + O(bl/bh)) * ((ah - bh * rh) + (al - bl * rh)) / bh
143+
// Let q = round(1/bh), then the above expressions are approximately:
144+
// = (1 + O(bl / bh)) * (1 + O(2^-52)) * q * ((ah - bh * rh) + (al - bl * rh))
145+
// So we can compute:
146+
// rl = q * (ah - bh * rh) + q * (al - bl * rh)
147+
// as accurate as possible, then the error is bounded by:
148+
// |(ah + al) / (bh + bl) - (rh + rl)| < O(bl/bh) * (2^-52 + al/ah + bl/bh)
149+
LIBC_INLINE DoubleDouble div(const DoubleDouble &a, const DoubleDouble &b) {
150+
DoubleDouble r;
151+
double q = 1.0 / b.hi;
152+
r.hi = a.hi * q;
153+
154+
#ifdef LIBC_TARGET_CPU_HAS_FMA
155+
double e_hi = fputil::multiply_add(b.hi, -r.hi, a.hi);
156+
double e_lo = fputil::multiply_add(b.lo, -r.hi, a.lo);
157+
#else
158+
DoubleDouble b_hi_r_hi = fputil::exact_mult</*NO_FMA=*/true>(b.hi, -r.hi);
159+
DoubleDouble b_lo_r_hi = fputil::exact_mult</*NO_FMA=*/true>(b.lo, -r.hi);
160+
double e_hi = (a.hi + b_hi_r_hi.hi) + b_hi_r_hi.lo;
161+
double e_lo = (a.lo + b_lo_r_hi.hi) + b_lo_r_hi.lo;
162+
#endif // LIBC_TARGET_CPU_HAS_FMA
163+
164+
r.lo = q * (e_hi + e_lo);
165+
return r;
166+
}
167+
132168
} // namespace LIBC_NAMESPACE::fputil
133169

134170
#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_DOUBLE_DOUBLE_H

libc/src/math/generic/CMakeLists.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,27 @@ add_entrypoint_object(
323323
-O3
324324
)
325325

326+
add_entrypoint_object(
327+
tan
328+
SRCS
329+
tan.cpp
330+
HDRS
331+
../tan.h
332+
DEPENDS
333+
.range_reduction_double
334+
libc.hdr.errno_macros
335+
libc.src.errno.errno
336+
libc.src.__support.FPUtil.double_double
337+
libc.src.__support.FPUtil.dyadic_float
338+
libc.src.__support.FPUtil.except_value_utils
339+
libc.src.__support.FPUtil.fenv_impl
340+
libc.src.__support.FPUtil.fp_bits
341+
libc.src.__support.FPUtil.multiply_add
342+
libc.src.__support.macros.optimization
343+
COMPILE_OPTIONS
344+
-O3
345+
)
346+
326347
add_entrypoint_object(
327348
tanf
328349
SRCS

0 commit comments

Comments
 (0)