1 /*-------------------------------------------------------------------------
2 expf.c - Computes e**x of a 32-bit float as outlined in [1]
4 Copyright (C) 2001, 2002, Jesus Calvino-Fraga, jesusc@ieee.org
6 This library is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this library; see the file COPYING. If not, write to the
18 Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
21 As a special exception, if you link this library with other files,
22 some of which are compiled with SDCC, to produce an executable,
23 this library does not by itself cause the resulting executable to
24 be covered by the GNU General Public License. This exception does
25 not however invalidate any other reasons why the executable file
26 might be covered by the GNU General Public License.
27 -------------------------------------------------------------------------*/
29 /* [1] William James Cody and W. M. Waite. _Software manual for the
30 elementary functions_, Englewood Cliffs, N.J.:Prentice-Hall, 1980. */
32 /* Version 1.0 - Initial release */
34 #define __SDCC_MATH_LIB
41 #define __SDCC_FLOAT_LIB
44 // TODO: share with other temps
45 static __bit sign_bit
;
46 static __data
unsigned char expf_y
[4];
47 static __data
unsigned char n
;
54 mov _sign_bit
, c
// remember sign
55 clr acc
.7 // and make input positive
58 rlc a
// extract exponent
61 // input is a very small number, so e^x is 1.000000
67 // TODO: check exponent for very small values, and return zero
70 add a
, #0xE8 // is x >= 0.69314718
78 jnc expf_no_range_reduction
80 mov (_expf_y
+ 0), dpl
// keep copy of x in "exp_y"
81 mov (_expf_y
+ 1), dph
92 lcall ___fsmul
// x * 1.442695041 = x / ln(2)
97 lcall ___fs2uchar
// n = int(x * 1.442695041)
102 lcall fs_return_inf
// exponent overflow
109 lcall expf_scale_and_add
110 mov (_expf_y
+ 0), dpl
111 mov (_expf_y
+ 1), dph
118 lcall expf_scale_and_add
119 expf_no_range_reduction
:
122 // Compute e^x using the cordic algorithm. This works over an
123 // input range of 0 to 0.69314712. Can be extended to work from
124 // 0 to 1.0 if the results are normalized, but over the range
125 // we use, the result is always from 1.0 to 1.99999988 (fixed
130 rlc a
// extract exponent to acc
132 mov r1
, dpl
// mantissa to r4/r3/r2/r1
137 // first, align the input into a 32 bit long
138 cjne a
, #121, exp_lshift
142 // exp_a is greater than 121, so left shift
147 // exp_a is less than 121, so right shift
151 exp_noshift
: // r4/r3/r2/r1 = x
153 mov (_expf_y
+ 0), a
// y = 1.0;
156 mov (_expf_y
+ 3), #0x20
157 mov dptr
, #__fs_natural_log_table
165 movc a
, @a
+dptr
// r7/r6/r5/b = table[i]
178 subb a
, b
// compare x to table[i]
185 jc exp_cordic_skip
// if table[i] < x
189 mov r1
, a
// x -= table[i]
200 mov r5
, (_expf_y
+ 1) // r7/r6/r5/b = y >> i
201 mov r6
, (_expf_y
+ 2)
202 mov r7
, (_expf_y
+ 3)
204 lcall __fs_cordic_rshift_r765_unsigned
210 mov (_expf_y
+ 1), a
// y += (y >> i)
219 cjne r0
, #27, exp_cordic_loop
220 mov r4
, (_expf_y
+ 3)
221 mov r3
, (_expf_y
+ 2)
222 mov r2
, (_expf_y
+ 1)
223 mov r1
, (_expf_y
+ 0)
225 lcall fs_normalize_a
// end of cordic
228 add a
, _n
// ldexpf(x, n)
230 lcall fs_round_and_return
232 jnb _sign_bit
, expf_done
240 lcall ___fsdiv
// 1.0 / x
246 clr acc
.7 // Result is always positive!
249 #pragma less_pedantic
252 static void dummy1(void) __naked
262 lcall ___uchar2fs
// turn n into float
263 lcall ___fsmul
// n * scale_factor
272 mov dpl
, (_expf_y
+ 0)
273 mov dph
, (_expf_y
+ 1)
276 lcall ___fsadd
// x += (n * scale_factor)
285 static void dummy(void) __naked
307 djnz r0
, fs_lshift_loop
314 #else // not MATH_ASM_MCS51
316 #define P0 0.2499999995E+0
317 #define P1 0.4160288626E-2
318 #define Q0 0.5000000000E+0
319 #define Q1 0.4998717877E-1
321 #define P(z) ((P1*z)+P0)
322 #define Q(z) ((Q1*z)+Q0)
324 #define C1 0.693359375
325 #define C2 -2.1219444005469058277e-4
327 #define BIGX 88.72283911 /* ln(HUGE_VALF) */
328 #define EXPEPS 1.0E-7 /* exp(1.0E-7)=0.0000001 */
329 #define K1 1.4426950409 /* 1/ln(2) */
331 float expf(float x
) _FLOAT_FUNC_REENTRANT
334 float xn
, g
, r
, z
, y
;
342 if(y
<EXPEPS
) return 1.0;