intervals 0.3.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION.txt +1 -0
- data/ext/crlibm/AUTHORS +2 -0
- data/ext/crlibm/COPYING +504 -0
- data/ext/crlibm/ChangeLog +80 -0
- data/ext/crlibm/INSTALL +182 -0
- data/ext/crlibm/Makefile.am +84 -0
- data/ext/crlibm/Makefile.in +530 -0
- data/ext/crlibm/NEWS +0 -0
- data/ext/crlibm/README +31 -0
- data/ext/crlibm/TODO +47 -0
- data/ext/crlibm/VERSION +1 -0
- data/ext/crlibm/aclocal.m4 +989 -0
- data/ext/crlibm/atan-itanium.c +846 -0
- data/ext/crlibm/atan-pentium.c +261 -0
- data/ext/crlibm/atan_accurate.c +244 -0
- data/ext/crlibm/atan_accurate.h +191 -0
- data/ext/crlibm/atan_fast.c +324 -0
- data/ext/crlibm/atan_fast.h +678 -0
- data/ext/crlibm/config.guess +1461 -0
- data/ext/crlibm/config.sub +1566 -0
- data/ext/crlibm/configure +7517 -0
- data/ext/crlibm/configure.ac +364 -0
- data/ext/crlibm/crlibm.h +125 -0
- data/ext/crlibm/crlibm_config.h +149 -0
- data/ext/crlibm/crlibm_config.h.in +148 -0
- data/ext/crlibm/crlibm_private.c +293 -0
- data/ext/crlibm/crlibm_private.h +658 -0
- data/ext/crlibm/csh_fast.c +631 -0
- data/ext/crlibm/csh_fast.h +771 -0
- data/ext/crlibm/double-extended.h +496 -0
- data/ext/crlibm/exp-td.c +962 -0
- data/ext/crlibm/exp-td.h +685 -0
- data/ext/crlibm/exp_accurate.c +197 -0
- data/ext/crlibm/exp_accurate.h +85 -0
- data/ext/crlibm/gappa/log-de-E0-logir0.gappa +106 -0
- data/ext/crlibm/gappa/log-de-E0.gappa +79 -0
- data/ext/crlibm/gappa/log-de.gappa +81 -0
- data/ext/crlibm/gappa/log-td-E0-logir0.gappa +126 -0
- data/ext/crlibm/gappa/log-td-E0.gappa +143 -0
- data/ext/crlibm/gappa/log-td-accurate-E0-logir0.gappa +230 -0
- data/ext/crlibm/gappa/log-td-accurate-E0.gappa +213 -0
- data/ext/crlibm/gappa/log-td-accurate.gappa +217 -0
- data/ext/crlibm/gappa/log-td.gappa +156 -0
- data/ext/crlibm/gappa/trigoSinCosCase3.gappa +204 -0
- data/ext/crlibm/gappa/trigoTanCase2.gappa +73 -0
- data/ext/crlibm/install-sh +269 -0
- data/ext/crlibm/log-de.c +431 -0
- data/ext/crlibm/log-de.h +732 -0
- data/ext/crlibm/log-td.c +852 -0
- data/ext/crlibm/log-td.h +819 -0
- data/ext/crlibm/log10-td.c +906 -0
- data/ext/crlibm/log10-td.h +823 -0
- data/ext/crlibm/log2-td.c +935 -0
- data/ext/crlibm/log2-td.h +821 -0
- data/ext/crlibm/maple/atan.mpl +359 -0
- data/ext/crlibm/maple/common-procedures.mpl +997 -0
- data/ext/crlibm/maple/csh.mpl +446 -0
- data/ext/crlibm/maple/double-extended.mpl +151 -0
- data/ext/crlibm/maple/exp-td.mpl +195 -0
- data/ext/crlibm/maple/log-de.mpl +243 -0
- data/ext/crlibm/maple/log-td.mpl +316 -0
- data/ext/crlibm/maple/log10-td.mpl +345 -0
- data/ext/crlibm/maple/log2-td.mpl +334 -0
- data/ext/crlibm/maple/trigo.mpl +728 -0
- data/ext/crlibm/maple/triple-double.mpl +58 -0
- data/ext/crlibm/missing +198 -0
- data/ext/crlibm/mkinstalldirs +40 -0
- data/ext/crlibm/rem_pio2_accurate.c +219 -0
- data/ext/crlibm/rem_pio2_accurate.h +53 -0
- data/ext/crlibm/scs_lib/AUTHORS +3 -0
- data/ext/crlibm/scs_lib/COPYING +504 -0
- data/ext/crlibm/scs_lib/ChangeLog +16 -0
- data/ext/crlibm/scs_lib/INSTALL +215 -0
- data/ext/crlibm/scs_lib/Makefile.am +18 -0
- data/ext/crlibm/scs_lib/Makefile.in +328 -0
- data/ext/crlibm/scs_lib/NEWS +0 -0
- data/ext/crlibm/scs_lib/README +9 -0
- data/ext/crlibm/scs_lib/TODO +4 -0
- data/ext/crlibm/scs_lib/addition_scs.c +623 -0
- data/ext/crlibm/scs_lib/config.guess +1461 -0
- data/ext/crlibm/scs_lib/config.sub +1566 -0
- data/ext/crlibm/scs_lib/configure +6226 -0
- data/ext/crlibm/scs_lib/division_scs.c +110 -0
- data/ext/crlibm/scs_lib/double2scs.c +174 -0
- data/ext/crlibm/scs_lib/install-sh +269 -0
- data/ext/crlibm/scs_lib/missing +198 -0
- data/ext/crlibm/scs_lib/mkinstalldirs +40 -0
- data/ext/crlibm/scs_lib/multiplication_scs.c +456 -0
- data/ext/crlibm/scs_lib/poly_fct.c +112 -0
- data/ext/crlibm/scs_lib/print_scs.c +73 -0
- data/ext/crlibm/scs_lib/rand_scs.c +63 -0
- data/ext/crlibm/scs_lib/scs.h +353 -0
- data/ext/crlibm/scs_lib/scs2double.c +391 -0
- data/ext/crlibm/scs_lib/scs2mpf.c +58 -0
- data/ext/crlibm/scs_lib/scs2mpfr.c +61 -0
- data/ext/crlibm/scs_lib/scs_private.c +23 -0
- data/ext/crlibm/scs_lib/scs_private.h +133 -0
- data/ext/crlibm/scs_lib/tests/tbx_timing.h +102 -0
- data/ext/crlibm/scs_lib/wrapper_scs.h +486 -0
- data/ext/crlibm/scs_lib/zero_scs.c +52 -0
- data/ext/crlibm/stamp-h.in +1 -0
- data/ext/crlibm/tests/Makefile.am +43 -0
- data/ext/crlibm/tests/Makefile.in +396 -0
- data/ext/crlibm/tests/blind_test.c +148 -0
- data/ext/crlibm/tests/generate_test_vectors.c +258 -0
- data/ext/crlibm/tests/soak_test.c +334 -0
- data/ext/crlibm/tests/test_common.c +627 -0
- data/ext/crlibm/tests/test_common.h +28 -0
- data/ext/crlibm/tests/test_perf.c +570 -0
- data/ext/crlibm/tests/test_val.c +249 -0
- data/ext/crlibm/trigo_accurate.c +500 -0
- data/ext/crlibm/trigo_accurate.h +331 -0
- data/ext/crlibm/trigo_fast.c +1219 -0
- data/ext/crlibm/trigo_fast.h +639 -0
- data/ext/crlibm/triple-double.h +878 -0
- data/ext/extconf.rb +31 -0
- data/ext/fpu.c +107 -0
- data/ext/jamis-mod.rb +591 -0
- data/lib/fpu.rb +287 -0
- data/lib/interval.rb +1170 -0
- data/lib/intervals.rb +212 -0
- data/lib/struct_float.rb +133 -0
- data/test/data_atan.txt +360 -0
- data/test/data_cos.txt +346 -0
- data/test/data_cosh.txt +3322 -0
- data/test/data_exp.txt +3322 -0
- data/test/data_log.txt +141 -0
- data/test/data_sin.txt +140 -0
- data/test/data_sinh.txt +3322 -0
- data/test/data_tan.txt +342 -0
- metadata +186 -0
@@ -0,0 +1,197 @@
|
|
1
|
+
/*
|
2
|
+
* Correctly rounded exponential
|
3
|
+
*
|
4
|
+
* Author : David Defour
|
5
|
+
*
|
6
|
+
* This file is part of the crlibm library developed by the Arenaire
|
7
|
+
* project at Ecole Normale Superieure de Lyon
|
8
|
+
*
|
9
|
+
* This program is free software; you can redistribute it and/or modify
|
10
|
+
* it under the terms of the GNU Lesser General Public License as published by
|
11
|
+
* the Free Software Foundation; either version 2 of the License, or
|
12
|
+
* (at your option) any later version.
|
13
|
+
*
|
14
|
+
* This program is distributed in the hope that it will be useful,
|
15
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
* GNU General Public License for more details.
|
18
|
+
*
|
19
|
+
* You should have received a copy of the GNU Lesser General Public License
|
20
|
+
* along with this program; if not, write to the Free Software
|
21
|
+
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
22
|
+
*/
|
23
|
+
#include <stdio.h>
|
24
|
+
#include <stdlib.h>
|
25
|
+
#include "crlibm.h"
|
26
|
+
#include "crlibm_private.h"
|
27
|
+
#include "exp_accurate.h"
|
28
|
+
|
29
|
+
|
30
|
+
/***********************************************************/
|
31
|
+
/* Second step */
|
32
|
+
/***********************************************************/
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
/**
|
37
|
+
* We use the Brent formula to evaluate exp(x)
|
38
|
+
*
|
39
|
+
* 1) Step 1 : range reduction
|
40
|
+
*
|
41
|
+
* x - k * ln(2) -ln(2) +ln(2)
|
42
|
+
* r = --------------------- ------ < r < ------
|
43
|
+
* 512 1024 1024
|
44
|
+
*
|
45
|
+
* (512) (k)
|
46
|
+
* so that exp(x) = exp(r)^ * 2^
|
47
|
+
*
|
48
|
+
*
|
49
|
+
* 2) Step 2 : polynomial evaluation
|
50
|
+
*
|
51
|
+
* 2 3 4 5
|
52
|
+
* exp(r) ~ (1 + r + r^ /2! + r^ /3! + r^ /4! + r^ /5!
|
53
|
+
* 6 7 8 9
|
54
|
+
* + r^ /6! + r^ /7! + r^ /8! + r^ /9!
|
55
|
+
* 10 11
|
56
|
+
* + r^ /10! + r^ /11! )*(1+err)
|
57
|
+
*
|
58
|
+
* (-164)
|
59
|
+
* where |err| < 2^
|
60
|
+
*
|
61
|
+
*
|
62
|
+
* 3) Step 3 : compute exp(r) to the power of 512
|
63
|
+
*
|
64
|
+
* (512) 2 2 2 2 2 2 2 2 2
|
65
|
+
* exp(r)^ = ((((((((exp(r)^ )^ )^ )^ )^ )^ )^ )^ )^
|
66
|
+
*
|
67
|
+
*
|
68
|
+
*
|
69
|
+
* 4) Step 4 : reconstruction
|
70
|
+
*
|
71
|
+
* (512) (k)
|
72
|
+
* exp(x) = exp(r)^ * 2^
|
73
|
+
*
|
74
|
+
*
|
75
|
+
* Take an scs number as input and give the exponential of x
|
76
|
+
* exactly rounded to nearest.
|
77
|
+
*
|
78
|
+
* Notes:
|
79
|
+
* - Flags need to be set to round to nearest
|
80
|
+
*/
|
81
|
+
|
82
|
+
void exp_SC(scs_ptr res_scs, double x){
|
83
|
+
scs_t sc1, red, red_low;
|
84
|
+
db_number db;
|
85
|
+
int i, k;
|
86
|
+
|
87
|
+
|
88
|
+
/* db.d = x/512 (= 2^9) */
|
89
|
+
|
90
|
+
db.d = x;
|
91
|
+
db.i[HI] -= (9 << 20);
|
92
|
+
scs_set_d(sc1, db.d);
|
93
|
+
|
94
|
+
|
95
|
+
DOUBLE2INT(k, (db.d * iln2_o512.d));
|
96
|
+
|
97
|
+
/* 1) R�duction d'argument */
|
98
|
+
|
99
|
+
scs_set(red, sc_ln2_o512_1_ptr);
|
100
|
+
scs_set(red_low, sc_ln2_o512_2_ptr);
|
101
|
+
if (k>0){
|
102
|
+
scs_mul_ui(red, (unsigned int) k);
|
103
|
+
scs_mul_ui(red_low, (unsigned int) k);
|
104
|
+
}else {
|
105
|
+
scs_mul_ui(red, (unsigned int)(-k));
|
106
|
+
scs_mul_ui(red_low, (unsigned int)(-k));
|
107
|
+
red->sign *= -1;
|
108
|
+
red_low->sign *=-1;
|
109
|
+
}
|
110
|
+
|
111
|
+
scs_sub(red, sc1, red);
|
112
|
+
scs_sub(red, red, red_low);
|
113
|
+
|
114
|
+
|
115
|
+
/* 2) Evaluation polynomiale */
|
116
|
+
|
117
|
+
scs_mul(res_scs, constant_poly_ptr[0], red);
|
118
|
+
for(i=1; i< 10; i++){
|
119
|
+
scs_add(res_scs, constant_poly_ptr[i], res_scs);
|
120
|
+
scs_mul(res_scs, red, res_scs);
|
121
|
+
}
|
122
|
+
|
123
|
+
scs_add(res_scs, SCS_ONE, res_scs);
|
124
|
+
scs_mul(res_scs, red, res_scs);
|
125
|
+
scs_add(res_scs, SCS_ONE, res_scs);
|
126
|
+
|
127
|
+
/* 3) Mise a la puissance exp(r)^512 */
|
128
|
+
for(i=0; i<9; i++)
|
129
|
+
scs_square(res_scs, res_scs);
|
130
|
+
|
131
|
+
|
132
|
+
res_scs->index += (int)(k/30);
|
133
|
+
if ((k%30) > 0)
|
134
|
+
scs_mul_ui(res_scs, (unsigned int) (1<<((k%30))));
|
135
|
+
else if ((k%30) < 0){
|
136
|
+
res_scs->index --;
|
137
|
+
scs_mul_ui(res_scs, (unsigned int) (1<<((30+(k%30)))));
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
/*************************************************************
|
144
|
+
*************************************************************
|
145
|
+
* ROUNDED TO NEAREST *
|
146
|
+
*************************************************************
|
147
|
+
*************************************************************/
|
148
|
+
double scs_exp_rn(double x){
|
149
|
+
scs_t res_scs;
|
150
|
+
db_number res;
|
151
|
+
|
152
|
+
#if EVAL_PERF==1
|
153
|
+
crlibm_second_step_taken++;
|
154
|
+
/* printf("second step taken"); */
|
155
|
+
#endif
|
156
|
+
|
157
|
+
|
158
|
+
/* 4) Reconstruction */
|
159
|
+
|
160
|
+
exp_SC(res_scs, x);
|
161
|
+
scs_get_d(&res.d, res_scs);
|
162
|
+
|
163
|
+
return res.d;
|
164
|
+
}
|
165
|
+
|
166
|
+
|
167
|
+
/*************************************************************
|
168
|
+
*************************************************************
|
169
|
+
* ROUNDED TOWARD -INFINITY *
|
170
|
+
*************************************************************
|
171
|
+
*************************************************************/
|
172
|
+
double scs_exp_rd(double x){
|
173
|
+
scs_t res_scs;
|
174
|
+
db_number res;
|
175
|
+
|
176
|
+
exp_SC(res_scs, x);
|
177
|
+
scs_get_d_minf(&res.d, res_scs);
|
178
|
+
|
179
|
+
return res.d;
|
180
|
+
}
|
181
|
+
|
182
|
+
|
183
|
+
/*************************************************************
|
184
|
+
*************************************************************
|
185
|
+
* ROUNDED TOWARD +INFINITY *
|
186
|
+
*************************************************************
|
187
|
+
*************************************************************/
|
188
|
+
double scs_exp_ru(double x){
|
189
|
+
scs_t res_scs;
|
190
|
+
db_number res;
|
191
|
+
|
192
|
+
exp_SC(res_scs, x);
|
193
|
+
scs_get_d_pinf(&res.d, res_scs);
|
194
|
+
|
195
|
+
return res.d;
|
196
|
+
}
|
197
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
/***********************************************************/
|
5
|
+
/* Second step */
|
6
|
+
/***********************************************************/
|
7
|
+
|
8
|
+
#ifdef WORDS_BIGENDIAN
|
9
|
+
static const db_number
|
10
|
+
iln2_o512 = {{0x40871547, 0x652B82FE}}; /* 512/ln(2) */
|
11
|
+
#else
|
12
|
+
static const db_number
|
13
|
+
iln2_o512 = {{0x652B82FE, 0x40871547}}; /* 512/ln(2) */
|
14
|
+
#endif
|
15
|
+
|
16
|
+
static const struct scs
|
17
|
+
sc_ln2_o512_1 = {{0x00162e42, 0x3fbe8e7b, 0x335793c7, 0x19cc01f9,
|
18
|
+
0x1ed5e81e, 0x1a193394, 0x316c5b14, 0x00000000},
|
19
|
+
DB_ONE, -1, 1 },
|
20
|
+
sc_ln2_o512_2 = {{0x068badc5, 0x355f457c, 0x3dc3b103, 0x1bd75930,
|
21
|
+
0x2acaa97d, 0x295f4362, 0x07697571, 0x2b827042},
|
22
|
+
DB_ONE, -8, 1 };
|
23
|
+
|
24
|
+
#define sc_ln2_o512_1_ptr ((scs_ptr)(&sc_ln2_o512_1))
|
25
|
+
#define sc_ln2_o512_2_ptr ((scs_ptr)(&sc_ln2_o512_2))
|
26
|
+
|
27
|
+
|
28
|
+
/* We should add 1+x to this polynom and multiply it by x^2 */
|
29
|
+
static const scs constant_poly[10]= /* 2^-164 */
|
30
|
+
/* ~2.505211e-08 */
|
31
|
+
{{{0x0000001a, 0x39915ae6, 0x271b3b26, 0x3bc3c8d6,
|
32
|
+
0x327f2894, 0x1a80bba6, 0x2d7be149, 0x149ab262},
|
33
|
+
DB_ONE, -1, 1 }
|
34
|
+
,
|
35
|
+
/* ~2.755732e-07 */
|
36
|
+
{{0x00000127, 0x393ee8a7, 0x2647a705, 0x037af958,
|
37
|
+
0x0c753fb3, 0x0941e129, 0x13162578, 0x1773558f},
|
38
|
+
DB_ONE, -1, 1 }
|
39
|
+
,
|
40
|
+
/* ~2.755732e-06 */
|
41
|
+
{{0x00000b8e, 0x3c74aad8, 0x399abcfd, 0x1225e04b,
|
42
|
+
0x2e8dea13, 0x038b8517, 0x3212cece, 0x2cb577c5},
|
43
|
+
DB_ONE, -1, 1 }
|
44
|
+
,
|
45
|
+
/* ~2.480159e-05 */
|
46
|
+
{{0x00006806, 0x201a01a0, 0x066e4bb6, 0x156666d6,
|
47
|
+
0x333d1ab0, 0x06772281, 0x044e4578, 0x04d8d60d},
|
48
|
+
DB_ONE, -1, 1 }
|
49
|
+
,
|
50
|
+
/* ~1.984127e-04 */
|
51
|
+
{{0x00034034, 0x00d00d00, 0x34034034, 0x0249047b,
|
52
|
+
0x38e5a9d7, 0x30805847, 0x335f9062, 0x206ba2e1},
|
53
|
+
DB_ONE, -1, 1 }
|
54
|
+
,
|
55
|
+
/* ~1.388889e-03 */
|
56
|
+
{{0x0016c16c, 0x05b05b05, 0x2c16c16c, 0x121e8acb,
|
57
|
+
0x25da960e, 0x2999616d, 0x2b3ae80c, 0x1a17471d},
|
58
|
+
DB_ONE, -1, 1 }
|
59
|
+
,
|
60
|
+
/* ~8.333333e-03 */
|
61
|
+
{{0x00888888, 0x22222222, 0x08888888, 0x22222220,
|
62
|
+
0x072a661e, 0x15f0a5cf, 0x3fc53e81, 0x3da68844},
|
63
|
+
DB_ONE, -1, 1 }
|
64
|
+
,
|
65
|
+
/* ~4.166667e-02 */
|
66
|
+
{{0x02aaaaaa, 0x2aaaaaaa, 0x2aaaaaaa, 0x2aaaaa9e,
|
67
|
+
0x2e389977, 0x07fcaf81, 0x07fee303, 0x13eab39c},
|
68
|
+
DB_ONE, -1, 1 }
|
69
|
+
,
|
70
|
+
/* ~1.666667e-01 */
|
71
|
+
{{0x0aaaaaaa, 0x2aaaaaaa, 0x2aaaaaaa, 0x2aaaaaaa,
|
72
|
+
0x2aaaaadc, 0x1902174f, 0x32f46829, 0x13f2855b},
|
73
|
+
DB_ONE, -1, 1 }
|
74
|
+
,
|
75
|
+
/* ~5.000000e-01 */
|
76
|
+
{{0x20000000, 0x00000000, 0x00000000, 0x00000000,
|
77
|
+
0x00000075, 0x21e5e9c2, 0x1e95e039, 0x17dad7b5},
|
78
|
+
DB_ONE, -1, 1 }
|
79
|
+
};
|
80
|
+
|
81
|
+
|
82
|
+
#define constant_poly_ptr (scs_ptr)&constant_poly
|
83
|
+
|
84
|
+
|
85
|
+
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# Usage: You need to set the constants. Running the log-de.mpl Maple script
|
2
|
+
# should create the required sed files. The command to run is
|
3
|
+
# sed -f TEMPLOG/log-de_0.sed log-de-E0-logir0.gappa | gappa > /dev/null
|
4
|
+
|
5
|
+
# NOTATION CONVENTION
|
6
|
+
# Variables that correspond to double-precision variables in the code begin with a small letter
|
7
|
+
# Other variables begin with a capital letter.
|
8
|
+
# Variables that will be replaced with Maple-computed constants begin with an underscore
|
9
|
+
# Otherwise avoid underscores as they are painful to carry on to LaTeX :)
|
10
|
+
|
11
|
+
# polynomial coefficients, computed by Maple
|
12
|
+
c1 = <float64ne>(_c1);
|
13
|
+
c2 = <float64ne>(_c2);
|
14
|
+
c3 = <float64ne>(_c3);
|
15
|
+
c4 = <float64ne>(_c4);
|
16
|
+
c5 = <float64ne>(_c5);
|
17
|
+
c6 = <float64ne>(_c6);
|
18
|
+
c7 = <float64ne>(_c7);
|
19
|
+
log2h = <float64ne>(_log2h);
|
20
|
+
log2l = <float64ne>(_log2l);
|
21
|
+
|
22
|
+
# Transcription of the code, NOT using FMA
|
23
|
+
z2 <float80ne>= z*z;
|
24
|
+
p67 <float80ne>= c6 + z*c7;
|
25
|
+
p45 <float80ne>= c4 + z*c5;
|
26
|
+
p23 <float80ne>= c2 + z*c3;
|
27
|
+
z4 <float80ne>= z2*z2;
|
28
|
+
p47 <float80ne>= p45 + z2*p67;
|
29
|
+
p03 <float80ne>= z + z2*p23;
|
30
|
+
log <float80ne>= p03 + z4*p47;
|
31
|
+
|
32
|
+
|
33
|
+
# Give the polynomial in Estrin form (no need to transcribe the intermediate steps)
|
34
|
+
# Since the argument reduction is exact, z=Z.
|
35
|
+
Z2 = z*z;
|
36
|
+
Z4 = Z2*Z2;
|
37
|
+
Z3 = z*z*z; # to lighten the hints
|
38
|
+
|
39
|
+
P23 = (c2+z*c3);
|
40
|
+
P47 = (c4 + z*c5) + Z2*(c6 + z*c7);
|
41
|
+
P03 = z + Z2*P23;
|
42
|
+
AP03 = z + Z2*p23;
|
43
|
+
AP03R0 = z + z2*p23;
|
44
|
+
AP03R1 = z+<float80ne>(z2*p23);
|
45
|
+
# AP03R2 = p03
|
46
|
+
|
47
|
+
PolyLog1pz = P03 + Z4*P47 ;
|
48
|
+
|
49
|
+
# PolyLog1pz = P03 + Z4*P47, with the differential between p47 and P47 managed below
|
50
|
+
LogR = p03 + Z4*p47;
|
51
|
+
LogR0 = p03 + z4*p47;
|
52
|
+
LogR1 = p03 + <float80ne>(z4*p47);
|
53
|
+
# LogR2 = log
|
54
|
+
|
55
|
+
{
|
56
|
+
z in [-_zmax, _zmax]
|
57
|
+
/\ (PolyLog1pz - Log)/Log in [-_epsilonApproxQuick, _epsilonApproxQuick]
|
58
|
+
|
59
|
+
->
|
60
|
+
|
61
|
+
(log - Log)/Log in [-1b-61, 1b-61]
|
62
|
+
}
|
63
|
+
|
64
|
+
# the obvious decomposition of (log-Log)/Log:
|
65
|
+
(log-Log)/Log -> (log - PolyLog1pz)/PolyLog1pz + (PolyLog1pz - Log)/Log + ((log - PolyLog1pz)/PolyLog1pz) * ((PolyLog1pz - Log)/Log);
|
66
|
+
|
67
|
+
# Intermediate steps for epsilon(log,PolyLog1pz)
|
68
|
+
(log - PolyLog1pz)/PolyLog1pz -> (log-LogR1)/LogR1 + (LogR1 - PolyLog1pz)/PolyLog1pz + ((log-LogR1)/LogR1)* ((LogR1 - PolyLog1pz)/PolyLog1pz);
|
69
|
+
(LogR1 - PolyLog1pz)/PolyLog1pz -> (LogR1- LogR0)/LogR0 + (LogR0 - PolyLog1pz)/PolyLog1pz + ((LogR1- LogR0)/LogR0) * ((LogR0 - PolyLog1pz)/PolyLog1pz);
|
70
|
+
(LogR0 - PolyLog1pz)/PolyLog1pz -> (LogR0 -LogR)/LogR + (LogR - PolyLog1pz)/PolyLog1pz + ((LogR0 -LogR)/LogR)*((LogR - PolyLog1pz)/PolyLog1pz);
|
71
|
+
|
72
|
+
# First we need to get an error of p03 (I think. There may well be a shorter path to a proof)
|
73
|
+
|
74
|
+
# layers of approx
|
75
|
+
(p03 - P03)/P03 -> (p03 - AP03)/AP03 + (AP03-P03)/P03 + ((p03 - AP03)/AP03) * ((AP03-P03)/P03);
|
76
|
+
(p03 - AP03)/AP03 -> (p03 - AP03R1)/AP03R1 + (AP03R1 - AP03)/AP03 + ((p03 - AP03R1)/AP03R1) * ((AP03R1 - AP03)/AP03) ;
|
77
|
+
(AP03R1 - AP03)/AP03 -> (AP03R1 - AP03R0)/AP03R0 + (AP03R0 - AP03)/AP03 + ((AP03R1 - AP03R0)/AP03R0)*((AP03R0 - AP03)/AP03) ;
|
78
|
+
|
79
|
+
(AP03-P03)/P03 -> z*(p23-P23)/(1+z*P23);
|
80
|
+
|
81
|
+
# Now all the trick is to factor z, so as to divide by (1+epsilon)
|
82
|
+
#(AP03R1 - AP03R0)/AP03R0 -> ( (z*p23) * ((<float80ne>(z2*p23) - (z2*p23))/ (z2*p23)) ) / (1 + (z2/z)*p23) ;
|
83
|
+
(AP03R1 - AP03R0)/AP03R0 -> ((<float80ne>(z2*p23) - (z2*p23))/z) / (1 + (z2/z)*p23) ;
|
84
|
+
(<float80ne>(z2*p23) - (z2*p23))/z -> ((<float80ne>(z2*p23) - (z2*p23))/(z2*p23)) * (z2/z) * p23;
|
85
|
+
z2/z -> z*((z2-Z2)/Z2) + z;
|
86
|
+
|
87
|
+
(AP03R0 - AP03)/AP03 -> z*(((z2-Z2)/Z2)*p23) / (1 + z*p23);
|
88
|
+
|
89
|
+
# -----------rounding error-------------- ---- small ---
|
90
|
+
(LogR1 - LogR0)/LogR0 -> ((<float80ne>(z4*p47) - z4*p47)/(z4*p47)) * p47 * (z4/(p03+z4*p47));
|
91
|
+
# Now please Gappa remark that (z4/(p03+z4*p47)) is small
|
92
|
+
z4/(p03+z4*p47) -> (z4/Z4) * (Z4 / (p03+z4*p47));
|
93
|
+
z4/Z4 -> (z4-Z4)/Z4 + 1;
|
94
|
+
Z4 / (p03+z4*p47) -> Z3/(p03/z + (z4/z) * p47);
|
95
|
+
z4/z -> Z3* (z4/Z4);
|
96
|
+
p03/z -> (p03/P03) * (P03/z);
|
97
|
+
p03/P03 -> (p03 - P03)/P03 + 1;
|
98
|
+
P03/z -> 1 + z*P23;
|
99
|
+
|
100
|
+
(LogR0 - LogR)/LogR -> ((z4-Z4)/z)*p47 / (p03/z + Z3*p47);
|
101
|
+
(z4-Z4)/z -> ((z4-Z4) / Z4) * Z3;
|
102
|
+
|
103
|
+
|
104
|
+
(LogR - PolyLog1pz)/PolyLog1pz -> ((p03-P03)/z + Z3*(p47-P47)) / (P03/z + Z3*P47);
|
105
|
+
(p03-P03)/z -> ((p03-P03)/P03) * (P03/z);
|
106
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Usage: You need to set the constants. Running the log-de.mpl Maple script
|
2
|
+
# should create the required sed files and give the command to run.
|
3
|
+
|
4
|
+
# NOTATION CONVENTION
|
5
|
+
# Variables that correspond to double-precision variables in the code begin with a small letter
|
6
|
+
# Other variables begin with a capital letter.
|
7
|
+
# Variables that will be replaced with Maple-computed constants begin with an underscore
|
8
|
+
# Otherwise avoid underscores as they are painful to carry on to LaTeX :)
|
9
|
+
|
10
|
+
# polynomial coefficients, computed by Maple
|
11
|
+
c1 = <float64ne>(_c1);
|
12
|
+
c2 = <float64ne>(_c2);
|
13
|
+
c3 = <float64ne>(_c3);
|
14
|
+
c4 = <float64ne>(_c4);
|
15
|
+
c5 = <float64ne>(_c5);
|
16
|
+
c6 = <float64ne>(_c6);
|
17
|
+
c7 = <float64ne>(_c7);
|
18
|
+
log2h = <float64ne>(_log2h);
|
19
|
+
log2l = <float64ne>(_log2l);
|
20
|
+
r = <float64ne>(_r);
|
21
|
+
logirh = <float64ne>(_logirh);
|
22
|
+
logirl = <float64ne>(_logirl);
|
23
|
+
|
24
|
+
|
25
|
+
# Transcription of the code, NOT using FMA
|
26
|
+
z2 <float80ne>= z*z;
|
27
|
+
p67 <float80ne>= c6 + z*c7;
|
28
|
+
p45 <float80ne>= c4 + z*c5;
|
29
|
+
p23 <float80ne>= c2 + z*c3;
|
30
|
+
p01 <float80ne>= logirh + z;
|
31
|
+
z4 <float80ne>= z2*z2;
|
32
|
+
p47 <float80ne>= p45 + z2*p67;
|
33
|
+
p03 <float80ne>= p01 + z2*p23;
|
34
|
+
log <float80ne>= p03 + z4*p47;
|
35
|
+
|
36
|
+
# Exact mathematical definition of the log
|
37
|
+
Log = Log1pz + Logir;
|
38
|
+
|
39
|
+
############# Now come auxiliary definitions
|
40
|
+
|
41
|
+
# Give the polynomial in Estrin form (no need to transcribe the intermediate steps)
|
42
|
+
# Since the argument reduction is exact, z=Z.
|
43
|
+
Z2 = z*z;
|
44
|
+
Z4 = Z2*Z2;
|
45
|
+
ALog = ( (logirh+z) + Z2*(c2+z*c3) ) + Z4*( (c4+z*c5) + Z2*(c6+z*c7) );
|
46
|
+
|
47
|
+
# Useless definition, except for debugging the proof
|
48
|
+
P07R = ( (logirh+z) + z2*(c2+z*c3) ) + z4*( (c4+z*c5) + z2*(c6+z*c7) );
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
PolyLog1pz = z + Z2*(c2+z*c3) + Z4*( (c4+z*c5) + Z2*(c6+z*c7) );
|
53
|
+
|
54
|
+
|
55
|
+
{
|
56
|
+
z in [-_zmax, _zmax]
|
57
|
+
/\ (logirh + logirl) - Logir in [-1b-129, 1b-129]
|
58
|
+
/\ (PolyLog1pz - Log1pz)/Log1pz in [-_epsilonApproxQuick, _epsilonApproxQuick]
|
59
|
+
/\ (PolyLog1pz - Log1pz) in [-_deltaApproxQuick, _deltaApproxQuick]
|
60
|
+
->
|
61
|
+
(log - Log)/Log in [-1b-61, 1b-61]
|
62
|
+
}
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
# Trivialities
|
68
|
+
Log2 -> (log2h + log2l) - ((log2h + log2l) - Log2);
|
69
|
+
Logir -> (logirh + logirl) - ((logirh + logirl) -Logir);
|
70
|
+
Log1pz -> PolyLog1pz - (PolyLog1pz - Log1pz);
|
71
|
+
|
72
|
+
(logirh-Logir) -> ((logirh + logirl) - Logir) - logirl;
|
73
|
+
|
74
|
+
(log-Log)/Log -> (log - ALog)/ALog + (ALog - Log)/Log + ((log - ALog)/ALog) * ((ALog - Log)/Log);
|
75
|
+
|
76
|
+
# A complex rule obtained by substituting by hand the definitions of ALog and Log until they could be usefully aligned.
|
77
|
+
ALog - Log -> (logirh-Logir) + (PolyLog1pz - Log1pz) ;
|
78
|
+
(ALog - Log)/Log -> (logirh-Logir)/Logir + (PolyLog1pz - Log1pz)/Log1pz + ((logirh-Logir)/Logir) * ((PolyLog1pz - Log1pz)/Log1pz) ;
|
79
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Usage: You need to set the constants. Running the log-de.mpl Maple script
|
2
|
+
# should create the required sed files and give the command to run.
|
3
|
+
|
4
|
+
# NOTATION CONVENTION
|
5
|
+
# Variables that correspond to double-precision variables in the code begin with a small letter
|
6
|
+
# Other variables begin with a capital letter.
|
7
|
+
# Variables that will be replaced with Maple-computed constants begin with an underscore
|
8
|
+
# Otherwise avoid underscores as they are painful to carry on to LaTeX :)
|
9
|
+
|
10
|
+
# polynomial coefficients, computed by Maple
|
11
|
+
c1 = <float64ne>(_c1);
|
12
|
+
c2 = <float64ne>(_c2);
|
13
|
+
c3 = <float64ne>(_c3);
|
14
|
+
c4 = <float64ne>(_c4);
|
15
|
+
c5 = <float64ne>(_c5);
|
16
|
+
c6 = <float64ne>(_c6);
|
17
|
+
c7 = <float64ne>(_c7);
|
18
|
+
log2h = <float64ne>(_log2h);
|
19
|
+
log2 = <float64ne>(_log2l);
|
20
|
+
r = <float64ne>(_r);
|
21
|
+
logirh = <float64ne>(_logirh);
|
22
|
+
logirl = <float64ne>(_logirl);
|
23
|
+
|
24
|
+
E=1; # TODO paper proof that E=1 is the worst case
|
25
|
+
|
26
|
+
|
27
|
+
# Transcription of the code, NOT using FMA
|
28
|
+
z2 <float80ne>= z*z;
|
29
|
+
p67 <float80ne>= c6 + z*c7;
|
30
|
+
p45 <float80ne>= c4 + z*c5;
|
31
|
+
p23 <float80ne>= c2 + z*c3;
|
32
|
+
p01 <float80ne>= logirh + z*c1;
|
33
|
+
z4 <float80ne>= z2*z2;
|
34
|
+
p47 <float80ne>= p45 + z2*p67;
|
35
|
+
p03 <float80ne>= p01 + z2*p23;
|
36
|
+
p07 <float80ne>= p03 + z4*p47;
|
37
|
+
log <float80ne>= p07 + E*log2h;
|
38
|
+
|
39
|
+
# Exact mathematical definition of the log
|
40
|
+
Log = Log1pz + Logir + E*Log2;
|
41
|
+
|
42
|
+
############# Now come auxiliary definitions
|
43
|
+
|
44
|
+
# Give the polynomial in Estrin form (no need to transcribe the intermediate steps)
|
45
|
+
# Since the argument reduction is exact, z=Z.
|
46
|
+
Z2 = z*z;
|
47
|
+
Z4 = Z2*Z2;
|
48
|
+
P07 = ( (logirh+z*c1) + Z2*(c2+z*c3) ) + Z4*( (c4+z*c5) + Z2*(c6+z*c7) );
|
49
|
+
|
50
|
+
# Useless definition, except for debugging the proof
|
51
|
+
P07R = ( (logirh+z*c1) + z2*(c2+z*c3) ) + z4*( (c4+z*c5) + z2*(c6+z*c7) );
|
52
|
+
|
53
|
+
ALog = P07 + E*Log2;
|
54
|
+
|
55
|
+
|
56
|
+
PolyLog1pz = z*c1 + Z2*(c2+z*c3) + Z4*( (c4+z*c5) + Z2*(c6+z*c7) );
|
57
|
+
|
58
|
+
|
59
|
+
{
|
60
|
+
z in [-_zmax, _zmax]
|
61
|
+
/\ (log2h + log2l) - Log2 in [-1b-129, 1b-129] # TODO give exact value, just for cleanness
|
62
|
+
/\ (logirh + logirl) - Logir in [-1b-129, 1b-129] # idem. This is true but needs a proof out of Gappa
|
63
|
+
#/\ (PolyLog1pz - Log1pz)/Log1pz in [-_epsilonApproxQuick, _epsilonApproxQuick]
|
64
|
+
/\ (PolyLog1pz - Log1pz) in [-_deltaApproxQuick, _deltaApproxQuick]
|
65
|
+
->
|
66
|
+
(log - Log)/Log in ? # [-1b-62, 1b-62]
|
67
|
+
/\ log-Log in ?
|
68
|
+
/\ log in ?
|
69
|
+
}
|
70
|
+
|
71
|
+
|
72
|
+
# Trivialities
|
73
|
+
Log2 -> (log2h + log2l) - ((log2h + log2l) - Log2);
|
74
|
+
Logir -> logirh + ((logirl - (logirh +logirl -Logir)));
|
75
|
+
Log -> ALog - (ALog-Log);
|
76
|
+
|
77
|
+
log - Log -> (log - ALog) + (ALog - Log);
|
78
|
+
|
79
|
+
# A complex rule obtained by substituting by hand the definitions of ALog and Log until they could be usefully aligned.
|
80
|
+
ALog - Log -> (logirh-Logir) + (PolyLog1pz - Log1pz) ;
|
81
|
+
|
@@ -0,0 +1,126 @@
|
|
1
|
+
|
2
|
+
c3 = <float64ne> (_c3);
|
3
|
+
c4 = <float64ne> (_c4);
|
4
|
+
c5 = <float64ne> (_c5);
|
5
|
+
c6 = <float64ne> (_c6);
|
6
|
+
c7 = <float64ne> (_c7);
|
7
|
+
|
8
|
+
|
9
|
+
E = 0; #MAPLE
|
10
|
+
|
11
|
+
zh = <float64ne> (Z);
|
12
|
+
zl = Z - zh; #MAPLE
|
13
|
+
|
14
|
+
polyHorner <float64ne>= c3 + zh * (c4 + zh * (c5 + zh * (c6 + zh * c7)));
|
15
|
+
|
16
|
+
ZhSquarehl = zh * zh; #MAPLE
|
17
|
+
zhSquareh = <float64ne> (ZhSquarehl);
|
18
|
+
zhSquarel = <float64ne> (ZhSquarehl - zhSquareh);
|
19
|
+
|
20
|
+
zhSquareHalfh = zhSquareh * (-0.5); #MAPLE
|
21
|
+
zhSquareHalfl = zhSquarel * (-0.5); #MAPLE
|
22
|
+
ZhSquareHalfhl = ZhSquarehl * (-0.5); #MAPLE
|
23
|
+
|
24
|
+
ZhCube <float64ne>= (zh * zhSquareh);
|
25
|
+
polyUpper <float64ne>= polyHorner * ZhCube;
|
26
|
+
|
27
|
+
temp = <float64ne> (zh * zl);
|
28
|
+
T1hl = polyUpper - temp; #MAPLE
|
29
|
+
t1h = <float64ne> (T1hl);
|
30
|
+
t1l = <float64ne> (T1hl - t1h);
|
31
|
+
|
32
|
+
T2 = Z + ZhSquareHalfhl; #MAPLE
|
33
|
+
t2h = <float64ne> (T2hl);
|
34
|
+
t2l = <float64ne> (T2hl - t2h);
|
35
|
+
|
36
|
+
PE = T2hl + T1hl; #MAPLE
|
37
|
+
ph = <float64ne> (Phl);
|
38
|
+
pl = <float64ne> (Phl - ph);
|
39
|
+
|
40
|
+
|
41
|
+
#We can simplify the computations in the function in this case as we know that
|
42
|
+
#all operations (add, mult) on 0 (as a double double) are exact.
|
43
|
+
|
44
|
+
Loghm = Phl; #MAPLE
|
45
|
+
|
46
|
+
logh = <float64ne> (Loghm);
|
47
|
+
logm = <float64ne> (Loghm - logh);
|
48
|
+
|
49
|
+
#Mathematical definition of the logarithm and the polynomial
|
50
|
+
|
51
|
+
Phigher = (c3 + Z * (c4 + Z * (c5 + Z * (c6 + Z * c7)))); #MAPLE
|
52
|
+
ZZZ = Z*Z*Z; #MAPLE
|
53
|
+
ZZZPhigher = ZZZ * Phigher; #MAPLE
|
54
|
+
HZZ = (-0.5*Z*Z); #MAPLE
|
55
|
+
ZpHZZ = Z + HZZ; #MAPLE
|
56
|
+
P = ZpHZZ + ZZZPhigher; #MAPLE
|
57
|
+
|
58
|
+
#We apply the same simplification on the mathematical definition of the log
|
59
|
+
Log = Log1pZ; #MAPLE
|
60
|
+
|
61
|
+
|
62
|
+
#Additional useful definitions
|
63
|
+
|
64
|
+
ZZ = Z*Z; #MAPLE
|
65
|
+
ZZZPhigherPzhzl = ZZZPhigher - zh * zl; #MAPLE
|
66
|
+
|
67
|
+
HZ = -0.5*Z; #MAPLE
|
68
|
+
|
69
|
+
Flzhzl = temp; #MAPLE
|
70
|
+
|
71
|
+
{
|
72
|
+
(T2hl - T2) / T2 in [-1b-103,1b-103]
|
73
|
+
/\ (Phl - PE) / PE in [-1b-103,1b-103]
|
74
|
+
/\ Z in [_zmin,_zmax]
|
75
|
+
/\ (P - Log1pZ) / Log1pZ in [-_epsilonApproxQuick,_epsilonApproxQuick]
|
76
|
+
/\ ((logh + logm) - Loghm) / Loghm in [-1b-106,1b-106]
|
77
|
+
->
|
78
|
+
((logh + logm) - Log) / Log in [-5b-65,5b-65]
|
79
|
+
}
|
80
|
+
|
81
|
+
T2hl - T2 -> ((T2hl - T2) / T2) * T2;
|
82
|
+
T2hl -> (T2hl - T2) + T2;
|
83
|
+
|
84
|
+
Phl - PE -> ((Phl - PE) / PE) * PE;
|
85
|
+
Phl -> (Phl - PE) + PE;
|
86
|
+
|
87
|
+
|
88
|
+
(ZhSquarehl - ZZ) / ZZ -> 2 * ((zh - Z) / Z) + ((zh - Z) / Z) * ((zh - Z) / Z);
|
89
|
+
|
90
|
+
(zhSquareh - ZZ) / ZZ -> ((ZhSquarehl - ZZ) / ZZ) + ((zhSquareh - ZhSquarehl) / ZZ);
|
91
|
+
|
92
|
+
(zhSquareh - ZhSquarehl) / ZZ -> ((zhSquareh - ZhSquarehl) / ZhSquarehl) * (ZhSquarehl / ZZ);
|
93
|
+
|
94
|
+
ZhSquarehl / ZZ -> ((ZhSquarehl - ZZ) / ZZ) + 1;
|
95
|
+
|
96
|
+
(ZhCube - ZZZ) / ZZZ -> (((zh * zhSquareh) - ZZZ) / ZZZ) + ((ZhCube - (zh * zhSquareh)) / ZZZ);
|
97
|
+
|
98
|
+
((zh * zhSquareh) - ZZZ) / ZZZ -> (1 + ((zh - Z) / Z)) * (1 + ((zhSquareh - ZZ) / ZZ)) - 1;
|
99
|
+
|
100
|
+
((ZhCube - (zh * zhSquareh)) / ZZZ) -> ((ZhCube - (zh * zhSquareh)) / (zh * zhSquareh)) * (((zh - Z) / Z) + 1) * (((zhSquareh - ZZ) / ZZ) + 1);
|
101
|
+
|
102
|
+
polyHorner / Phigher -> ((polyHorner - Phigher) / Phigher) + 1;
|
103
|
+
|
104
|
+
(polyUpper - ZZZPhigher) / ZZZPhigher -> ((polyHorner - Phigher) / Phigher) + ((ZhCube - ZZZ) / ZZZ) * (polyHorner / Phigher) +
|
105
|
+
+ ((polyUpper - (polyHorner * ZhCube)) / (polyHorner * ZhCube)) * (polyHorner / Phigher) +
|
106
|
+
+ ((ZhCube - ZZZ) / ZZZ) * ((polyUpper - (polyHorner * ZhCube)) / (polyHorner * ZhCube)) *
|
107
|
+
(polyHorner / Phigher);
|
108
|
+
|
109
|
+
|
110
|
+
((ZhSquareHalfhl - (zh * zl)) - HZZ) / HZZ -> - ((zh - Z) / Z) * ((zh - Z) / Z);
|
111
|
+
|
112
|
+
(ZhSquareHalfhl - HZZ) / HZZ -> (ZhSquarehl - ZZ) / ZZ;
|
113
|
+
|
114
|
+
((T2hl - (zh * zl)) - ZpHZZ) / ZpHZZ -> ((HZ * (((ZhSquareHalfhl - (zh * zl)) - HZZ) / HZZ)) + ((T2hl - T2) / T2)
|
115
|
+
+ (HZ * ((T2hl - T2) / T2))
|
116
|
+
+ (HZ * ((ZhSquareHalfhl - HZZ) / HZZ) * ((T2hl - T2) / T2))) / (1 + HZ);
|
117
|
+
|
118
|
+
(PE - P) / P -> (((1 + HZ) * (((T2hl - (zh * zl)) - ZpHZZ) / ZpHZZ)) +
|
119
|
+
((1 + ((zh - Z) / Z)) * (Z * ((zh - Z) / Z)) * ((Flzhzl - (zh * zl)) / (zh * zl)))
|
120
|
+
+ (ZZ * Phigher * ((polyUpper - ZZZPhigher) / ZZZPhigher))) / (1 + HZ + ZZ * Phigher);
|
121
|
+
|
122
|
+
(Phl - P) / P -> ((PE - P) / P) + ((((PE - P) / P) + 1) * ((Phl - PE) / PE));
|
123
|
+
|
124
|
+
(Loghm - Log) / Log -> ((Loghm - P) / P) + ((P - Log) / Log) + ((Loghm - P) / P) * ((P - Log) / Log);
|
125
|
+
|
126
|
+
(((logh + logm) - Log) / Log) -> (((logh + logm) - Loghm) / Loghm) + ((Loghm - Log) / Log) + (((logh + logm) - Loghm) / Loghm) * ((Loghm - Log) / Log);
|