223 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			223 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
| 
 | |
|   fp_trig.c: floating-point math routines for the Linux-m68k
 | |
|   floating point emulator.
 | |
| 
 | |
|   Copyright (c) 1998-1999 David Huggins-Daines / Roman Zippel.
 | |
| 
 | |
|   I hereby give permission, free of charge, to copy, modify, and
 | |
|   redistribute this software, in source or binary form, provided that
 | |
|   the above copyright notice and the following disclaimer are included
 | |
|   in all such copies.
 | |
| 
 | |
|   THIS SOFTWARE IS PROVIDED "AS IS", WITH ABSOLUTELY NO WARRANTY, REAL
 | |
|   OR IMPLIED.
 | |
| 
 | |
| */
 | |
| 
 | |
| #include "fp_emu.h"
 | |
| 
 | |
| static const struct fp_ext fp_one =
 | |
| {
 | |
| 	.exp = 0x3fff,
 | |
| };
 | |
| 
 | |
| extern struct fp_ext *fp_fadd(struct fp_ext *dest, const struct fp_ext *src);
 | |
| extern struct fp_ext *fp_fdiv(struct fp_ext *dest, const struct fp_ext *src);
 | |
| 
 | |
| struct fp_ext *
 | |
| fp_fsqrt(struct fp_ext *dest, struct fp_ext *src)
 | |
| {
 | |
| 	struct fp_ext tmp, src2;
 | |
| 	int i, exp;
 | |
| 
 | |
| 	dprint(PINSTR, "fsqrt\n");
 | |
| 
 | |
| 	fp_monadic_check(dest, src);
 | |
| 
 | |
| 	if (IS_ZERO(dest))
 | |
| 		return dest;
 | |
| 
 | |
| 	if (dest->sign) {
 | |
| 		fp_set_nan(dest);
 | |
| 		return dest;
 | |
| 	}
 | |
| 	if (IS_INF(dest))
 | |
| 		return dest;
 | |
| 
 | |
| 	/*
 | |
| 	 *		 sqrt(m) * 2^(p)	, if e = 2*p
 | |
| 	 * sqrt(m*2^e) =
 | |
| 	 *		 sqrt(2*m) * 2^(p)	, if e = 2*p + 1
 | |
| 	 *
 | |
| 	 * So we use the last bit of the exponent to decide wether to
 | |
| 	 * use the m or 2*m.
 | |
| 	 *
 | |
| 	 * Since only the fractional part of the mantissa is stored and
 | |
| 	 * the integer part is assumed to be one, we place a 1 or 2 into
 | |
| 	 * the fixed point representation.
 | |
| 	 */
 | |
| 	exp = dest->exp;
 | |
| 	dest->exp = 0x3FFF;
 | |
| 	if (!(exp & 1))		/* lowest bit of exponent is set */
 | |
| 		dest->exp++;
 | |
| 	fp_copy_ext(&src2, dest);
 | |
| 
 | |
| 	/*
 | |
| 	 * The taylor row around a for sqrt(x) is:
 | |
| 	 *	sqrt(x) = sqrt(a) + 1/(2*sqrt(a))*(x-a) + R
 | |
| 	 * With a=1 this gives:
 | |
| 	 *	sqrt(x) = 1 + 1/2*(x-1)
 | |
| 	 *		= 1/2*(1+x)
 | |
| 	 */
 | |
| 	fp_fadd(dest, &fp_one);
 | |
| 	dest->exp--;		/* * 1/2 */
 | |
| 
 | |
| 	/*
 | |
| 	 * We now apply the newton rule to the function
 | |
| 	 *	f(x) := x^2 - r
 | |
| 	 * which has a null point on x = sqrt(r).
 | |
| 	 *
 | |
| 	 * It gives:
 | |
| 	 *	x' := x - f(x)/f'(x)
 | |
| 	 *	    = x - (x^2 -r)/(2*x)
 | |
| 	 *	    = x - (x - r/x)/2
 | |
| 	 *          = (2*x - x + r/x)/2
 | |
| 	 *	    = (x + r/x)/2
 | |
| 	 */
 | |
| 	for (i = 0; i < 9; i++) {
 | |
| 		fp_copy_ext(&tmp, &src2);
 | |
| 
 | |
| 		fp_fdiv(&tmp, dest);
 | |
| 		fp_fadd(dest, &tmp);
 | |
| 		dest->exp--;
 | |
| 	}
 | |
| 
 | |
| 	dest->exp += (exp - 0x3FFF) / 2;
 | |
| 
 | |
| 	return dest;
 | |
| }
 | |
