18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux/PA-RISC Project (http://www.parisc-linux.org/) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Floating-point emulation code 68c2ecf20Sopenharmony_ci * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * BEGIN_DESC 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * File: 128c2ecf20Sopenharmony_ci * @(#) pa/spmath/dfrem.c $Revision: 1.1 $ 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Purpose: 158c2ecf20Sopenharmony_ci * Double Precision Floating-point Remainder 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * External Interfaces: 188c2ecf20Sopenharmony_ci * dbl_frem(srcptr1,srcptr2,dstptr,status) 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Internal Interfaces: 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Theory: 238c2ecf20Sopenharmony_ci * <<please update with a overview of the operation of this file>> 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * END_DESC 268c2ecf20Sopenharmony_ci*/ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "float.h" 318c2ecf20Sopenharmony_ci#include "dbl_float.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * Double Precision Floating-point Remainder 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ciint 388c2ecf20Sopenharmony_cidbl_frem (dbl_floating_point * srcptr1, dbl_floating_point * srcptr2, 398c2ecf20Sopenharmony_ci dbl_floating_point * dstptr, unsigned int *status) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2; 428c2ecf20Sopenharmony_ci register unsigned int resultp1, resultp2; 438c2ecf20Sopenharmony_ci register int opnd1_exponent, opnd2_exponent, dest_exponent, stepcount; 448c2ecf20Sopenharmony_ci register boolean roundup = FALSE; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2); 478c2ecf20Sopenharmony_ci Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2); 488c2ecf20Sopenharmony_ci /* 498c2ecf20Sopenharmony_ci * check first operand for NaN's or infinity 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci if ((opnd1_exponent = Dbl_exponent(opnd1p1)) == DBL_INFINITY_EXPONENT) { 528c2ecf20Sopenharmony_ci if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) { 538c2ecf20Sopenharmony_ci if (Dbl_isnotnan(opnd2p1,opnd2p2)) { 548c2ecf20Sopenharmony_ci /* invalid since first operand is infinity */ 558c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) 568c2ecf20Sopenharmony_ci return(INVALIDEXCEPTION); 578c2ecf20Sopenharmony_ci Set_invalidflag(); 588c2ecf20Sopenharmony_ci Dbl_makequietnan(resultp1,resultp2); 598c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 608c2ecf20Sopenharmony_ci return(NOEXCEPTION); 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci else { 648c2ecf20Sopenharmony_ci /* 658c2ecf20Sopenharmony_ci * is NaN; signaling or quiet? 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci if (Dbl_isone_signaling(opnd1p1)) { 688c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 698c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) 708c2ecf20Sopenharmony_ci return(INVALIDEXCEPTION); 718c2ecf20Sopenharmony_ci /* make NaN quiet */ 728c2ecf20Sopenharmony_ci Set_invalidflag(); 738c2ecf20Sopenharmony_ci Dbl_set_quiet(opnd1p1); 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci /* 768c2ecf20Sopenharmony_ci * is second operand a signaling NaN? 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci else if (Dbl_is_signalingnan(opnd2p1)) { 798c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 808c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) 818c2ecf20Sopenharmony_ci return(INVALIDEXCEPTION); 828c2ecf20Sopenharmony_ci /* make NaN quiet */ 838c2ecf20Sopenharmony_ci Set_invalidflag(); 848c2ecf20Sopenharmony_ci Dbl_set_quiet(opnd2p1); 858c2ecf20Sopenharmony_ci Dbl_copytoptr(opnd2p1,opnd2p2,dstptr); 868c2ecf20Sopenharmony_ci return(NOEXCEPTION); 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci /* 898c2ecf20Sopenharmony_ci * return quiet NaN 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci Dbl_copytoptr(opnd1p1,opnd1p2,dstptr); 928c2ecf20Sopenharmony_ci return(NOEXCEPTION); 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci /* 968c2ecf20Sopenharmony_ci * check second operand for NaN's or infinity 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci if ((opnd2_exponent = Dbl_exponent(opnd2p1)) == DBL_INFINITY_EXPONENT) { 998c2ecf20Sopenharmony_ci if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) { 1008c2ecf20Sopenharmony_ci /* 1018c2ecf20Sopenharmony_ci * return first operand 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci Dbl_copytoptr(opnd1p1,opnd1p2,dstptr); 1048c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci /* 1078c2ecf20Sopenharmony_ci * is NaN; signaling or quiet? 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci if (Dbl_isone_signaling(opnd2p1)) { 1108c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 1118c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 1128c2ecf20Sopenharmony_ci /* make NaN quiet */ 1138c2ecf20Sopenharmony_ci Set_invalidflag(); 1148c2ecf20Sopenharmony_ci Dbl_set_quiet(opnd2p1); 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci /* 1178c2ecf20Sopenharmony_ci * return quiet NaN 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_ci Dbl_copytoptr(opnd2p1,opnd2p2,dstptr); 1208c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * check second operand for zero 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) { 1268c2ecf20Sopenharmony_ci /* invalid since second operand is zero */ 1278c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 1288c2ecf20Sopenharmony_ci Set_invalidflag(); 1298c2ecf20Sopenharmony_ci Dbl_makequietnan(resultp1,resultp2); 1308c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 1318c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* 1358c2ecf20Sopenharmony_ci * get sign of result 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_ci resultp1 = opnd1p1; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* 1408c2ecf20Sopenharmony_ci * check for denormalized operands 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci if (opnd1_exponent == 0) { 1438c2ecf20Sopenharmony_ci /* check for zero */ 1448c2ecf20Sopenharmony_ci if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) { 1458c2ecf20Sopenharmony_ci Dbl_copytoptr(opnd1p1,opnd1p2,dstptr); 1468c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci /* normalize, then continue */ 1498c2ecf20Sopenharmony_ci opnd1_exponent = 1; 1508c2ecf20Sopenharmony_ci Dbl_normalize(opnd1p1,opnd1p2,opnd1_exponent); 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci else { 1538c2ecf20Sopenharmony_ci Dbl_clear_signexponent_set_hidden(opnd1p1); 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci if (opnd2_exponent == 0) { 1568c2ecf20Sopenharmony_ci /* normalize, then continue */ 1578c2ecf20Sopenharmony_ci opnd2_exponent = 1; 1588c2ecf20Sopenharmony_ci Dbl_normalize(opnd2p1,opnd2p2,opnd2_exponent); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci else { 1618c2ecf20Sopenharmony_ci Dbl_clear_signexponent_set_hidden(opnd2p1); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* find result exponent and divide step loop count */ 1658c2ecf20Sopenharmony_ci dest_exponent = opnd2_exponent - 1; 1668c2ecf20Sopenharmony_ci stepcount = opnd1_exponent - opnd2_exponent; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* 1698c2ecf20Sopenharmony_ci * check for opnd1/opnd2 < 1 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_ci if (stepcount < 0) { 1728c2ecf20Sopenharmony_ci /* 1738c2ecf20Sopenharmony_ci * check for opnd1/opnd2 > 1/2 1748c2ecf20Sopenharmony_ci * 1758c2ecf20Sopenharmony_ci * In this case n will round to 1, so 1768c2ecf20Sopenharmony_ci * r = opnd1 - opnd2 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci if (stepcount == -1 && 1798c2ecf20Sopenharmony_ci Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) { 1808c2ecf20Sopenharmony_ci /* set sign */ 1818c2ecf20Sopenharmony_ci Dbl_allp1(resultp1) = ~Dbl_allp1(resultp1); 1828c2ecf20Sopenharmony_ci /* align opnd2 with opnd1 */ 1838c2ecf20Sopenharmony_ci Dbl_leftshiftby1(opnd2p1,opnd2p2); 1848c2ecf20Sopenharmony_ci Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2, 1858c2ecf20Sopenharmony_ci opnd2p1,opnd2p2); 1868c2ecf20Sopenharmony_ci /* now normalize */ 1878c2ecf20Sopenharmony_ci while (Dbl_iszero_hidden(opnd2p1)) { 1888c2ecf20Sopenharmony_ci Dbl_leftshiftby1(opnd2p1,opnd2p2); 1898c2ecf20Sopenharmony_ci dest_exponent--; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci Dbl_set_exponentmantissa(resultp1,resultp2,opnd2p1,opnd2p2); 1928c2ecf20Sopenharmony_ci goto testforunderflow; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci /* 1958c2ecf20Sopenharmony_ci * opnd1/opnd2 <= 1/2 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * In this case n will round to zero, so 1988c2ecf20Sopenharmony_ci * r = opnd1 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ci Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2); 2018c2ecf20Sopenharmony_ci dest_exponent = opnd1_exponent; 2028c2ecf20Sopenharmony_ci goto testforunderflow; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* 2068c2ecf20Sopenharmony_ci * Generate result 2078c2ecf20Sopenharmony_ci * 2088c2ecf20Sopenharmony_ci * Do iterative subtract until remainder is less than operand 2. 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_ci while (stepcount-- > 0 && (Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2))) { 2118c2ecf20Sopenharmony_ci if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) { 2128c2ecf20Sopenharmony_ci Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci Dbl_leftshiftby1(opnd1p1,opnd1p2); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci /* 2178c2ecf20Sopenharmony_ci * Do last subtract, then determine which way to round if remainder 2188c2ecf20Sopenharmony_ci * is exactly 1/2 of opnd2 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) { 2218c2ecf20Sopenharmony_ci Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2); 2228c2ecf20Sopenharmony_ci roundup = TRUE; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci if (stepcount > 0 || Dbl_iszero(opnd1p1,opnd1p2)) { 2258c2ecf20Sopenharmony_ci /* division is exact, remainder is zero */ 2268c2ecf20Sopenharmony_ci Dbl_setzero_exponentmantissa(resultp1,resultp2); 2278c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 2288c2ecf20Sopenharmony_ci return(NOEXCEPTION); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * Check for cases where opnd1/opnd2 < n 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci * In this case the result's sign will be opposite that of 2358c2ecf20Sopenharmony_ci * opnd1. The mantissa also needs some correction. 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci Dbl_leftshiftby1(opnd1p1,opnd1p2); 2388c2ecf20Sopenharmony_ci if (Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) { 2398c2ecf20Sopenharmony_ci Dbl_invert_sign(resultp1); 2408c2ecf20Sopenharmony_ci Dbl_leftshiftby1(opnd2p1,opnd2p2); 2418c2ecf20Sopenharmony_ci Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2,opnd1p1,opnd1p2); 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci /* check for remainder being exactly 1/2 of opnd2 */ 2448c2ecf20Sopenharmony_ci else if (Dbl_isequal(opnd1p1,opnd1p2,opnd2p1,opnd2p2) && roundup) { 2458c2ecf20Sopenharmony_ci Dbl_invert_sign(resultp1); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* normalize result's mantissa */ 2498c2ecf20Sopenharmony_ci while (Dbl_iszero_hidden(opnd1p1)) { 2508c2ecf20Sopenharmony_ci dest_exponent--; 2518c2ecf20Sopenharmony_ci Dbl_leftshiftby1(opnd1p1,opnd1p2); 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* 2568c2ecf20Sopenharmony_ci * Test for underflow 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_ci testforunderflow: 2598c2ecf20Sopenharmony_ci if (dest_exponent <= 0) { 2608c2ecf20Sopenharmony_ci /* trap if UNDERFLOWTRAP enabled */ 2618c2ecf20Sopenharmony_ci if (Is_underflowtrap_enabled()) { 2628c2ecf20Sopenharmony_ci /* 2638c2ecf20Sopenharmony_ci * Adjust bias of result 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_ci Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl); 2668c2ecf20Sopenharmony_ci /* frem is always exact */ 2678c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 2688c2ecf20Sopenharmony_ci return(UNDERFLOWEXCEPTION); 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci /* 2718c2ecf20Sopenharmony_ci * denormalize result or set to signed zero 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci if (dest_exponent >= (1 - DBL_P)) { 2748c2ecf20Sopenharmony_ci Dbl_rightshift_exponentmantissa(resultp1,resultp2, 2758c2ecf20Sopenharmony_ci 1-dest_exponent); 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci else { 2788c2ecf20Sopenharmony_ci Dbl_setzero_exponentmantissa(resultp1,resultp2); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci else Dbl_set_exponent(resultp1,dest_exponent); 2828c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 2838c2ecf20Sopenharmony_ci return(NOEXCEPTION); 2848c2ecf20Sopenharmony_ci} 285