162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci fp_trig.c: floating-point math routines for the Linux-m68k 462306a36Sopenharmony_ci floating point emulator. 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci Copyright (c) 1998-1999 David Huggins-Daines / Roman Zippel. 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci I hereby give permission, free of charge, to copy, modify, and 962306a36Sopenharmony_ci redistribute this software, in source or binary form, provided that 1062306a36Sopenharmony_ci the above copyright notice and the following disclaimer are included 1162306a36Sopenharmony_ci in all such copies. 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci THIS SOFTWARE IS PROVIDED "AS IS", WITH ABSOLUTELY NO WARRANTY, REAL 1462306a36Sopenharmony_ci OR IMPLIED. 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci*/ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "fp_emu.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic const struct fp_ext fp_one = 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci .exp = 0x3fff, 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ciextern struct fp_ext *fp_fadd(struct fp_ext *dest, const struct fp_ext *src); 2662306a36Sopenharmony_ciextern struct fp_ext *fp_fdiv(struct fp_ext *dest, const struct fp_ext *src); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct fp_ext * 2962306a36Sopenharmony_cifp_fsqrt(struct fp_ext *dest, struct fp_ext *src) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct fp_ext tmp, src2; 3262306a36Sopenharmony_ci int i, exp; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci dprint(PINSTR, "fsqrt\n"); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci fp_monadic_check(dest, src); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (IS_ZERO(dest)) 3962306a36Sopenharmony_ci return dest; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (dest->sign) { 4262306a36Sopenharmony_ci fp_set_nan(dest); 4362306a36Sopenharmony_ci return dest; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci if (IS_INF(dest)) 4662306a36Sopenharmony_ci return dest; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* 4962306a36Sopenharmony_ci * sqrt(m) * 2^(p) , if e = 2*p 5062306a36Sopenharmony_ci * sqrt(m*2^e) = 5162306a36Sopenharmony_ci * sqrt(2*m) * 2^(p) , if e = 2*p + 1 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * So we use the last bit of the exponent to decide whether to 5462306a36Sopenharmony_ci * use the m or 2*m. 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * Since only the fractional part of the mantissa is stored and 5762306a36Sopenharmony_ci * the integer part is assumed to be one, we place a 1 or 2 into 5862306a36Sopenharmony_ci * the fixed point representation. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci exp = dest->exp; 6162306a36Sopenharmony_ci dest->exp = 0x3FFF; 6262306a36Sopenharmony_ci if (!(exp & 1)) /* lowest bit of exponent is set */ 6362306a36Sopenharmony_ci dest->exp++; 6462306a36Sopenharmony_ci fp_copy_ext(&src2, dest); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* 6762306a36Sopenharmony_ci * The taylor row around a for sqrt(x) is: 6862306a36Sopenharmony_ci * sqrt(x) = sqrt(a) + 1/(2*sqrt(a))*(x-a) + R 6962306a36Sopenharmony_ci * With a=1 this gives: 7062306a36Sopenharmony_ci * sqrt(x) = 1 + 1/2*(x-1) 7162306a36Sopenharmony_ci * = 1/2*(1+x) 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci fp_fadd(dest, &fp_one); 7462306a36Sopenharmony_ci dest->exp--; /* * 1/2 */ 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* 7762306a36Sopenharmony_ci * We now apply the newton rule to the function 7862306a36Sopenharmony_ci * f(x) := x^2 - r 7962306a36Sopenharmony_ci * which has a null point on x = sqrt(r). 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * It gives: 8262306a36Sopenharmony_ci * x' := x - f(x)/f'(x) 8362306a36Sopenharmony_ci * = x - (x^2 -r)/(2*x) 8462306a36Sopenharmony_ci * = x - (x - r/x)/2 8562306a36Sopenharmony_ci * = (2*x - x + r/x)/2 8662306a36Sopenharmony_ci * = (x + r/x)/2 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci for (i = 0; i < 9; i++) { 8962306a36Sopenharmony_ci fp_copy_ext(&tmp, &src2); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci fp_fdiv(&tmp, dest); 9262306a36Sopenharmony_ci fp_fadd(dest, &tmp); 9362306a36Sopenharmony_ci dest->exp--; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci dest->exp += (exp - 0x3FFF) / 2; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return dest; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistruct fp_ext * 10262306a36Sopenharmony_cifp_fetoxm1(struct fp_ext *dest, struct fp_ext *src) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci uprint("fetoxm1\n"); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci fp_monadic_check(dest, src); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return dest; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistruct fp_ext * 11262306a36Sopenharmony_cifp_fetox(struct fp_ext *dest, struct fp_ext *src) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci uprint("fetox\n"); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci fp_monadic_check(dest, src); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return dest; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistruct fp_ext * 12262306a36Sopenharmony_cifp_ftwotox(struct fp_ext *dest, struct fp_ext *src) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci uprint("ftwotox\n"); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci fp_monadic_check(dest, src); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return dest; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistruct fp_ext * 13262306a36Sopenharmony_cifp_ftentox(struct fp_ext *dest, struct fp_ext *src) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci uprint("ftentox\n"); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci fp_monadic_check(dest, src); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return dest; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistruct fp_ext * 14262306a36Sopenharmony_cifp_flogn(struct fp_ext *dest, struct fp_ext *src) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci uprint("flogn\n"); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci fp_monadic_check(dest, src); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return dest; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistruct fp_ext * 15262306a36Sopenharmony_cifp_flognp1(struct fp_ext *dest, struct fp_ext *src) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci uprint("flognp1\n"); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci fp_monadic_check(dest, src); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return dest; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistruct fp_ext * 16262306a36Sopenharmony_cifp_flog10(struct fp_ext *dest, struct fp_ext *src) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci uprint("flog10\n"); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci fp_monadic_check(dest, src); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return dest; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistruct fp_ext * 17262306a36Sopenharmony_cifp_flog2(struct fp_ext *dest, struct fp_ext *src) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci uprint("flog2\n"); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci fp_monadic_check(dest, src); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return dest; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistruct fp_ext * 18262306a36Sopenharmony_cifp_fgetexp(struct fp_ext *dest, struct fp_ext *src) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci dprint(PINSTR, "fgetexp\n"); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci fp_monadic_check(dest, src); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (IS_INF(dest)) { 18962306a36Sopenharmony_ci fp_set_nan(dest); 19062306a36Sopenharmony_ci return dest; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci if (IS_ZERO(dest)) 19362306a36Sopenharmony_ci return dest; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci fp_conv_long2ext(dest, (int)dest->exp - 0x3FFF); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci fp_normalize_ext(dest); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci return dest; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistruct fp_ext * 20362306a36Sopenharmony_cifp_fgetman(struct fp_ext *dest, struct fp_ext *src) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci dprint(PINSTR, "fgetman\n"); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci fp_monadic_check(dest, src); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (IS_ZERO(dest)) 21062306a36Sopenharmony_ci return dest; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (IS_INF(dest)) 21362306a36Sopenharmony_ci return dest; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci dest->exp = 0x3FFF; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return dest; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 220