//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /* Refer to the exp routine for the underlying algorithm */ #if __CLC_FPSIZE == 32 _CLC_OVERLOAD _CLC_CONST _CLC_DEF __CLC_FLOATN __clc_expm1(__CLC_FLOATN x) { const __CLC_FLOATN x_max = 0x1.62e42ep+6f; // 64 * ln(2) const __CLC_FLOATN ln2_tail = -0x1.05c610p-29f; // small correction term for ln(2) const __CLC_FLOATN c1 = 0x1.a26762p-13f; // ~1.250000e-4 const __CLC_FLOATN c2 = 0x1.6d2e00p-10f; // ~ 9.999999e-4 const __CLC_FLOATN c3 = 0x1.110ff2p-7f; // ~8.333333e-3 const __CLC_FLOATN c4 = 0x1.555502p-5f; // ~4.166667e-2 const __CLC_FLOATN c5 = 0x1.555556p-3f; // ~1.666667e-1 __CLC_FLOATN fn = __clc_rint(x * (__CLC_FLOATN)M_LOG2E); __CLC_FLOATN t = __clc_fma(-fn, ln2_tail, __clc_fma(-fn, (__CLC_FLOATN)M_LN2, x)); __CLC_FLOATN q0 = __clc_mad(t, c1, c2); __CLC_FLOATN q1 = __clc_mad(t, q0, c3); __CLC_FLOATN q2 = __clc_mad(t, q1, c4); __CLC_FLOATN q3 = __clc_mad(t, q2, c5); __CLC_FLOATN p = __clc_fma(t, t * __clc_mad(t, q3, 0.5f), t); __CLC_INTN e = fn == 128.0f ? 127 : __CLC_CONVERT_INTN(fn); __CLC_FLOATN s = __clc_ldexp(__CLC_FP_LIT(1.0), e); __CLC_FLOATN z = __clc_fma(s, p, s - 1.0f); z = fn == 128.0f ? 2.0f * z : z; z = x > x_max ? __CLC_GENTYPE_INF : z; z = x < -17.0f ? -1.0f : z; return z; } #elif __CLC_FPSIZE == 64 _CLC_OVERLOAD _CLC_CONST _CLC_DEF __CLC_DOUBLEN __clc_expm1(__CLC_DOUBLEN x) { const __CLC_DOUBLEN max_expm1_arg = 0x1.62e42fefa39efp+9; const __CLC_DOUBLEN min_expm1_arg = -37.0; const __CLC_DOUBLEN lnof2_by_64_tail = 0x1.abc9e3b39803fp-56; __CLC_DOUBLEN dn = __clc_rint(x * M_LOG2E); // Reduced argument t = x - dn * (ln2/64), split into head and tail for // precision __CLC_DOUBLEN t = __clc_mad(-dn, lnof2_by_64_tail, __clc_mad(-dn, M_LN2, x)); const __CLC_DOUBLEN c0 = 0x1.1f32ea9d67f34p-29; const __CLC_DOUBLEN c1 = 0x1.af4eb2a1b768bp-26; const __CLC_DOUBLEN c2 = 0x1.27e500e0ac05bp-22; const __CLC_DOUBLEN c3 = 0x1.71de01b889c29p-19; const __CLC_DOUBLEN c4 = 0x1.a01a0197bcfd8p-16; const __CLC_DOUBLEN c5 = 0x1.a01a01ac1a723p-13; const __CLC_DOUBLEN c6 = 0x1.6c16c16c18931p-10; const __CLC_DOUBLEN c7 = 0x1.1111111110056p-7; const __CLC_DOUBLEN c8 = 0x1.5555555555552p-5; const __CLC_DOUBLEN c9 = 0x1.5555555555557p-3; const __CLC_DOUBLEN c10 = 0x1.0000000000000p-1; __CLC_DOUBLEN q0 = __clc_mad(t, c0, c1); __CLC_DOUBLEN q1 = __clc_mad(t, q0, c2); __CLC_DOUBLEN q2 = __clc_mad(t, q1, c3); __CLC_DOUBLEN q3 = __clc_mad(t, q2, c4); __CLC_DOUBLEN q4 = __clc_mad(t, q3, c5); __CLC_DOUBLEN q5 = __clc_mad(t, q4, c6); __CLC_DOUBLEN q6 = __clc_mad(t, q5, c7); __CLC_DOUBLEN q7 = __clc_mad(t, q6, c8); __CLC_DOUBLEN q8 = __clc_mad(t, q7, c9); __CLC_DOUBLEN p = __clc_mad(t, t * __clc_mad(t, q8, c10), t); __CLC_INTN e = __CLC_CONVERT_INTN(dn == 1024.0) ? 1023 : __CLC_CONVERT_INTN(dn); // s = 2^e __CLC_DOUBLEN s = __clc_ldexp(__CLC_FP_LIT(1.0), e); // expm1(x) ~= s * p + (s - 1) __CLC_DOUBLEN z = __clc_mad(s, p, s - 1.0); z = dn == 1024.0 ? 2.0 * z : z; z = x > max_expm1_arg ? __CLC_GENTYPE_INF : z; z = x < min_expm1_arg ? -1.0 : z; return z; } #elif __CLC_FPSIZE == 16 _CLC_OVERLOAD _CLC_DEF __CLC_HALFN __clc_expm1(__CLC_HALFN x) { __CLC_FLOATN x_float = __CLC_CONVERT_FLOATN(x); __CLC_FLOATN float_expm1 = __clc_exp2_fast(x_float * (__CLC_FLOATN)M_LOG2E) - 1.0f; __CLC_HALFN p = __clc_fma(x, x * __clc_fma(x, 0x1.555556p-3h, 0.5h), x); return __clc_fabs(x) < 0x1.0p-6h ? p : __CLC_CONVERT_HALFN(float_expm1); } #endif