1177668d1SDavid Schultz /*
2177668d1SDavid Schultz * ====================================================
3177668d1SDavid Schultz * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
4177668d1SDavid Schultz *
5177668d1SDavid Schultz * Developed at SunPro, a Sun Microsystems, Inc. business.
6177668d1SDavid Schultz * Permission to use, copy, modify, and distribute this
7177668d1SDavid Schultz * software is freely granted, provided that this notice
8177668d1SDavid Schultz * is preserved.
9177668d1SDavid Schultz * ====================================================
10177668d1SDavid Schultz */
11177668d1SDavid Schultz
1263687c8bSDavid Schultz /*
135ebf26f6SDavid Schultz * Float version of e_log2.c. See the latter for most comments.
1463687c8bSDavid Schultz */
1563687c8bSDavid Schultz
16177668d1SDavid Schultz #include "math.h"
17177668d1SDavid Schultz #include "math_private.h"
18177668d1SDavid Schultz #include "k_logf.h"
19177668d1SDavid Schultz
20177668d1SDavid Schultz static const float
21177668d1SDavid Schultz two25 = 3.3554432000e+07, /* 0x4c000000 */
2263687c8bSDavid Schultz ivln2hi = 1.4428710938e+00, /* 0x3fb8b000 */
2363687c8bSDavid Schultz ivln2lo = -1.7605285393e-04; /* 0xb9389ad4 */
24177668d1SDavid Schultz
25177668d1SDavid Schultz static const float zero = 0.0;
267dbbb6ddSDavid Schultz static volatile float vzero = 0.0;
27177668d1SDavid Schultz
28177668d1SDavid Schultz float
log2f(float x)29*99843eb8SSteve Kargl log2f(float x)
30177668d1SDavid Schultz {
31b052ec90SDavid Schultz float f,hfsq,hi,lo,r,y;
32177668d1SDavid Schultz int32_t i,k,hx;
33177668d1SDavid Schultz
34177668d1SDavid Schultz GET_FLOAT_WORD(hx,x);
35177668d1SDavid Schultz
36177668d1SDavid Schultz k=0;
37177668d1SDavid Schultz if (hx < 0x00800000) { /* x < 2**-126 */
38177668d1SDavid Schultz if ((hx&0x7fffffff)==0)
397dbbb6ddSDavid Schultz return -two25/vzero; /* log(+-0)=-inf */
40177668d1SDavid Schultz if (hx<0) return (x-x)/zero; /* log(-#) = NaN */
41177668d1SDavid Schultz k -= 25; x *= two25; /* subnormal number, scale up x */
42177668d1SDavid Schultz GET_FLOAT_WORD(hx,x);
43177668d1SDavid Schultz }
44177668d1SDavid Schultz if (hx >= 0x7f800000) return x+x;
45b052ec90SDavid Schultz if (hx == 0x3f800000)
46b052ec90SDavid Schultz return zero; /* log(1) = +0 */
47177668d1SDavid Schultz k += (hx>>23)-127;
48177668d1SDavid Schultz hx &= 0x007fffff;
49177668d1SDavid Schultz i = (hx+(0x4afb0d))&0x800000;
50177668d1SDavid Schultz SET_FLOAT_WORD(x,hx|(i^0x3f800000)); /* normalize x or x/2 */
51177668d1SDavid Schultz k += (i>>23);
52b052ec90SDavid Schultz y = (float)k;
53b052ec90SDavid Schultz f = x - (float)1.0;
54b052ec90SDavid Schultz hfsq = (float)0.5*f*f;
55b052ec90SDavid Schultz r = k_log1pf(f);
56b052ec90SDavid Schultz
57b052ec90SDavid Schultz /*
58b052ec90SDavid Schultz * We no longer need to avoid falling into the multi-precision
59b052ec90SDavid Schultz * calculations due to compiler bugs breaking Dekker's theorem.
60b052ec90SDavid Schultz * Keep avoiding this as an optimization. See e_log2.c for more
61b052ec90SDavid Schultz * details (some details are here only because the optimization
62b052ec90SDavid Schultz * is not yet available in double precision).
63b052ec90SDavid Schultz *
64b052ec90SDavid Schultz * Another compiler bug turned up. With gcc on i386,
65b052ec90SDavid Schultz * (ivln2lo + ivln2hi) would be evaluated in float precision
66b052ec90SDavid Schultz * despite runtime evaluations using double precision. So we
67b052ec90SDavid Schultz * must cast one of its terms to float_t. This makes the whole
68b052ec90SDavid Schultz * expression have type float_t, so return is forced to waste
69b052ec90SDavid Schultz * time clobbering its extra precision.
70b052ec90SDavid Schultz */
71b052ec90SDavid Schultz if (sizeof(float_t) > sizeof(float))
72b052ec90SDavid Schultz return (r - hfsq + f) * ((float_t)ivln2lo + ivln2hi) + y;
73b052ec90SDavid Schultz
74b052ec90SDavid Schultz hi = f - hfsq;
75b052ec90SDavid Schultz GET_FLOAT_WORD(hx,hi);
76177668d1SDavid Schultz SET_FLOAT_WORD(hi,hx&0xfffff000);
77b052ec90SDavid Schultz lo = (f - hi) - hfsq + r;
78b052ec90SDavid Schultz return (lo+hi)*ivln2lo + lo*ivln2hi + hi*ivln2hi + y;
79177668d1SDavid Schultz }
80