| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  | 
 | 3 |   fp_trig.c: floating-point math routines for the Linux-m68k | 
 | 4 |   floating point emulator. | 
 | 5 |  | 
 | 6 |   Copyright (c) 1998-1999 David Huggins-Daines / Roman Zippel. | 
 | 7 |  | 
 | 8 |   I hereby give permission, free of charge, to copy, modify, and | 
 | 9 |   redistribute this software, in source or binary form, provided that | 
 | 10 |   the above copyright notice and the following disclaimer are included | 
 | 11 |   in all such copies. | 
 | 12 |  | 
 | 13 |   THIS SOFTWARE IS PROVIDED "AS IS", WITH ABSOLUTELY NO WARRANTY, REAL | 
 | 14 |   OR IMPLIED. | 
 | 15 |  | 
 | 16 | */ | 
 | 17 |  | 
 | 18 | #include "fp_emu.h" | 
 | 19 |  | 
 | 20 | static const struct fp_ext fp_one = | 
 | 21 | { | 
 | 22 | 	.exp = 0x3fff, | 
 | 23 | }; | 
 | 24 |  | 
 | 25 | extern struct fp_ext *fp_fadd(struct fp_ext *dest, const struct fp_ext *src); | 
 | 26 | extern struct fp_ext *fp_fdiv(struct fp_ext *dest, const struct fp_ext *src); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 27 |  | 
 | 28 | struct fp_ext * | 
 | 29 | fp_fsqrt(struct fp_ext *dest, struct fp_ext *src) | 
 | 30 | { | 
 | 31 | 	struct fp_ext tmp, src2; | 
 | 32 | 	int i, exp; | 
 | 33 |  | 
 | 34 | 	dprint(PINSTR, "fsqrt\n"); | 
 | 35 |  | 
 | 36 | 	fp_monadic_check(dest, src); | 
 | 37 |  | 
 | 38 | 	if (IS_ZERO(dest)) | 
 | 39 | 		return dest; | 
 | 40 |  | 
 | 41 | 	if (dest->sign) { | 
 | 42 | 		fp_set_nan(dest); | 
 | 43 | 		return dest; | 
 | 44 | 	} | 
 | 45 | 	if (IS_INF(dest)) | 
 | 46 | 		return dest; | 
 | 47 |  | 
 | 48 | 	/* | 
 | 49 | 	 *		 sqrt(m) * 2^(p)	, if e = 2*p | 
 | 50 | 	 * sqrt(m*2^e) = | 
 | 51 | 	 *		 sqrt(2*m) * 2^(p)	, if e = 2*p + 1 | 
 | 52 | 	 * | 
 | 53 | 	 * So we use the last bit of the exponent to decide wether to | 
 | 54 | 	 * use the m or 2*m. | 
 | 55 | 	 * | 
 | 56 | 	 * Since only the fractional part of the mantissa is stored and | 
 | 57 | 	 * the integer part is assumed to be one, we place a 1 or 2 into | 
 | 58 | 	 * the fixed point representation. | 
 | 59 | 	 */ | 
 | 60 | 	exp = dest->exp; | 
 | 61 | 	dest->exp = 0x3FFF; | 
 | 62 | 	if (!(exp & 1))		/* lowest bit of exponent is set */ | 
 | 63 | 		dest->exp++; | 
 | 64 | 	fp_copy_ext(&src2, dest); | 
 | 65 |  | 
 | 66 | 	/* | 
| Simon Arlott | 0c79cf6 | 2007-10-20 01:20:32 +0200 | [diff] [blame] | 67 | 	 * The taylor row around a for sqrt(x) is: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 68 | 	 *	sqrt(x) = sqrt(a) + 1/(2*sqrt(a))*(x-a) + R | 
 | 69 | 	 * With a=1 this gives: | 
 | 70 | 	 *	sqrt(x) = 1 + 1/2*(x-1) | 
 | 71 | 	 *		= 1/2*(1+x) | 
 | 72 | 	 */ | 
 | 73 | 	fp_fadd(dest, &fp_one); | 
 | 74 | 	dest->exp--;		/* * 1/2 */ | 
 | 75 |  | 
 | 76 | 	/* | 
 | 77 | 	 * We now apply the newton rule to the function | 
 | 78 | 	 *	f(x) := x^2 - r | 
 | 79 | 	 * which has a null point on x = sqrt(r). | 
 | 80 | 	 * | 
 | 81 | 	 * It gives: | 
 | 82 | 	 *	x' := x - f(x)/f'(x) | 
 | 83 | 	 *	    = x - (x^2 -r)/(2*x) | 
 | 84 | 	 *	    = x - (x - r/x)/2 | 
 | 85 | 	 *          = (2*x - x + r/x)/2 | 
 | 86 | 	 *	    = (x + r/x)/2 | 
 | 87 | 	 */ | 
 | 88 | 	for (i = 0; i < 9; i++) { | 
 | 89 | 		fp_copy_ext(&tmp, &src2); | 
 | 90 |  | 
 | 91 | 		fp_fdiv(&tmp, dest); | 
 | 92 | 		fp_fadd(dest, &tmp); | 
 | 93 | 		dest->exp--; | 
 | 94 | 	} | 
 | 95 |  | 
 | 96 | 	dest->exp += (exp - 0x3FFF) / 2; | 
 | 97 |  | 
 | 98 | 	return dest; | 
 | 99 | } | 
 | 100 |  | 
 | 101 | struct fp_ext * | 
 | 102 | fp_fetoxm1(struct fp_ext *dest, struct fp_ext *src) | 
 | 103 | { | 
 | 104 | 	uprint("fetoxm1\n"); | 
 | 105 |  | 
 | 106 | 	fp_monadic_check(dest, src); | 
 | 107 |  | 
 | 108 | 	if (IS_ZERO(dest)) | 
 | 109 | 		return dest; | 
 | 110 |  | 
 | 111 | 	return dest; | 
 | 112 | } | 
 | 113 |  | 
 | 114 | struct fp_ext * | 
 | 115 | fp_fetox(struct fp_ext *dest, struct fp_ext *src) | 
 | 116 | { | 
 | 117 | 	uprint("fetox\n"); | 
 | 118 |  | 
 | 119 | 	fp_monadic_check(dest, src); | 
 | 120 |  | 
 | 121 | 	return dest; | 
 | 122 | } | 
 | 123 |  | 
 | 124 | struct fp_ext * | 
 | 125 | fp_ftwotox(struct fp_ext *dest, struct fp_ext *src) | 
 | 126 | { | 
 | 127 | 	uprint("ftwotox\n"); | 
 | 128 |  | 
 | 129 | 	fp_monadic_check(dest, src); | 
 | 130 |  | 
 | 131 | 	return dest; | 
 | 132 | } | 
 | 133 |  | 
 | 134 | struct fp_ext * | 
 | 135 | fp_ftentox(struct fp_ext *dest, struct fp_ext *src) | 
 | 136 | { | 
 | 137 | 	uprint("ftentox\n"); | 
 | 138 |  | 
 | 139 | 	fp_monadic_check(dest, src); | 
 | 140 |  | 
 | 141 | 	return dest; | 
 | 142 | } | 
 | 143 |  | 
 | 144 | struct fp_ext * | 
 | 145 | fp_flogn(struct fp_ext *dest, struct fp_ext *src) | 
 | 146 | { | 
 | 147 | 	uprint("flogn\n"); | 
 | 148 |  | 
 | 149 | 	fp_monadic_check(dest, src); | 
 | 150 |  | 
 | 151 | 	return dest; | 
 | 152 | } | 
 | 153 |  | 
 | 154 | struct fp_ext * | 
 | 155 | fp_flognp1(struct fp_ext *dest, struct fp_ext *src) | 
 | 156 | { | 
 | 157 | 	uprint("flognp1\n"); | 
 | 158 |  | 
 | 159 | 	fp_monadic_check(dest, src); | 
 | 160 |  | 
 | 161 | 	return dest; | 
 | 162 | } | 
 | 163 |  | 
 | 164 | struct fp_ext * | 
 | 165 | fp_flog10(struct fp_ext *dest, struct fp_ext *src) | 
 | 166 | { | 
 | 167 | 	uprint("flog10\n"); | 
 | 168 |  | 
 | 169 | 	fp_monadic_check(dest, src); | 
 | 170 |  | 
 | 171 | 	return dest; | 
 | 172 | } | 
 | 173 |  | 
 | 174 | struct fp_ext * | 
 | 175 | fp_flog2(struct fp_ext *dest, struct fp_ext *src) | 
 | 176 | { | 
 | 177 | 	uprint("flog2\n"); | 
 | 178 |  | 
 | 179 | 	fp_monadic_check(dest, src); | 
 | 180 |  | 
 | 181 | 	return dest; | 
 | 182 | } | 
 | 183 |  | 
 | 184 | struct fp_ext * | 
 | 185 | fp_fgetexp(struct fp_ext *dest, struct fp_ext *src) | 
 | 186 | { | 
 | 187 | 	dprint(PINSTR, "fgetexp\n"); | 
 | 188 |  | 
 | 189 | 	fp_monadic_check(dest, src); | 
 | 190 |  | 
 | 191 | 	if (IS_INF(dest)) { | 
 | 192 | 		fp_set_nan(dest); | 
 | 193 | 		return dest; | 
 | 194 | 	} | 
 | 195 | 	if (IS_ZERO(dest)) | 
 | 196 | 		return dest; | 
 | 197 |  | 
 | 198 | 	fp_conv_long2ext(dest, (int)dest->exp - 0x3FFF); | 
 | 199 |  | 
 | 200 | 	fp_normalize_ext(dest); | 
 | 201 |  | 
 | 202 | 	return dest; | 
 | 203 | } | 
 | 204 |  | 
 | 205 | struct fp_ext * | 
 | 206 | fp_fgetman(struct fp_ext *dest, struct fp_ext *src) | 
 | 207 | { | 
 | 208 | 	dprint(PINSTR, "fgetman\n"); | 
 | 209 |  | 
 | 210 | 	fp_monadic_check(dest, src); | 
 | 211 |  | 
 | 212 | 	if (IS_ZERO(dest)) | 
 | 213 | 		return dest; | 
 | 214 |  | 
 | 215 | 	if (IS_INF(dest)) | 
 | 216 | 		return dest; | 
 | 217 |  | 
 | 218 | 	dest->exp = 0x3FFF; | 
 | 219 |  | 
 | 220 | 	return dest; | 
 | 221 | } | 
 | 222 |  |