Files
TheRock/compiler/amd-llvm/libclc/clc/lib/generic/math/clc_erfc.inc
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

222 lines
8.6 KiB
C++

//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// Some of this implementation is based on ideas from Sun libm.
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/*
* x
* 2 |\
* erf(x) = --------- | exp(-t*t)dt
* sqrt(pi) \|
* 0
*
* erfc(x) = 1-erf(x)
* Note that
* erf(-x) = -erf(x)
* erfc(-x) = 2 - erfc(x)
*
* Method:
* 1. For |x| in [0, 0.84375]
* erf(x) = x + x*R(x^2)
* erfc(x) = 1 - erf(x) if x in [-.84375,0.25]
* = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375]
* where R = P/Q where P is an odd poly of degree 8 and
* Q is an odd poly of degree 10.
* -57.90
* | R - (erf(x)-x)/x | <= 2
*
*
* Remark. The formula is derived by noting
* erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
* and that
* 2/sqrt(pi) = 1.128379167095512573896158903121545171688
* is close to one. The interval is chosen because the fix
* point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
* near 0.6174), and by some experiment, 0.84375 is chosen to
* guarantee the error is less than one ulp for erf.
*
* 2. For |x| in [0.84375,1.25], let s = |x| - 1, and
* c = 0.84506291151 rounded to single (24 bits)
* erf(x) = sign(x) * (c + P1(s)/Q1(s))
* erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0
* 1+(c+P1(s)/Q1(s)) if x < 0
* |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
* Remark: here we use the taylor series expansion at x=1.
* erf(1+s) = erf(1) + s*Poly(s)
* = 0.845.. + P1(s)/Q1(s)
* That is, we use rational approximation to approximate
* erf(1+s) - (c = (single)0.84506291151)
* Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
* where
* P1(s) = degree 6 poly in s
* Q1(s) = degree 6 poly in s
*
* 3. For x in [1.25,1/0.35(~2.857143)],
* erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
* erf(x) = 1 - erfc(x)
* where
* R1(z) = degree 7 poly in z, (z=1/x^2)
* S1(z) = degree 8 poly in z
*
* 4. For x in [1/0.35,28]
* erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
* = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
* = 2.0 - tiny (if x <= -6)
* erf(x) = sign(x)*(1.0 - erfc(x)) if x < 6, else
* erf(x) = sign(x)*(1.0 - tiny)
* where
* R2(z) = degree 6 poly in z, (z=1/x^2)
* S2(z) = degree 7 poly in z
*
* Note1:
* To compute exp(-x*x-0.5625+R/S), let s be a single
* precision number and s := x; then
* -x*x = -s*s + (s-x)*(s+x)
* exp(-x*x-0.5626+R/S) =
* exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
* Note2:
* Here 4 and 5 make use of the asymptotic series
* exp(-x*x)
* erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
* x*sqrt(pi)
* We use rational approximation to approximate
* g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
* Here is the error bound for R1/S1 and R2/S2
* |R1/S1 - f(x)| < 2**(-62.57)
* |R2/S2 - f(x)| < 2**(-61.52)
*
* 5. For inf > x >= 28
* erf(x) = sign(x) *(1 - tiny) (raise inexact)
* erfc(x) = tiny*tiny (raise underflow) if x > 0
* = 2 - tiny if x<0
*
* 7. Special case:
* erf(0) = 0, erf(inf) = 1, erf(-inf) = -1,
* erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
* erfc/erf(NaN) is NaN
*/
#pragma OPENCL FP_CONTRACT OFF
#if __CLC_FPSIZE == 32
// Computes exp(x**2) * erfc(x)
static _CLC_DEF _CLC_OVERLOAD _CLC_CONST __CLC_FLOATN
__clc_erfc_scaled(__CLC_FLOATN x) {
__CLC_FLOATN n = x - 2.0f;
__CLC_FLOATN d = x + 2.0f;
__CLC_FLOATN r = __clc_recip_fast(d);
__CLC_FLOATN q = n * r;
__CLC_FLOATN e = __clc_fma(-q, x, __clc_fma(q + 1.0f, -2.0f, x));
q = __clc_fma(r, e, q);
// Polynomial in q
__CLC_FLOATN u0 = __clc_mad(q, -0x1.adf188p-12f, -0x1.45aea6p-10f);
__CLC_FLOATN u1 = __clc_mad(q, u0, 0x1.5a5f68p-10f);
__CLC_FLOATN u2 = __clc_mad(q, u1, 0x1.1b44cep-7f);
__CLC_FLOATN u3 = __clc_mad(q, u2, -0x1.082b62p-7f);
__CLC_FLOATN u4 = __clc_mad(q, u3, -0x1.bc143p-5f);
__CLC_FLOATN u5 = __clc_mad(q, u4, 0x1.4ffc54p-3f);
__CLC_FLOATN u6 = __clc_mad(q, u5, -0x1.5407fap-3f);
__CLC_FLOATN u7 = __clc_mad(q, u6, -0x1.7bf616p-4f);
__CLC_FLOATN p = __clc_mad(q, u7, 0x1.1ba038p-2f);
// Final evaluation
__CLC_FLOATN tx = x + x;
d = 1.0f + tx;
r = __clc_recip_fast(d);
q = __clc_fma(p, r, r);
e = __clc_fma(-q, tx, 1.0f) + (p - q);
return __clc_fma(r, e, q);
}
_CLC_DEF _CLC_OVERLOAD _CLC_CONST __CLC_FLOATN __clc_erfc(__CLC_FLOATN x) {
__CLC_FLOATN ax = __clc_fabs(x);
__CLC_FLOATN x2h = -x * x;
__CLC_FLOATN x2l = __clc_fma(-x, x, -x2h);
__CLC_FLOATN e = __clc_exp(x2h);
e = __clc_fma(e, x2l, e);
__CLC_FLOATN ret = e * __clc_erfc_scaled(ax);
ret = ax > 0x1.41bbf8p+3f ? 0.0f : ret;
__CLC_FLOATN nret = 2.0f - ret;
return x < 0.0f ? nret : ret;
}
#elif __CLC_FPSIZE == 64
// Computes exp(x**2) * erfc(x)
static _CLC_OVERLOAD _CLC_CONST __CLC_DOUBLEN
__clc_erfc_scaled(__CLC_DOUBLEN x) {
__CLC_DOUBLEN n = x - 4.0;
__CLC_DOUBLEN d = x + 4.0;
__CLC_DOUBLEN r = __clc_recip_fast(d);
__CLC_DOUBLEN q = n * r;
__CLC_DOUBLEN e = __clc_mad(-q, x, __clc_mad(q + 1.0, -4.0, x));
q = __clc_fma(r, e, q);
__CLC_DOUBLEN u0 =
__clc_mad(q, -0x1.1f39d54df3c0ep-27, -0x1.1166337cfa789p-27);
__CLC_DOUBLEN u1 = __clc_mad(q, u0, 0x1.b45f1d9802b82p-24);
__CLC_DOUBLEN u2 = __clc_mad(q, u1, 0x1.d90488a03dcdbp-25);
__CLC_DOUBLEN u3 = __clc_mad(q, u2, -0x1.b87b02eba62d8p-21);
__CLC_DOUBLEN u4 = __clc_mad(q, u3, 0x1.5104ba56e15f1p-22);
__CLC_DOUBLEN u5 = __clc_mad(q, u4, 0x1.7f29f71c907dep-18);
__CLC_DOUBLEN u6 = __clc_mad(q, u5, -0x1.78f5c2cd770fbp-17);
__CLC_DOUBLEN u7 = __clc_mad(q, u6, -0x1.995fb76d0a51ap-16);
__CLC_DOUBLEN u8 = __clc_mad(q, u7, 0x1.3be2ec022d0edp-13);
__CLC_DOUBLEN u9 = __clc_mad(q, u8, -0x1.a1deb2fdbf62ep-13);
__CLC_DOUBLEN u10 = __clc_mad(q, u9, -0x1.8d4ac3689fc43p-11);
__CLC_DOUBLEN u11 = __clc_mad(q, u10, 0x1.49c67192d909bp-8);
__CLC_DOUBLEN u12 = __clc_mad(q, u11, -0x1.09623852ff07p-6);
__CLC_DOUBLEN u13 = __clc_mad(q, u12, 0x1.3079edfadea8fp-5);
__CLC_DOUBLEN u14 = __clc_mad(q, u13, -0x1.0fb06dff6591p-4);
__CLC_DOUBLEN u15 = __clc_mad(q, u14, 0x1.7fee004de8f32p-4);
__CLC_DOUBLEN u16 = __clc_mad(q, u15, -0x1.9ddb23c3dbeb3p-4);
__CLC_DOUBLEN u17 = __clc_mad(q, u16, 0x1.16ecefcfa693p-4);
__CLC_DOUBLEN u18 = __clc_mad(q, u17, 0x1.f7f5df66fb8a3p-7);
__CLC_DOUBLEN u19 = __clc_mad(q, u18, -0x1.1df1ad154a2a8p-3);
__CLC_DOUBLEN p = __clc_mad(q, u19, 0x1.dd2c8b74febf8p-3);
__CLC_DOUBLEN tx = x + x;
d = 1.0 + tx;
r = __clc_recip_fast(d);
q = __clc_mad(p, r, r);
e = __clc_mad(-q, tx, 1.0) + (p - q);
return __clc_mad(r, e, q);
}
_CLC_DEF _CLC_OVERLOAD _CLC_CONST __CLC_DOUBLEN __clc_erfc(__CLC_DOUBLEN x) {
__CLC_DOUBLEN ax = __clc_fabs(x);
__CLC_DOUBLEN x2h = -x * x;
__CLC_DOUBLEN x2l = __clc_mad(-x, x, -x2h);
__CLC_DOUBLEN e = __clc_exp(x2h);
e = __clc_mad(e, x2l, e);
__CLC_DOUBLEN ret = e * __clc_erfc_scaled(ax);
ret = ax > 0x1.b39dc41e48bfcp+4 ? 0.0f : ret;
__CLC_DOUBLEN nret = 2.0 - ret;
return x < 0.0 ? nret : ret;
}
#elif __CLC_FPSIZE == 16
_CLC_OVERLOAD _CLC_CONST _CLC_DEF __CLC_HALFN __clc_erfc(__CLC_HALFN x) {
return __CLC_CONVERT_HALFN(__clc_erfc(__CLC_CONVERT_FLOATN(x)));
}
#endif