18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci  fp_trig.c: floating-point math routines for the Linux-m68k
48c2ecf20Sopenharmony_ci  floating point emulator.
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci  Copyright (c) 1998-1999 David Huggins-Daines / Roman Zippel.
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci  I hereby give permission, free of charge, to copy, modify, and
98c2ecf20Sopenharmony_ci  redistribute this software, in source or binary form, provided that
108c2ecf20Sopenharmony_ci  the above copyright notice and the following disclaimer are included
118c2ecf20Sopenharmony_ci  in all such copies.
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci  THIS SOFTWARE IS PROVIDED "AS IS", WITH ABSOLUTELY NO WARRANTY, REAL
148c2ecf20Sopenharmony_ci  OR IMPLIED.
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci*/
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "fp_emu.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic const struct fp_ext fp_one =
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	.exp = 0x3fff,
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciextern struct fp_ext *fp_fadd(struct fp_ext *dest, const struct fp_ext *src);
268c2ecf20Sopenharmony_ciextern struct fp_ext *fp_fdiv(struct fp_ext *dest, const struct fp_ext *src);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistruct fp_ext *
298c2ecf20Sopenharmony_cifp_fsqrt(struct fp_ext *dest, struct fp_ext *src)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	struct fp_ext tmp, src2;
328c2ecf20Sopenharmony_ci	int i, exp;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	dprint(PINSTR, "fsqrt\n");
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	fp_monadic_check(dest, src);
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	if (IS_ZERO(dest))
398c2ecf20Sopenharmony_ci		return dest;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	if (dest->sign) {
428c2ecf20Sopenharmony_ci		fp_set_nan(dest);
438c2ecf20Sopenharmony_ci		return dest;
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci	if (IS_INF(dest))
468c2ecf20Sopenharmony_ci		return dest;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	/*
498c2ecf20Sopenharmony_ci	 *		 sqrt(m) * 2^(p)	, if e = 2*p
508c2ecf20Sopenharmony_ci	 * sqrt(m*2^e) =
518c2ecf20Sopenharmony_ci	 *		 sqrt(2*m) * 2^(p)	, if e = 2*p + 1
528c2ecf20Sopenharmony_ci	 *
538c2ecf20Sopenharmony_ci	 * So we use the last bit of the exponent to decide whether to
548c2ecf20Sopenharmony_ci	 * use the m or 2*m.
558c2ecf20Sopenharmony_ci	 *
568c2ecf20Sopenharmony_ci	 * Since only the fractional part of the mantissa is stored and
578c2ecf20Sopenharmony_ci	 * the integer part is assumed to be one, we place a 1 or 2 into
588c2ecf20Sopenharmony_ci	 * the fixed point representation.
598c2ecf20Sopenharmony_ci	 */
608c2ecf20Sopenharmony_ci	exp = dest->exp;
618c2ecf20Sopenharmony_ci	dest->exp = 0x3FFF;
628c2ecf20Sopenharmony_ci	if (!(exp & 1))		/* lowest bit of exponent is set */
638c2ecf20Sopenharmony_ci		dest->exp++;
648c2ecf20Sopenharmony_ci	fp_copy_ext(&src2, dest);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	/*
678c2ecf20Sopenharmony_ci	 * The taylor row around a for sqrt(x) is:
688c2ecf20Sopenharmony_ci	 *	sqrt(x) = sqrt(a) + 1/(2*sqrt(a))*(x-a) + R
698c2ecf20Sopenharmony_ci	 * With a=1 this gives:
708c2ecf20Sopenharmony_ci	 *	sqrt(x) = 1 + 1/2*(x-1)
718c2ecf20Sopenharmony_ci	 *		= 1/2*(1+x)
728c2ecf20Sopenharmony_ci	 */
738c2ecf20Sopenharmony_ci	fp_fadd(dest, &fp_one);
748c2ecf20Sopenharmony_ci	dest->exp--;		/* * 1/2 */
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	/*
778c2ecf20Sopenharmony_ci	 * We now apply the newton rule to the function
788c2ecf20Sopenharmony_ci	 *	f(x) := x^2 - r
798c2ecf20Sopenharmony_ci	 * which has a null point on x = sqrt(r).
808c2ecf20Sopenharmony_ci	 *
818c2ecf20Sopenharmony_ci	 * It gives:
828c2ecf20Sopenharmony_ci	 *	x' := x - f(x)/f'(x)
838c2ecf20Sopenharmony_ci	 *	    = x - (x^2 -r)/(2*x)
848c2ecf20Sopenharmony_ci	 *	    = x - (x - r/x)/2
858c2ecf20Sopenharmony_ci	 *          = (2*x - x + r/x)/2
868c2ecf20Sopenharmony_ci	 *	    = (x + r/x)/2
878c2ecf20Sopenharmony_ci	 */
888c2ecf20Sopenharmony_ci	for (i = 0; i < 9; i++) {
898c2ecf20Sopenharmony_ci		fp_copy_ext(&tmp, &src2);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		fp_fdiv(&tmp, dest);
928c2ecf20Sopenharmony_ci		fp_fadd(dest, &tmp);
938c2ecf20Sopenharmony_ci		dest->exp--;
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	dest->exp += (exp - 0x3FFF) / 2;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return dest;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistruct fp_ext *
1028c2ecf20Sopenharmony_cifp_fetoxm1(struct fp_ext *dest, struct fp_ext *src)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	uprint("fetoxm1\n");
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	fp_monadic_check(dest, src);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	return dest;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistruct fp_ext *
1128c2ecf20Sopenharmony_cifp_fetox(struct fp_ext *dest, struct fp_ext *src)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	uprint("fetox\n");
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	fp_monadic_check(dest, src);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	return dest;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistruct fp_ext *
1228c2ecf20Sopenharmony_cifp_ftwotox(struct fp_ext *dest, struct fp_ext *src)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	uprint("ftwotox\n");
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	fp_monadic_check(dest, src);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return dest;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistruct fp_ext *
1328c2ecf20Sopenharmony_cifp_ftentox(struct fp_ext *dest, struct fp_ext *src)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	uprint("ftentox\n");
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	fp_monadic_check(dest, src);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return dest;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistruct fp_ext *
1428c2ecf20Sopenharmony_cifp_flogn(struct fp_ext *dest, struct fp_ext *src)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	uprint("flogn\n");
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	fp_monadic_check(dest, src);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	return dest;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistruct fp_ext *
1528c2ecf20Sopenharmony_cifp_flognp1(struct fp_ext *dest, struct fp_ext *src)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	uprint("flognp1\n");
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	fp_monadic_check(dest, src);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	return dest;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistruct fp_ext *
1628c2ecf20Sopenharmony_cifp_flog10(struct fp_ext *dest, struct fp_ext *src)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	uprint("flog10\n");
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	fp_monadic_check(dest, src);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	return dest;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistruct fp_ext *
1728c2ecf20Sopenharmony_cifp_flog2(struct fp_ext *dest, struct fp_ext *src)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	uprint("flog2\n");
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	fp_monadic_check(dest, src);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	return dest;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistruct fp_ext *
1828c2ecf20Sopenharmony_cifp_fgetexp(struct fp_ext *dest, struct fp_ext *src)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	dprint(PINSTR, "fgetexp\n");
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	fp_monadic_check(dest, src);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (IS_INF(dest)) {
1898c2ecf20Sopenharmony_ci		fp_set_nan(dest);
1908c2ecf20Sopenharmony_ci		return dest;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci	if (IS_ZERO(dest))
1938c2ecf20Sopenharmony_ci		return dest;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	fp_conv_long2ext(dest, (int)dest->exp - 0x3FFF);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	fp_normalize_ext(dest);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return dest;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistruct fp_ext *
2038c2ecf20Sopenharmony_cifp_fgetman(struct fp_ext *dest, struct fp_ext *src)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	dprint(PINSTR, "fgetman\n");
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	fp_monadic_check(dest, src);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if (IS_ZERO(dest))
2108c2ecf20Sopenharmony_ci		return dest;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if (IS_INF(dest))
2138c2ecf20Sopenharmony_ci		return dest;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	dest->exp = 0x3FFF;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	return dest;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
220