| /* | |
| 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 whether 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); | |
| 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; | |
| } | |