18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------+ 38c2ecf20Sopenharmony_ci | poly_sin.c | 48c2ecf20Sopenharmony_ci | | 58c2ecf20Sopenharmony_ci | Computation of an approximation of the sin function and the cosine | 68c2ecf20Sopenharmony_ci | function by a polynomial. | 78c2ecf20Sopenharmony_ci | | 88c2ecf20Sopenharmony_ci | Copyright (C) 1992,1993,1994,1997,1999 | 98c2ecf20Sopenharmony_ci | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | 108c2ecf20Sopenharmony_ci | E-mail billm@melbpc.org.au | 118c2ecf20Sopenharmony_ci | | 128c2ecf20Sopenharmony_ci | | 138c2ecf20Sopenharmony_ci +---------------------------------------------------------------------------*/ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "exception.h" 168c2ecf20Sopenharmony_ci#include "reg_constant.h" 178c2ecf20Sopenharmony_ci#include "fpu_emu.h" 188c2ecf20Sopenharmony_ci#include "fpu_system.h" 198c2ecf20Sopenharmony_ci#include "control_w.h" 208c2ecf20Sopenharmony_ci#include "poly.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define N_COEFF_P 4 238c2ecf20Sopenharmony_ci#define N_COEFF_N 4 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic const unsigned long long pos_terms_l[N_COEFF_P] = { 268c2ecf20Sopenharmony_ci 0xaaaaaaaaaaaaaaabLL, 278c2ecf20Sopenharmony_ci 0x00d00d00d00cf906LL, 288c2ecf20Sopenharmony_ci 0x000006b99159a8bbLL, 298c2ecf20Sopenharmony_ci 0x000000000d7392e6LL 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic const unsigned long long neg_terms_l[N_COEFF_N] = { 338c2ecf20Sopenharmony_ci 0x2222222222222167LL, 348c2ecf20Sopenharmony_ci 0x0002e3bc74aab624LL, 358c2ecf20Sopenharmony_ci 0x0000000b09229062LL, 368c2ecf20Sopenharmony_ci 0x00000000000c7973LL 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define N_COEFF_PH 4 408c2ecf20Sopenharmony_ci#define N_COEFF_NH 4 418c2ecf20Sopenharmony_cistatic const unsigned long long pos_terms_h[N_COEFF_PH] = { 428c2ecf20Sopenharmony_ci 0x0000000000000000LL, 438c2ecf20Sopenharmony_ci 0x05b05b05b05b0406LL, 448c2ecf20Sopenharmony_ci 0x000049f93edd91a9LL, 458c2ecf20Sopenharmony_ci 0x00000000c9c9ed62LL 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic const unsigned long long neg_terms_h[N_COEFF_NH] = { 498c2ecf20Sopenharmony_ci 0xaaaaaaaaaaaaaa98LL, 508c2ecf20Sopenharmony_ci 0x001a01a01a019064LL, 518c2ecf20Sopenharmony_ci 0x0000008f76c68a77LL, 528c2ecf20Sopenharmony_ci 0x0000000000d58f5eLL 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/*--- poly_sine() -----------------------------------------------------------+ 568c2ecf20Sopenharmony_ci | | 578c2ecf20Sopenharmony_ci +---------------------------------------------------------------------------*/ 588c2ecf20Sopenharmony_civoid poly_sine(FPU_REG *st0_ptr) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci int exponent, echange; 618c2ecf20Sopenharmony_ci Xsig accumulator, argSqrd, argTo4; 628c2ecf20Sopenharmony_ci unsigned long fix_up, adj; 638c2ecf20Sopenharmony_ci unsigned long long fixed_arg; 648c2ecf20Sopenharmony_ci FPU_REG result; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci exponent = exponent(st0_ptr); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci accumulator.lsw = accumulator.midw = accumulator.msw = 0; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* Split into two ranges, for arguments below and above 1.0 */ 718c2ecf20Sopenharmony_ci /* The boundary between upper and lower is approx 0.88309101259 */ 728c2ecf20Sopenharmony_ci if ((exponent < -1) 738c2ecf20Sopenharmony_ci || ((exponent == -1) && (st0_ptr->sigh <= 0xe21240aa))) { 748c2ecf20Sopenharmony_ci /* The argument is <= 0.88309101259 */ 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci argSqrd.msw = st0_ptr->sigh; 778c2ecf20Sopenharmony_ci argSqrd.midw = st0_ptr->sigl; 788c2ecf20Sopenharmony_ci argSqrd.lsw = 0; 798c2ecf20Sopenharmony_ci mul64_Xsig(&argSqrd, &significand(st0_ptr)); 808c2ecf20Sopenharmony_ci shr_Xsig(&argSqrd, 2 * (-1 - exponent)); 818c2ecf20Sopenharmony_ci argTo4.msw = argSqrd.msw; 828c2ecf20Sopenharmony_ci argTo4.midw = argSqrd.midw; 838c2ecf20Sopenharmony_ci argTo4.lsw = argSqrd.lsw; 848c2ecf20Sopenharmony_ci mul_Xsig_Xsig(&argTo4, &argTo4); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l, 878c2ecf20Sopenharmony_ci N_COEFF_N - 1); 888c2ecf20Sopenharmony_ci mul_Xsig_Xsig(&accumulator, &argSqrd); 898c2ecf20Sopenharmony_ci negate_Xsig(&accumulator); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l, 928c2ecf20Sopenharmony_ci N_COEFF_P - 1); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci shr_Xsig(&accumulator, 2); /* Divide by four */ 958c2ecf20Sopenharmony_ci accumulator.msw |= 0x80000000; /* Add 1.0 */ 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci mul64_Xsig(&accumulator, &significand(st0_ptr)); 988c2ecf20Sopenharmony_ci mul64_Xsig(&accumulator, &significand(st0_ptr)); 998c2ecf20Sopenharmony_ci mul64_Xsig(&accumulator, &significand(st0_ptr)); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* Divide by four, FPU_REG compatible, etc */ 1028c2ecf20Sopenharmony_ci exponent = 3 * exponent; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* The minimum exponent difference is 3 */ 1058c2ecf20Sopenharmony_ci shr_Xsig(&accumulator, exponent(st0_ptr) - exponent); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci negate_Xsig(&accumulator); 1088c2ecf20Sopenharmony_ci XSIG_LL(accumulator) += significand(st0_ptr); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci echange = round_Xsig(&accumulator); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci setexponentpos(&result, exponent(st0_ptr) + echange); 1138c2ecf20Sopenharmony_ci } else { 1148c2ecf20Sopenharmony_ci /* The argument is > 0.88309101259 */ 1158c2ecf20Sopenharmony_ci /* We use sin(st(0)) = cos(pi/2-st(0)) */ 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci fixed_arg = significand(st0_ptr); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (exponent == 0) { 1208c2ecf20Sopenharmony_ci /* The argument is >= 1.0 */ 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* Put the binary point at the left. */ 1238c2ecf20Sopenharmony_ci fixed_arg <<= 1; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */ 1268c2ecf20Sopenharmony_ci fixed_arg = 0x921fb54442d18469LL - fixed_arg; 1278c2ecf20Sopenharmony_ci /* There is a special case which arises due to rounding, to fix here. */ 1288c2ecf20Sopenharmony_ci if (fixed_arg == 0xffffffffffffffffLL) 1298c2ecf20Sopenharmony_ci fixed_arg = 0; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci XSIG_LL(argSqrd) = fixed_arg; 1328c2ecf20Sopenharmony_ci argSqrd.lsw = 0; 1338c2ecf20Sopenharmony_ci mul64_Xsig(&argSqrd, &fixed_arg); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci XSIG_LL(argTo4) = XSIG_LL(argSqrd); 1368c2ecf20Sopenharmony_ci argTo4.lsw = argSqrd.lsw; 1378c2ecf20Sopenharmony_ci mul_Xsig_Xsig(&argTo4, &argTo4); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h, 1408c2ecf20Sopenharmony_ci N_COEFF_NH - 1); 1418c2ecf20Sopenharmony_ci mul_Xsig_Xsig(&accumulator, &argSqrd); 1428c2ecf20Sopenharmony_ci negate_Xsig(&accumulator); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h, 1458c2ecf20Sopenharmony_ci N_COEFF_PH - 1); 1468c2ecf20Sopenharmony_ci negate_Xsig(&accumulator); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci mul64_Xsig(&accumulator, &fixed_arg); 1498c2ecf20Sopenharmony_ci mul64_Xsig(&accumulator, &fixed_arg); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci shr_Xsig(&accumulator, 3); 1528c2ecf20Sopenharmony_ci negate_Xsig(&accumulator); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci add_Xsig_Xsig(&accumulator, &argSqrd); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci shr_Xsig(&accumulator, 1); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci accumulator.lsw |= 1; /* A zero accumulator here would cause problems */ 1598c2ecf20Sopenharmony_ci negate_Xsig(&accumulator); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* The basic computation is complete. Now fix the answer to 1628c2ecf20Sopenharmony_ci compensate for the error due to the approximation used for 1638c2ecf20Sopenharmony_ci pi/2 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* This has an exponent of -65 */ 1678c2ecf20Sopenharmony_ci fix_up = 0x898cc517; 1688c2ecf20Sopenharmony_ci /* The fix-up needs to be improved for larger args */ 1698c2ecf20Sopenharmony_ci if (argSqrd.msw & 0xffc00000) { 1708c2ecf20Sopenharmony_ci /* Get about 32 bit precision in these: */ 1718c2ecf20Sopenharmony_ci fix_up -= mul_32_32(0x898cc517, argSqrd.msw) / 6; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci fix_up = mul_32_32(fix_up, LL_MSW(fixed_arg)); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci adj = accumulator.lsw; /* temp save */ 1768c2ecf20Sopenharmony_ci accumulator.lsw -= fix_up; 1778c2ecf20Sopenharmony_ci if (accumulator.lsw > adj) 1788c2ecf20Sopenharmony_ci XSIG_LL(accumulator)--; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci echange = round_Xsig(&accumulator); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci setexponentpos(&result, echange - 1); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci significand(&result) = XSIG_LL(accumulator); 1868c2ecf20Sopenharmony_ci setsign(&result, getsign(st0_ptr)); 1878c2ecf20Sopenharmony_ci FPU_copy_to_reg0(&result, TAG_Valid); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci#ifdef PARANOID 1908c2ecf20Sopenharmony_ci if ((exponent(&result) >= 0) 1918c2ecf20Sopenharmony_ci && (significand(&result) > 0x8000000000000000LL)) { 1928c2ecf20Sopenharmony_ci EXCEPTION(EX_INTERNAL | 0x150); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci#endif /* PARANOID */ 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/*--- poly_cos() ------------------------------------------------------------+ 1998c2ecf20Sopenharmony_ci | | 2008c2ecf20Sopenharmony_ci +---------------------------------------------------------------------------*/ 2018c2ecf20Sopenharmony_civoid poly_cos(FPU_REG *st0_ptr) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci FPU_REG result; 2048c2ecf20Sopenharmony_ci long int exponent, exp2, echange; 2058c2ecf20Sopenharmony_ci Xsig accumulator, argSqrd, fix_up, argTo4; 2068c2ecf20Sopenharmony_ci unsigned long long fixed_arg; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci#ifdef PARANOID 2098c2ecf20Sopenharmony_ci if ((exponent(st0_ptr) > 0) 2108c2ecf20Sopenharmony_ci || ((exponent(st0_ptr) == 0) 2118c2ecf20Sopenharmony_ci && (significand(st0_ptr) > 0xc90fdaa22168c234LL))) { 2128c2ecf20Sopenharmony_ci EXCEPTION(EX_Invalid); 2138c2ecf20Sopenharmony_ci FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); 2148c2ecf20Sopenharmony_ci return; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci#endif /* PARANOID */ 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci exponent = exponent(st0_ptr); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci accumulator.lsw = accumulator.midw = accumulator.msw = 0; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if ((exponent < -1) 2238c2ecf20Sopenharmony_ci || ((exponent == -1) && (st0_ptr->sigh <= 0xb00d6f54))) { 2248c2ecf20Sopenharmony_ci /* arg is < 0.687705 */ 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci argSqrd.msw = st0_ptr->sigh; 2278c2ecf20Sopenharmony_ci argSqrd.midw = st0_ptr->sigl; 2288c2ecf20Sopenharmony_ci argSqrd.lsw = 0; 2298c2ecf20Sopenharmony_ci mul64_Xsig(&argSqrd, &significand(st0_ptr)); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (exponent < -1) { 2328c2ecf20Sopenharmony_ci /* shift the argument right by the required places */ 2338c2ecf20Sopenharmony_ci shr_Xsig(&argSqrd, 2 * (-1 - exponent)); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci argTo4.msw = argSqrd.msw; 2378c2ecf20Sopenharmony_ci argTo4.midw = argSqrd.midw; 2388c2ecf20Sopenharmony_ci argTo4.lsw = argSqrd.lsw; 2398c2ecf20Sopenharmony_ci mul_Xsig_Xsig(&argTo4, &argTo4); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h, 2428c2ecf20Sopenharmony_ci N_COEFF_NH - 1); 2438c2ecf20Sopenharmony_ci mul_Xsig_Xsig(&accumulator, &argSqrd); 2448c2ecf20Sopenharmony_ci negate_Xsig(&accumulator); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h, 2478c2ecf20Sopenharmony_ci N_COEFF_PH - 1); 2488c2ecf20Sopenharmony_ci negate_Xsig(&accumulator); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci mul64_Xsig(&accumulator, &significand(st0_ptr)); 2518c2ecf20Sopenharmony_ci mul64_Xsig(&accumulator, &significand(st0_ptr)); 2528c2ecf20Sopenharmony_ci shr_Xsig(&accumulator, -2 * (1 + exponent)); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci shr_Xsig(&accumulator, 3); 2558c2ecf20Sopenharmony_ci negate_Xsig(&accumulator); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci add_Xsig_Xsig(&accumulator, &argSqrd); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci shr_Xsig(&accumulator, 1); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* It doesn't matter if accumulator is all zero here, the 2628c2ecf20Sopenharmony_ci following code will work ok */ 2638c2ecf20Sopenharmony_ci negate_Xsig(&accumulator); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (accumulator.lsw & 0x80000000) 2668c2ecf20Sopenharmony_ci XSIG_LL(accumulator)++; 2678c2ecf20Sopenharmony_ci if (accumulator.msw == 0) { 2688c2ecf20Sopenharmony_ci /* The result is 1.0 */ 2698c2ecf20Sopenharmony_ci FPU_copy_to_reg0(&CONST_1, TAG_Valid); 2708c2ecf20Sopenharmony_ci return; 2718c2ecf20Sopenharmony_ci } else { 2728c2ecf20Sopenharmony_ci significand(&result) = XSIG_LL(accumulator); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* will be a valid positive nr with expon = -1 */ 2758c2ecf20Sopenharmony_ci setexponentpos(&result, -1); 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci } else { 2788c2ecf20Sopenharmony_ci fixed_arg = significand(st0_ptr); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (exponent == 0) { 2818c2ecf20Sopenharmony_ci /* The argument is >= 1.0 */ 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* Put the binary point at the left. */ 2848c2ecf20Sopenharmony_ci fixed_arg <<= 1; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */ 2878c2ecf20Sopenharmony_ci fixed_arg = 0x921fb54442d18469LL - fixed_arg; 2888c2ecf20Sopenharmony_ci /* There is a special case which arises due to rounding, to fix here. */ 2898c2ecf20Sopenharmony_ci if (fixed_arg == 0xffffffffffffffffLL) 2908c2ecf20Sopenharmony_ci fixed_arg = 0; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci exponent = -1; 2938c2ecf20Sopenharmony_ci exp2 = -1; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* A shift is needed here only for a narrow range of arguments, 2968c2ecf20Sopenharmony_ci i.e. for fixed_arg approx 2^-32, but we pick up more... */ 2978c2ecf20Sopenharmony_ci if (!(LL_MSW(fixed_arg) & 0xffff0000)) { 2988c2ecf20Sopenharmony_ci fixed_arg <<= 16; 2998c2ecf20Sopenharmony_ci exponent -= 16; 3008c2ecf20Sopenharmony_ci exp2 -= 16; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci XSIG_LL(argSqrd) = fixed_arg; 3048c2ecf20Sopenharmony_ci argSqrd.lsw = 0; 3058c2ecf20Sopenharmony_ci mul64_Xsig(&argSqrd, &fixed_arg); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (exponent < -1) { 3088c2ecf20Sopenharmony_ci /* shift the argument right by the required places */ 3098c2ecf20Sopenharmony_ci shr_Xsig(&argSqrd, 2 * (-1 - exponent)); 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci argTo4.msw = argSqrd.msw; 3138c2ecf20Sopenharmony_ci argTo4.midw = argSqrd.midw; 3148c2ecf20Sopenharmony_ci argTo4.lsw = argSqrd.lsw; 3158c2ecf20Sopenharmony_ci mul_Xsig_Xsig(&argTo4, &argTo4); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l, 3188c2ecf20Sopenharmony_ci N_COEFF_N - 1); 3198c2ecf20Sopenharmony_ci mul_Xsig_Xsig(&accumulator, &argSqrd); 3208c2ecf20Sopenharmony_ci negate_Xsig(&accumulator); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l, 3238c2ecf20Sopenharmony_ci N_COEFF_P - 1); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci shr_Xsig(&accumulator, 2); /* Divide by four */ 3268c2ecf20Sopenharmony_ci accumulator.msw |= 0x80000000; /* Add 1.0 */ 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci mul64_Xsig(&accumulator, &fixed_arg); 3298c2ecf20Sopenharmony_ci mul64_Xsig(&accumulator, &fixed_arg); 3308c2ecf20Sopenharmony_ci mul64_Xsig(&accumulator, &fixed_arg); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Divide by four, FPU_REG compatible, etc */ 3338c2ecf20Sopenharmony_ci exponent = 3 * exponent; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* The minimum exponent difference is 3 */ 3368c2ecf20Sopenharmony_ci shr_Xsig(&accumulator, exp2 - exponent); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci negate_Xsig(&accumulator); 3398c2ecf20Sopenharmony_ci XSIG_LL(accumulator) += fixed_arg; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* The basic computation is complete. Now fix the answer to 3428c2ecf20Sopenharmony_ci compensate for the error due to the approximation used for 3438c2ecf20Sopenharmony_ci pi/2 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* This has an exponent of -65 */ 3478c2ecf20Sopenharmony_ci XSIG_LL(fix_up) = 0x898cc51701b839a2ll; 3488c2ecf20Sopenharmony_ci fix_up.lsw = 0; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* The fix-up needs to be improved for larger args */ 3518c2ecf20Sopenharmony_ci if (argSqrd.msw & 0xffc00000) { 3528c2ecf20Sopenharmony_ci /* Get about 32 bit precision in these: */ 3538c2ecf20Sopenharmony_ci fix_up.msw -= mul_32_32(0x898cc517, argSqrd.msw) / 2; 3548c2ecf20Sopenharmony_ci fix_up.msw += mul_32_32(0x898cc517, argTo4.msw) / 24; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci exp2 += norm_Xsig(&accumulator); 3588c2ecf20Sopenharmony_ci shr_Xsig(&accumulator, 1); /* Prevent overflow */ 3598c2ecf20Sopenharmony_ci exp2++; 3608c2ecf20Sopenharmony_ci shr_Xsig(&fix_up, 65 + exp2); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci add_Xsig_Xsig(&accumulator, &fix_up); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci echange = round_Xsig(&accumulator); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci setexponentpos(&result, exp2 + echange); 3678c2ecf20Sopenharmony_ci significand(&result) = XSIG_LL(accumulator); 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci FPU_copy_to_reg0(&result, TAG_Valid); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci#ifdef PARANOID 3738c2ecf20Sopenharmony_ci if ((exponent(&result) >= 0) 3748c2ecf20Sopenharmony_ci && (significand(&result) > 0x8000000000000000LL)) { 3758c2ecf20Sopenharmony_ci EXCEPTION(EX_INTERNAL | 0x151); 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci#endif /* PARANOID */ 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci} 380