blob: b7ecd4a7a2d9e7418e1568633a112a88b2ee14f5 [file] [log] [blame]
/*
* Copyright (c) 2014 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "math32.h"
/*
* ====================================================
* 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.
* ====================================================
*/
#define pi 3.1415927410e+00f /* 0x40490fdb */
#define a0 7.7215664089e-02f /* 0x3d9e233f */
#define a1 3.2246702909e-01f /* 0x3ea51a66 */
#define a2 6.7352302372e-02f /* 0x3d89f001 */
#define a3 2.0580807701e-02f /* 0x3ca89915 */
#define a4 7.3855509982e-03f /* 0x3bf2027e */
#define a5 2.8905137442e-03f /* 0x3b3d6ec6 */
#define a6 1.1927076848e-03f /* 0x3a9c54a1 */
#define a7 5.1006977446e-04f /* 0x3a05b634 */
#define a8 2.2086278477e-04f /* 0x39679767 */
#define a9 1.0801156895e-04f /* 0x38e28445 */
#define a10 2.5214456400e-05f /* 0x37d383a2 */
#define a11 4.4864096708e-05f /* 0x383c2c75 */
#define tc 1.4616321325e+00f /* 0x3fbb16c3 */
#define tf -1.2148628384e-01f /* 0xbdf8cdcd */
/* tt -(tail of tf) */
#define tt 6.6971006518e-09f /* 0x31e61c52 */
#define t0 4.8383611441e-01f /* 0x3ef7b95e */
#define t1 -1.4758771658e-01f /* 0xbe17213c */
#define t2 6.4624942839e-02f /* 0x3d845a15 */
#define t3 -3.2788541168e-02f /* 0xbd064d47 */
#define t4 1.7970675603e-02f /* 0x3c93373d */
#define t5 -1.0314224288e-02f /* 0xbc28fcfe */
#define t6 6.1005386524e-03f /* 0x3bc7e707 */
#define t7 -3.6845202558e-03f /* 0xbb7177fe */
#define t8 2.2596477065e-03f /* 0x3b141699 */
#define t9 -1.4034647029e-03f /* 0xbab7f476 */
#define t10 8.8108185446e-04f /* 0x3a66f867 */
#define t11 -5.3859531181e-04f /* 0xba0d3085 */
#define t12 3.1563205994e-04f /* 0x39a57b6b */
#define t13 -3.1275415677e-04f /* 0xb9a3f927 */
#define t14 3.3552918467e-04f /* 0x39afe9f7 */
#define u0 -7.7215664089e-02f /* 0xbd9e233f */
#define u1 6.3282704353e-01f /* 0x3f2200f4 */
#define u2 1.4549225569e+00f /* 0x3fba3ae7 */
#define u3 9.7771751881e-01f /* 0x3f7a4bb2 */
#define u4 2.2896373272e-01f /* 0x3e6a7578 */
#define u5 1.3381091878e-02f /* 0x3c5b3c5e */
#define v1 2.4559779167e+00f /* 0x401d2ebe */
#define v2 2.1284897327e+00f /* 0x4008392d */
#define v3 7.6928514242e-01f /* 0x3f44efdf */
#define v4 1.0422264785e-01f /* 0x3dd572af */
#define v5 3.2170924824e-03f /* 0x3b52d5db */
#define s0 -7.7215664089e-02f /* 0xbd9e233f */
#define s1 2.1498242021e-01f /* 0x3e5c245a */
#define s2 3.2577878237e-01f /* 0x3ea6cc7a */
#define s3 1.4635047317e-01f /* 0x3e15dce6 */
#define s4 2.6642270386e-02f /* 0x3cda40e4 */
#define s5 1.8402845599e-03f /* 0x3af135b4 */
#define s6 3.1947532989e-05f /* 0x3805ff67 */
#define r1 1.3920053244e+00f /* 0x3fb22d3b */
#define r2 7.2193557024e-01f /* 0x3f38d0c5 */
#define r3 1.7193385959e-01f /* 0x3e300f6e */
#define r4 1.8645919859e-02f /* 0x3c98bf54 */
#define r5 7.7794247773e-04f /* 0x3a4beed6 */
#define r6 7.3266842264e-06f /* 0x36f5d7bd */
#define w0 4.1893854737e-01f /* 0x3ed67f1d */
#define w1 8.3333335817e-02f /* 0x3daaaaab */
#define w2 -2.7777778450e-03f /* 0xbb360b61 */
#define w3 7.9365057172e-04f /* 0x3a500cfd */
#define w4 -5.9518753551e-04f /* 0xba1c065c */
#define w5 8.3633989561e-04f /* 0x3a5b3dd2 */
#define w6 -1.6309292987e-03f /* 0xbad5c4e8 */
__attribute__ ((overloadable, always_inline)) float
lgamma_r(float x, int *signp)
{
int hx = as_int(x);
int ix = hx & 0x7fffffff;
float absx = as_float(ix);
if (ix >= 0x7f800000) {
*signp = 1;
return x;
}
if (absx < 0x1.0p-70f) {
*signp = hx < 0 ? -1 : 1;
return -log(absx);
}
float r;
if (absx == 1.0f | absx == 2.0f)
r = 0.0f;
else if (absx < 2.0f) {
float y = 2.0f - absx;
int i = 0;
int c = absx < 0x1.bb4c30p+0f;
float yt = absx - tc;
y = c ? yt : y;
i = c ? 1 : i;
c = absx < 0x1.3b4c40p+0f;
yt = absx - 1.0f;
y = c ? yt : y;
i = c ? 2 : i;
r = -log(absx);
yt = 1.0f - absx;
c = absx <= 0x1.ccccccp-1f;
r = c ? r : 0.0f;
y = c ? yt : y;
i = c ? 0 : i;
c = absx < 0x1.769440p-1f;
yt = absx - (tc - 1.0f);
y = c ? yt : y;
i = c ? 1 : i;
c = absx < 0x1.da6610p-3f;
y = c ? absx : y;
i = c ? 2 : i;
float z, w, p1, p2, p3, p;
switch (i) {
case 0:
z = y * y;
p1 = mad(z, mad(z, mad(z, mad(z, mad(z, a10, a8), a6), a4), a2), a0);
p2 = z * mad(z, mad(z, mad(z, mad(z, mad(z, a11, a9), a7), a5), a3), a1);
p = mad(y, p1, p2);
r += mad(y, -0.5f, p);
break;
case 1:
z = y * y;
w = z * y;
p1 = mad(w, mad(w, mad(w, mad(w, t12, t9), t6), t3), t0);
p2 = mad(w, mad(w, mad(w, mad(w, t13, t10), t7), t4), t1);
p3 = mad(w, mad(w, mad(w, mad(w, t14, t11), t8), t5), t2);
p = mad(z, p1, -mad(w, -mad(y, p3, p2), tt));
r += tf + p;
break;
case 2:
p1 = y * mad(y, mad(y, mad(y, mad(y, mad(y, u5, u4), u3), u2), u1), u0);
p2 = mad(y, mad(y, mad(y, mad(y, mad(y, v5, v4), v3), v2), v1), 1.0f);
r += mad(y, -0.5f, MATH_DIVIDE(p1, p2));
break;
}
} else if (absx < 8.0f) {
int i = (int)absx;
float y = absx - (float) i;
float p = y * mad(y, mad(y, mad(y, mad(y, mad(y, mad(y, s6, s5), s4), s3), s2), s1), s0);
float q = mad(y, mad(y, mad(y, mad(y, mad(y, mad(y, r6, r5), r4), r3), r2), r1), 1.0f);
r = mad(y, 0.5f, MATH_DIVIDE(p, q));
float y6 = y + 6.0f;
float y5 = y + 5.0f;
float y4 = y + 4.0f;
float y3 = y + 3.0f;
float y2 = y + 2.0f;
float z = 1.0f;
z *= i > 6 ? y6 : 1.0f;
z *= i > 5 ? y5 : 1.0f;
z *= i > 4 ? y4 : 1.0f;
z *= i > 3 ? y3 : 1.0f;
z *= i > 2 ? y2 : 1.0f;
r += log(z);
} else if (absx < 0x1.0p+58f) {
float z = 1.0f / absx;
float y = z * z;
float w = mad(z, mad(y, mad(y, mad(y, mad(y, mad(y, w6, w5), w4), w3), w2), w1), w0);
r = mad(absx - 0.5f, log(absx) - 1.0f, w);
} else
// 2**58 <= x <= Inf
r = absx * (log(absx) - 1.0f);
int s = 1;
if (x < 0.0f) {
float t = sinpi(x);
r = log(pi / fabs(t * x)) - r;
r = t == 0.0f ? as_float(PINFBITPATT_SP32) : r;
s = t < 0.0f ? -1 : s;
}
*signp = s;
return r;
}
#if __OPENCL_C_VERSION__ < 200
__attribute__ ((overloadable, always_inline)) float
lgamma_r(float x, __local int *signp)
{
int s;
float l = lgamma_r(x, &s);
*signp = s;
return l;
}
__attribute__ ((overloadable, always_inline)) float
lgamma_r(float x, __global int *signp)
{
int s;
float l = lgamma_r(x, &s);
*signp = s;
return l;
}
#endif
__attribute__ ((overloadable, always_inline)) float
lgamma(float x)
{
int s;
float l = lgamma_r(x, &s);
return l;
}