Home | History | Annotate | Line # | Download | only in fpe
fpu_trig.c revision 1.10
      1 /*	$NetBSD: fpu_trig.c,v 1.10 2013/04/18 13:40:25 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_trig.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_trig.c,v 1.10 2013/04/18 13:40:25 isaki Exp $");
     61 
     62 #include "fpu_emulate.h"
     63 
     64 static inline struct fpn *fpu_cos_halfpi(struct fpemu *);
     65 static inline struct fpn *fpu_sin_halfpi(struct fpemu *);
     66 
     67 struct fpn *
     68 fpu_acos(struct fpemu *fe)
     69 {
     70 	/* stub */
     71 	return &fe->fe_f2;
     72 }
     73 
     74 struct fpn *
     75 fpu_asin(struct fpemu *fe)
     76 {
     77 	/* stub */
     78 	return &fe->fe_f2;
     79 }
     80 
     81 struct fpn *
     82 fpu_atan(struct fpemu *fe)
     83 {
     84 	/* stub */
     85 	return &fe->fe_f2;
     86 }
     87 
     88 /*
     89  * taylor expansion used by sin(), cos(), sinh(), cosh().
     90  * hyperb is for sinh(), cosh().
     91  */
     92 struct fpn *
     93 fpu_sincos_taylor(struct fpemu *fe, struct fpn *s0, uint32_t f, int hyperb)
     94 {
     95 	struct fpn res;
     96 	struct fpn x2;
     97 	struct fpn *s1;
     98 	struct fpn *r;
     99 	int sign;
    100 	uint32_t k;
    101 
    102 	/* x2 := x * x */
    103 	CPYFPN(&fe->fe_f1, &fe->fe_f2);
    104 	r = fpu_mul(fe);
    105 	CPYFPN(&x2, r);
    106 
    107 	/* res := s0 */
    108 	CPYFPN(&res, s0);
    109 
    110 	sign = 1;	/* sign := (-1)^n */
    111 
    112 	for (;;) {
    113 		/* (f1 :=) s0 * x^2 */
    114 		CPYFPN(&fe->fe_f1, s0);
    115 		CPYFPN(&fe->fe_f2, &x2);
    116 		r = fpu_mul(fe);
    117 		CPYFPN(&fe->fe_f1, r);
    118 
    119 		/*
    120 		 * for sin(),  s1 := s0 * x^2 / (2n+1)2n
    121 		 * for cos(),  s1 := s0 * x^2 / 2n(2n-1)
    122 		 */
    123 		k = f * (f + 1);
    124 		fpu_explode(fe, &fe->fe_f2, FTYPE_LNG, &k);
    125 		s1 = fpu_div(fe);
    126 
    127 		/* break if s1 is enough small */
    128 		if (ISZERO(s1))
    129 			break;
    130 		if (res.fp_exp - s1->fp_exp >= FP_NMANT)
    131 			break;
    132 
    133 		/* s0 := s1 for next loop */
    134 		CPYFPN(s0, s1);
    135 
    136 		CPYFPN(&fe->fe_f2, s1);
    137 		if (!hyperb) {
    138 			/* (-1)^n */
    139 			fe->fe_f2.fp_sign = sign;
    140 		}
    141 
    142 		/* res += s1 */
    143 		CPYFPN(&fe->fe_f1, &res);
    144 		r = fpu_add(fe);
    145 		CPYFPN(&res, r);
    146 
    147 		f += 2;
    148 		sign ^= 1;
    149 	}
    150 
    151 	CPYFPN(&fe->fe_f2, &res);
    152 	return &fe->fe_f2;
    153 }
    154 
    155 /*
    156  *           inf   (-1)^n    2n
    157  * cos(x) = \sum { ------ * x   }
    158  *           n=0     2n!
    159  *
    160  *              x^2   x^4   x^6
    161  *        = 1 - --- + --- - --- + ...
    162  *               2!    4!    6!
    163  *
    164  *        = s0 - s1 + s2  - s3  + ...
    165  *
    166  *               x*x           x*x           x*x
    167  * s0 = 1,  s1 = ---*s0,  s2 = ---*s1,  s3 = ---*s2, ...
    168  *               1*2           3*4           5*6
    169  *
    170  * here 0 <= x < pi/2
    171  */
    172 static inline struct fpn *
    173 fpu_cos_halfpi(struct fpemu *fe)
    174 {
    175 	struct fpn s0;
    176 
    177 	/* s0 := 1 */
    178 	fpu_const(&s0, FPU_CONST_1);
    179 
    180 	return fpu_sincos_taylor(fe, &s0, 1, 0);
    181 }
    182 
    183 /*
    184  *          inf    (-1)^n     2n+1
    185  * sin(x) = \sum { ------- * x     }
    186  *          n=0    (2n+1)!
    187  *
    188  *              x^3   x^5   x^7
    189  *        = x - --- + --- - --- + ...
    190  *               3!    5!    7!
    191  *
    192  *        = s0 - s1 + s2  - s3  + ...
    193  *
    194  *               x*x           x*x           x*x
    195  * s0 = x,  s1 = ---*s0,  s2 = ---*s1,  s3 = ---*s2, ...
    196  *               2*3           4*5           6*7
    197  *
    198  * here 0 <= x < pi/2
    199  */
    200 static inline struct fpn *
    201 fpu_sin_halfpi(struct fpemu *fe)
    202 {
    203 	struct fpn s0;
    204 
    205 	/* s0 := x */
    206 	CPYFPN(&s0, &fe->fe_f2);
    207 
    208 	return fpu_sincos_taylor(fe, &s0, 2, 0);
    209 }
    210 
    211 /*
    212  * cos(x):
    213  *
    214  *	if (x < 0) {
    215  *		x = abs(x);
    216  *	}
    217  *	if (x > 2*pi) {
    218  *		x %= 2*pi;
    219  *	}
    220  *	if (x > pi) {
    221  *		x -= pi;
    222  *		sign inverse;
    223  *	}
    224  *	if (x > pi/2) {
    225  *		y = sin(x - pi/2);
    226  *		sign inverse;
    227  *	} else {
    228  *		y = cos(x);
    229  *	}
    230  *	if (sign) {
    231  *		y = -y;
    232  *	}
    233  */
    234 struct fpn *
    235 fpu_cos(struct fpemu *fe)
    236 {
    237 	struct fpn x;
    238 	struct fpn p;
    239 	struct fpn *r;
    240 	int sign;
    241 
    242 	if (ISNAN(&fe->fe_f2))
    243 		return &fe->fe_f2;
    244 	if (ISINF(&fe->fe_f2))
    245 		return fpu_newnan(fe);
    246 
    247 	CPYFPN(&x, &fe->fe_f2);
    248 
    249 	/* x = abs(input) */
    250 	x.fp_sign = 0;
    251 	sign = 0;
    252 
    253 	/* p <- 2*pi */
    254 	fpu_const(&p, FPU_CONST_PI);
    255 	p.fp_exp++;
    256 
    257 	/*
    258 	 * if (x > 2*pi*N)
    259 	 *  cos(x) is cos(x - 2*pi*N)
    260 	 */
    261 	CPYFPN(&fe->fe_f1, &x);
    262 	CPYFPN(&fe->fe_f2, &p);
    263 	r = fpu_cmp(fe);
    264 	if (r->fp_sign == 0) {
    265 		CPYFPN(&fe->fe_f1, &x);
    266 		CPYFPN(&fe->fe_f2, &p);
    267 		r = fpu_mod(fe);
    268 		CPYFPN(&x, r);
    269 	}
    270 
    271 	/* p <- pi */
    272 	p.fp_exp--;
    273 
    274 	/*
    275 	 * if (x > pi)
    276 	 *  cos(x) is -cos(x - pi)
    277 	 */
    278 	CPYFPN(&fe->fe_f1, &x);
    279 	CPYFPN(&fe->fe_f2, &p);
    280 	fe->fe_f2.fp_sign = 1;
    281 	r = fpu_add(fe);
    282 	if (r->fp_sign == 0) {
    283 		CPYFPN(&x, r);
    284 		sign ^= 1;
    285 	}
    286 
    287 	/* p <- pi/2 */
    288 	p.fp_exp--;
    289 
    290 	/*
    291 	 * if (x > pi/2)
    292 	 *  cos(x) is -sin(x - pi/2)
    293 	 * else
    294 	 *  cos(x)
    295 	 */
    296 	CPYFPN(&fe->fe_f1, &x);
    297 	CPYFPN(&fe->fe_f2, &p);
    298 	fe->fe_f2.fp_sign = 1;
    299 	r = fpu_add(fe);
    300 	if (r->fp_sign == 0) {
    301 		CPYFPN(&fe->fe_f2, r);
    302 		r = fpu_sin_halfpi(fe);
    303 		sign ^= 1;
    304 	} else {
    305 		CPYFPN(&fe->fe_f2, &x);
    306 		r = fpu_cos_halfpi(fe);
    307 	}
    308 
    309 	CPYFPN(&fe->fe_f2, r);
    310 	fe->fe_f2.fp_sign = sign;
    311 
    312 	return &fe->fe_f2;
    313 }
    314 
    315 /*
    316  * sin(x):
    317  *
    318  *	if (x < 0) {
    319  *		x = abs(x);
    320  *		sign = 1;
    321  *	}
    322  *	if (x > 2*pi) {
    323  *		x %= 2*pi;
    324  *	}
    325  *	if (x > pi) {
    326  *		x -= pi;
    327  *		sign inverse;
    328  *	}
    329  *	if (x > pi/2) {
    330  *		y = cos(x - pi/2);
    331  *	} else {
    332  *		y = sin(x);
    333  *	}
    334  *	if (sign) {
    335  *		y = -y;
    336  *	}
    337  */
    338 struct fpn *
    339 fpu_sin(struct fpemu *fe)
    340 {
    341 	struct fpn x;
    342 	struct fpn p;
    343 	struct fpn *r;
    344 	int sign;
    345 
    346 	if (ISNAN(&fe->fe_f2))
    347 		return &fe->fe_f2;
    348 	if (ISINF(&fe->fe_f2))
    349 		return fpu_newnan(fe);
    350 
    351 	CPYFPN(&x, &fe->fe_f2);
    352 
    353 	/* x = abs(input) */
    354 	sign = x.fp_sign;
    355 	x.fp_sign = 0;
    356 
    357 	/* p <- 2*pi */
    358 	fpu_const(&p, FPU_CONST_PI);
    359 	p.fp_exp++;
    360 
    361 	/*
    362 	 * if (x > 2*pi*N)
    363 	 *  sin(x) is sin(x - 2*pi*N)
    364 	 */
    365 	CPYFPN(&fe->fe_f1, &x);
    366 	CPYFPN(&fe->fe_f2, &p);
    367 	r = fpu_cmp(fe);
    368 	if (r->fp_sign == 0) {
    369 		CPYFPN(&fe->fe_f1, &x);
    370 		CPYFPN(&fe->fe_f2, &p);
    371 		r = fpu_mod(fe);
    372 		CPYFPN(&x, r);
    373 	}
    374 
    375 	/* p <- pi */
    376 	p.fp_exp--;
    377 
    378 	/*
    379 	 * if (x > pi)
    380 	 *  sin(x) is -sin(x - pi)
    381 	 */
    382 	CPYFPN(&fe->fe_f1, &x);
    383 	CPYFPN(&fe->fe_f2, &p);
    384 	fe->fe_f2.fp_sign = 1;
    385 	r = fpu_add(fe);
    386 	if (r->fp_sign == 0) {
    387 		CPYFPN(&x, r);
    388 		sign ^= 1;
    389 	}
    390 
    391 	/* p <- pi/2 */
    392 	p.fp_exp--;
    393 
    394 	/*
    395 	 * if (x > pi/2)
    396 	 *  sin(x) is cos(x - pi/2)
    397 	 * else
    398 	 *  sin(x)
    399 	 */
    400 	CPYFPN(&fe->fe_f1, &x);
    401 	CPYFPN(&fe->fe_f2, &p);
    402 	fe->fe_f2.fp_sign = 1;
    403 	r = fpu_add(fe);
    404 	if (r->fp_sign == 0) {
    405 		CPYFPN(&fe->fe_f2, r);
    406 		r = fpu_cos_halfpi(fe);
    407 	} else {
    408 		CPYFPN(&fe->fe_f2, &x);
    409 		r = fpu_sin_halfpi(fe);
    410 	}
    411 
    412 	CPYFPN(&fe->fe_f2, r);
    413 	fe->fe_f2.fp_sign = sign;
    414 
    415 	return &fe->fe_f2;
    416 }
    417 
    418 /*
    419  * tan(x) = sin(x) / cos(x)
    420  */
    421 struct fpn *
    422 fpu_tan(struct fpemu *fe)
    423 {
    424 	struct fpn x;
    425 	struct fpn s;
    426 	struct fpn *r;
    427 
    428 	if (ISNAN(&fe->fe_f2))
    429 		return &fe->fe_f2;
    430 	if (ISINF(&fe->fe_f2))
    431 		return fpu_newnan(fe);
    432 
    433 	CPYFPN(&x, &fe->fe_f2);
    434 
    435 	/* sin(x) */
    436 	CPYFPN(&fe->fe_f2, &x);
    437 	r = fpu_sin(fe);
    438 	CPYFPN(&s, r);
    439 
    440 	/* cos(x) */
    441 	CPYFPN(&fe->fe_f2, &x);
    442 	r = fpu_cos(fe);
    443 	CPYFPN(&fe->fe_f2, r);
    444 
    445 	CPYFPN(&fe->fe_f1, &s);
    446 	r = fpu_div(fe);
    447 
    448 	CPYFPN(&fe->fe_f2, r);
    449 
    450 	return &fe->fe_f2;
    451 }
    452 
    453 struct fpn *
    454 fpu_sincos(struct fpemu *fe, int regc)
    455 {
    456 	struct fpn x;
    457 	struct fpn *r;
    458 
    459 	CPYFPN(&x, &fe->fe_f2);
    460 
    461 	/* cos(x) */
    462 	r = fpu_cos(fe);
    463 	fpu_implode(fe, r, FTYPE_EXT, &fe->fe_fpframe->fpf_regs[regc]);
    464 
    465 	/* sin(x) */
    466 	CPYFPN(&fe->fe_f2, &x);
    467 	r = fpu_sin(fe);
    468 	return r;
    469 }
    470