| 
 | |
| struct fp_ext *
 | |
| fp_fetoxm1(struct fp_ext *dest, struct fp_ext *src)
 | |
| {
 | |
| 	uprint("fetoxm1\n");
 | |
| 
 | |
| 	fp_monadic_check(dest, src);
 | |
| 
 | |
| 	if (IS_ZERO(dest))
 | |
| 		return dest;
 | |
| 
 | |
| 	return dest;
 | |
| }
 | |
| 
 | |
| struct fp_ext *
 | |
| fp_fetox(struct fp_ext *dest, struct fp_ext *src)
 | |
| {
 | |
| 	uprint("fetox\n");
 | |
| 
 | |
| 	fp_monadic_check(dest, src);
 | |
| 
 | |
| 	return dest;
 | |
| }
 | |
| 
 | |
| struct fp_ext *
 | |
| fp_ftwotox(struct fp_ext *dest, struct fp_ext *src)
 | |
| {
 | |
| 	uprint("ftwotox\n");
 | |
| 
 | |
| 	fp_monadic_check(dest, src);
 | |
| 
 | |
| 	return dest;
 | |
| }
 | |
| 
 | |
| struct fp_ext *
 | |
| fp_ftentox(struct fp_ext *dest, struct fp_ext *src)
 | |
| {
 | |
| 	uprint("ftentox\n");
 | |
| 
 | |
| 	fp_monadic_check(dest, src);
 | |
| 
 | |
| 	return dest;
 | |
| }
 | |
| 
 | |
| struct fp_ext *
 | |
| fp_flogn(struct fp_ext *dest, struct fp_ext *src)
 | |
| {
 | |
| 	uprint("flogn\n");
 | |
| 
 | |
| 	fp_monadic_check(dest, src);
 | |
| 
 | |
| 	return dest;
 | |
| }
 | |
| 
 | |
| struct fp_ext *
 | |
| fp_flognp1(struct fp_ext *dest, struct fp_ext *src)
 | |
| {
 | |
| 	uprint("flognp1\n");
 | |
| 
 | |
| 	fp_monadic_check(dest, src);
 | |
| 
 | |
| 	return dest;
 | |
| }
 | |
| 
 | |
| struct fp_ext *
 | |
| fp_flog10(struct fp_ext *dest, struct fp_ext *src)
 | |
| {
 | |
| 	uprint("flog10\n");
 | |
| 
 | |
| 	fp_monadic_check(dest, src);
 | |
| 
 | |
| 	return dest;
 | |
| }
 | |
| 
 | |
| struct fp_ext *
 | |
| fp_flog2(struct fp_ext *dest, struct fp_ext *src)
 | |
| {
 | |
| 	uprint("flog2\n");
 | |
| 
 | |
| 	fp_monadic_check(dest, src);
 | |
| 
 | |
| 	return dest;
 | |
| }
 | |
| 
 | |
| struct fp_ext *
 | |
| fp_fgetexp(struct fp_ext *dest, struct fp_ext *src)
 | |
| {
 | |
| 	dprint(PINSTR, "fgetexp\n");
 | |
| 
 | |
| 	fp_monadic_check(dest, src);
 | |
| 
 | |
| 	if (IS_INF(dest)) {
 | |
| 		fp_set_nan(dest);
 | |
| 		return dest;
 | |
| 	}
 | |
| 	if (IS_ZERO(dest))
 | |
| 		return dest;
 | |
| 
 | |
| 	fp_conv_long2ext(dest, (int)dest->exp - 0x3FFF);
 | |
| 
 | |
| 	fp_normalize_ext(dest);
 | |
| 
 | |
| 	return dest;
 | |
| }
 | |
| 
 | |
| struct fp_ext *
 | |
| fp_fgetman(struct fp_ext *dest, struct fp_ext *src)
 | |
| {
 | |
| 	dprint(PINSTR, "fgetman\n");
 | |
| 
 | |
| 	fp_monadic_check(dest, src);
 | |
| 
 | |
| 	if (IS_ZERO(dest))
 | |
| 		return dest;
 | |
| 
 | |
| 	if (IS_INF(dest))
 | |
| 		return dest;
 | |
| 
 | |
| 	dest->exp = 0x3FFF;
 | |
| 
 | |
| 	return dest;
 | |
| }
 | |
| 
 |