xref: /netbsd-src/sys/arch/m68k/fpe/fpu_hyperb.c (revision af56d1fe9956bd7c616e18c1b7f025f464618471)
1 /*	$NetBSD: fpu_hyperb.c,v 1.15 2013/04/20 07:33:05 isaki Exp $	*/
2 
3 /*
4  * Copyright (c) 1995  Ken Nakata
5  *	All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the author nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  *	@(#)fpu_hyperb.c	10/24/95
32  */
33 
34 /*
35  * Copyright (c) 2011 Tetsuya Isaki. All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  *
46  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
47  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
50  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
51  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
52  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
53  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
54  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56  * SUCH DAMAGE.
57  */
58 
59 #include <sys/cdefs.h>
60 __KERNEL_RCSID(0, "$NetBSD: fpu_hyperb.c,v 1.15 2013/04/20 07:33:05 isaki Exp $");
61 
62 #include <machine/ieee.h>
63 
64 #include "fpu_emulate.h"
65 
66 /* The number of items to terminate the Taylor expansion */
67 #define MAX_ITEMS	(2000)
68 
69 /*
70  * fpu_hyperb.c: defines the following functions
71  *
72  *	fpu_atanh(), fpu_cosh(), fpu_sinh(), and fpu_tanh()
73  */
74 
75 /*
76  *             1       1 + x
77  * atanh(x) = ---*log(-------)
78  *             2       1 - x
79  */
80 struct fpn *
81 fpu_atanh(struct fpemu *fe)
82 {
83 	struct fpn x;
84 	struct fpn t;
85 	struct fpn *r;
86 
87 	if (ISNAN(&fe->fe_f2))
88 		return &fe->fe_f2;
89 	if (ISINF(&fe->fe_f2))
90 		return fpu_newnan(fe);
91 
92 	/*
93 	 * if x is +0/-0, 68000PRM.pdf says it returns +0/-0 but
94 	 * my real 68882 returns +0 for both.
95 	 */
96 	if (ISZERO(&fe->fe_f2)) {
97 		fe->fe_f2.fp_sign = 0;
98 		return &fe->fe_f2;
99 	}
100 
101 	/*
102 	 * -INF if x == -1
103 	 * +INF if x ==  1
104 	 */
105 	r = &fe->fe_f2;
106 	if (r->fp_exp == 0 && r->fp_mant[0] == FP_1 &&
107 	    r->fp_mant[1] == 0 && r->fp_mant[2] == 0) {
108 		r->fp_class = FPC_INF;
109 		return r;
110 	}
111 
112 	/* NAN if |x| > 1 */
113 	if (fe->fe_f2.fp_exp >= 0)
114 		return fpu_newnan(fe);
115 
116 	CPYFPN(&x, &fe->fe_f2);
117 
118 	/* t := 1 - x */
119 	fpu_const(&fe->fe_f1, FPU_CONST_1);
120 	fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
121 	r = fpu_add(fe);
122 	CPYFPN(&t, r);
123 
124 	/* r := 1 + x */
125 	fpu_const(&fe->fe_f1, FPU_CONST_1);
126 	CPYFPN(&fe->fe_f2, &x);
127 	r = fpu_add(fe);
128 
129 	/* (1-x)/(1+x) */
130 	CPYFPN(&fe->fe_f1, r);
131 	CPYFPN(&fe->fe_f2, &t);
132 	r = fpu_div(fe);
133 
134 	/* log((1-x)/(1+x)) */
135 	CPYFPN(&fe->fe_f2, r);
136 	r = fpu_logn(fe);
137 
138 	/* r /= 2 */
139 	r->fp_exp--;
140 
141 	return r;
142 }
143 
144 /*
145  * taylor expansion used by sinh(), cosh().
146  */
147 static struct fpn *
148 __fpu_sinhcosh_taylor(struct fpemu *fe, struct fpn *s0, uint32_t f)
149 {
150 	struct fpn res;
151 	struct fpn x2;
152 	struct fpn *s1;
153 	struct fpn *r;
154 	int sign;
155 	uint32_t k;
156 
157 	/* x2 := x * x */
158 	CPYFPN(&fe->fe_f1, &fe->fe_f2);
159 	r = fpu_mul(fe);
160 	CPYFPN(&x2, r);
161 
162 	/* res := s0 */
163 	CPYFPN(&res, s0);
164 
165 	sign = 1;	/* sign := (-1)^n */
166 
167 	for (; f < (2 * MAX_ITEMS); ) {
168 		/* (f1 :=) s0 * x^2 */
169 		CPYFPN(&fe->fe_f1, s0);
170 		CPYFPN(&fe->fe_f2, &x2);
171 		r = fpu_mul(fe);
172 		CPYFPN(&fe->fe_f1, r);
173 
174 		/*
175 		 * for sinh(),  s1 := s0 * x^2 / (2n+1)2n
176 		 * for cosh(),  s1 := s0 * x^2 / 2n(2n-1)
177 		 */
178 		k = f * (f + 1);
179 		fpu_explode(fe, &fe->fe_f2, FTYPE_LNG, &k);
180 		s1 = fpu_div(fe);
181 
182 		/* break if s1 is enough small */
183 		if (ISZERO(s1))
184 			break;
185 		if (res.fp_exp - s1->fp_exp >= EXT_FRACBITS)
186 			break;
187 
188 		/* s0 := s1 for next loop */
189 		CPYFPN(s0, s1);
190 
191 		/* res += s1 */
192 		CPYFPN(&fe->fe_f2, s1);
193 		CPYFPN(&fe->fe_f1, &res);
194 		r = fpu_add(fe);
195 		CPYFPN(&res, r);
196 
197 		f += 2;
198 		sign ^= 1;
199 	}
200 
201 	CPYFPN(&fe->fe_f2, &res);
202 	return &fe->fe_f2;
203 }
204 
205 struct fpn *
206 fpu_cosh(struct fpemu *fe)
207 {
208 	struct fpn s0;
209 	struct fpn *r;
210 
211 	if (ISNAN(&fe->fe_f2))
212 		return &fe->fe_f2;
213 
214 	if (ISINF(&fe->fe_f2)) {
215 		fe->fe_f2.fp_sign = 0;
216 		return &fe->fe_f2;
217 	}
218 
219 	fpu_const(&s0, FPU_CONST_1);
220 	r = __fpu_sinhcosh_taylor(fe, &s0, 1);
221 
222 	return r;
223 }
224 
225 struct fpn *
226 fpu_sinh(struct fpemu *fe)
227 {
228 	struct fpn s0;
229 	struct fpn *r;
230 
231 	if (ISNAN(&fe->fe_f2))
232 		return &fe->fe_f2;
233 	if (ISINF(&fe->fe_f2))
234 		return &fe->fe_f2;
235 
236 	/* if x is +0/-0, return +0/-0 */
237 	if (ISZERO(&fe->fe_f2))
238 		return &fe->fe_f2;
239 
240 	CPYFPN(&s0, &fe->fe_f2);
241 	r = __fpu_sinhcosh_taylor(fe, &s0, 2);
242 
243 	return r;
244 }
245 
246 struct fpn *
247 fpu_tanh(struct fpemu *fe)
248 {
249 	struct fpn x;
250 	struct fpn s;
251 	struct fpn *r;
252 	int sign;
253 
254 	if (ISNAN(&fe->fe_f2))
255 		return &fe->fe_f2;
256 
257 	/* if x is +0/-0, return +0/-0 */
258 	if (ISZERO(&fe->fe_f2))
259 		return &fe->fe_f2;
260 
261 	if (ISINF(&fe->fe_f2)) {
262 		sign = fe->fe_f2.fp_sign;
263 		fpu_const(&fe->fe_f2, FPU_CONST_1);
264 		fe->fe_f2.fp_sign = sign;
265 		return &fe->fe_f2;
266 	}
267 
268 	CPYFPN(&x, &fe->fe_f2);
269 
270 	/* sinh(x) */
271 	CPYFPN(&fe->fe_f2, &x);
272 	r = fpu_sinh(fe);
273 	CPYFPN(&s, r);
274 
275 	/* cosh(x) */
276 	CPYFPN(&fe->fe_f2, &x);
277 	r = fpu_cosh(fe);
278 	CPYFPN(&fe->fe_f2, r);
279 
280 	CPYFPN(&fe->fe_f1, &s);
281 	r = fpu_div(fe);
282 
283 	return r;
284 }
285