1 /* Double-precision vector (SVE) log10 function
3 Copyright (C) 2023-2024 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <https://www.gnu.org/licenses/>. */
21 #include "poly_sve_f64.h"
23 #define Min 0x0010000000000000
24 #define Max 0x7ff0000000000000
25 #define Thres 0x7fe0000000000000 /* Max - Min. */
26 #define Off 0x3fe6900900000000
27 #define N (1 << V_LOG10_TABLE_BITS)
29 static svfloat64_t NOINLINE
30 special_case (svfloat64_t x
, svfloat64_t y
, svbool_t special
)
32 return sv_call_f64 (log10
, x
, y
, special
);
35 /* SVE log10 algorithm.
36 Maximum measured error is 2.46 ulps.
37 SV_NAME_D1 (log10)(0x1.131956cd4b627p+0) got 0x1.fffbdf6eaa669p-6
38 want 0x1.fffbdf6eaa667p-6. */
39 svfloat64_t
SV_NAME_D1 (log10
) (svfloat64_t x
, const svbool_t pg
)
41 svuint64_t ix
= svreinterpret_u64 (x
);
42 svbool_t special
= svcmpge (pg
, svsub_x (pg
, ix
, Min
), Thres
);
44 /* x = 2^k z; where z is in range [Off,2*Off) and exact.
45 The range is split into N subintervals.
46 The ith subinterval contains z and c is near its center. */
47 svuint64_t tmp
= svsub_x (pg
, ix
, Off
);
48 svuint64_t i
= svlsr_x (pg
, tmp
, 51 - V_LOG10_TABLE_BITS
);
49 i
= svand_x (pg
, i
, (N
- 1) << 1);
50 svfloat64_t k
= svcvt_f64_x (pg
, svasr_x (pg
, svreinterpret_s64 (tmp
), 52));
51 svfloat64_t z
= svreinterpret_f64 (
52 svsub_x (pg
, ix
, svand_x (pg
, tmp
, 0xfffULL
<< 52)));
54 /* log(x) = k*log(2) + log(c) + log(z/c). */
55 svfloat64_t invc
= svld1_gather_index (pg
, &__v_log10_data
.table
[0].invc
, i
);
57 = svld1_gather_index (pg
, &__v_log10_data
.table
[0].log10c
, i
);
59 /* We approximate log(z/c) with a polynomial P(x) ~= log(x + 1):
60 r = z/c - 1 (we look up precomputed 1/c)
62 svfloat64_t r
= svmad_x (pg
, invc
, z
, -1.0);
64 /* hi = log(c) + k*log(2). */
65 svfloat64_t w
= svmla_x (pg
, logc
, r
, __v_log10_data
.invln10
);
66 svfloat64_t hi
= svmla_x (pg
, w
, k
, __v_log10_data
.log10_2
);
68 /* y = r2*(A0 + r*A1 + r2*(A2 + r*A3 + r2*A4)) + hi. */
69 svfloat64_t r2
= svmul_x (pg
, r
, r
);
70 svfloat64_t y
= sv_pw_horner_4_f64_x (pg
, r
, r2
, __v_log10_data
.poly
);
72 if (__glibc_unlikely (svptest_any (pg
, special
)))
73 return special_case (x
, svmla_x (svnot_z (pg
, special
), hi
, r2
, y
),
75 return svmla_x (pg
, hi
, r2
, y
);