-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlog.c
120 lines (100 loc) · 2.52 KB
/
log.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/*
* Function to compute the logarithm with fully exact rounding
*
* Author : Defour David (David.Defour@ens-lyon.fr)
*
* Date of creation : 13/05/2002
* Last Modified : 17/05/2002
*/
#include <stdio.h>
#include "logsix.h"
/*
* 1) First reduction: exponent extraction
* E
* x = 2^ .(1+f) with 0 <= f < 1
*
* log(x) = E.log(2) + log(1+f) where:
* - log(2) is tabulated
* - log(1+f) need to be evaluated
*
*
* 2) Avoiding accuracy problem when E=-1 by testing
*
* if (1+f >= sqrt(2)) then
* 1+f = (1+f)/2; E = E+1;
* and,
* log(x) = (E+1).log(2) + log((1+f)/2)
*
* so now: sqrt(2)/2 <= (1+f) < sqrt(2)
*
*
* 3) Second reduction: tabular reduction
* -4
* wi = 1 + i. 2^
* 1
* log(1+f) = log(wi) + log ( 1 + --- . (1 + f - wi) )
* wi
*
* then |(1+f-wi)/wi| <= 2^-5 if we use rounded to nearest.
*
* 4) Computation:
* a) Table lookup of:
* - ti = log(wi)
* - inv_wi = 1/(wi)
* b) Polynomial evaluation of:
* - P(R) ~ log(1 + R), where R = (1+f-wi) * inv_wi
*
* -5
* with |R| < 2^
*
*
* 5) Reconstruction:
* log(x) = E.log(2) + t_i + P(R)
*
*/
void scs_log(scs_ptr res, db_number y, int E){
scs_t R, sc_ln2_times_E, res1, addi;
scs_ptr ti, inv_wi;
db_number z, wi;
int i;
#if EVAL_PERF
crlibm_second_step_taken++;
#endif
/* to normalize y.d and round to nearest */
/* + (1-trunc(sqrt(2.)/2 * 2^(4))*2^(-4) )+2.^(-(4+1))*/
z.d = y.d + norm_number.d;
i = (z.i[HI_ENDIAN] & 0x000fffff);
i = i >> 16; /* 0<= i <=11 */
wi.d = ((double)(11+i))*0.0625;
/* (1+f-w_i) */
y.d -= wi.d;
/* Table reduction */
ti = table_ti_ptr[i];
inv_wi = table_inv_wi_ptr[i];
/* R = (1+f-w_i)/w_i */
scs_set_d(R, y.d);
scs_mul(R, R, inv_wi);
/*
* Polynomial evaluation of log(1 + R) with an error less than 2^(-130)
*/
scs_mul(res1, constant_poly_ptr[0], R);
for(i=1; i<20; i++){
scs_add(addi, constant_poly_ptr[i], res1);
scs_mul(res1, addi, R);
}
if(E==0){
scs_add(res, res1, ti);
}else{
/* sc_ln2_times_E = E*log(2) */
scs_set(sc_ln2_times_E, sc_ln2_ptr);
if (E >= 0){
scs_mul_ui(sc_ln2_times_E, (unsigned int) E);
}else{
scs_mul_ui(sc_ln2_times_E, (unsigned int) -E);
sc_ln2_times_E->sign = -1;
}
scs_add(addi, res1, ti);
scs_add(res, addi, sc_ln2_times_E);
}
}
/* */