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