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/dfsub.c $Revision: 1.1 $ 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Purpose: 158c2ecf20Sopenharmony_ci * Double_subtract: subtract two double precision values. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * External Interfaces: 188c2ecf20Sopenharmony_ci * dbl_fsub(leftptr, rightptr, 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#include "float.h" 308c2ecf20Sopenharmony_ci#include "dbl_float.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * Double_subtract: subtract two double precision values. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ciint 368c2ecf20Sopenharmony_cidbl_fsub( 378c2ecf20Sopenharmony_ci dbl_floating_point *leftptr, 388c2ecf20Sopenharmony_ci dbl_floating_point *rightptr, 398c2ecf20Sopenharmony_ci dbl_floating_point *dstptr, 408c2ecf20Sopenharmony_ci unsigned int *status) 418c2ecf20Sopenharmony_ci { 428c2ecf20Sopenharmony_ci register unsigned int signless_upper_left, signless_upper_right, save; 438c2ecf20Sopenharmony_ci register unsigned int leftp1, leftp2, rightp1, rightp2, extent; 448c2ecf20Sopenharmony_ci register unsigned int resultp1 = 0, resultp2 = 0; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci register int result_exponent, right_exponent, diff_exponent; 478c2ecf20Sopenharmony_ci register int sign_save, jumpsize; 488c2ecf20Sopenharmony_ci register boolean inexact = FALSE, underflowtrap; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* Create local copies of the numbers */ 518c2ecf20Sopenharmony_ci Dbl_copyfromptr(leftptr,leftp1,leftp2); 528c2ecf20Sopenharmony_ci Dbl_copyfromptr(rightptr,rightp1,rightp2); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* A zero "save" helps discover equal operands (for later), * 558c2ecf20Sopenharmony_ci * and is used in swapping operands (if needed). */ 568c2ecf20Sopenharmony_ci Dbl_xortointp1(leftp1,rightp1,/*to*/save); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci /* 598c2ecf20Sopenharmony_ci * check first operand for NaN's or infinity 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ci if ((result_exponent = Dbl_exponent(leftp1)) == DBL_INFINITY_EXPONENT) 628c2ecf20Sopenharmony_ci { 638c2ecf20Sopenharmony_ci if (Dbl_iszero_mantissa(leftp1,leftp2)) 648c2ecf20Sopenharmony_ci { 658c2ecf20Sopenharmony_ci if (Dbl_isnotnan(rightp1,rightp2)) 668c2ecf20Sopenharmony_ci { 678c2ecf20Sopenharmony_ci if (Dbl_isinfinity(rightp1,rightp2) && save==0) 688c2ecf20Sopenharmony_ci { 698c2ecf20Sopenharmony_ci /* 708c2ecf20Sopenharmony_ci * invalid since operands are same signed infinity's 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 738c2ecf20Sopenharmony_ci Set_invalidflag(); 748c2ecf20Sopenharmony_ci Dbl_makequietnan(resultp1,resultp2); 758c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 768c2ecf20Sopenharmony_ci return(NOEXCEPTION); 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci /* 798c2ecf20Sopenharmony_ci * return infinity 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci Dbl_copytoptr(leftp1,leftp2,dstptr); 828c2ecf20Sopenharmony_ci return(NOEXCEPTION); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci else 868c2ecf20Sopenharmony_ci { 878c2ecf20Sopenharmony_ci /* 888c2ecf20Sopenharmony_ci * is NaN; signaling or quiet? 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci if (Dbl_isone_signaling(leftp1)) 918c2ecf20Sopenharmony_ci { 928c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 938c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 948c2ecf20Sopenharmony_ci /* make NaN quiet */ 958c2ecf20Sopenharmony_ci Set_invalidflag(); 968c2ecf20Sopenharmony_ci Dbl_set_quiet(leftp1); 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci /* 998c2ecf20Sopenharmony_ci * is second operand a signaling NaN? 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ci else if (Dbl_is_signalingnan(rightp1)) 1028c2ecf20Sopenharmony_ci { 1038c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 1048c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 1058c2ecf20Sopenharmony_ci /* make NaN quiet */ 1068c2ecf20Sopenharmony_ci Set_invalidflag(); 1078c2ecf20Sopenharmony_ci Dbl_set_quiet(rightp1); 1088c2ecf20Sopenharmony_ci Dbl_copytoptr(rightp1,rightp2,dstptr); 1098c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci /* 1128c2ecf20Sopenharmony_ci * return quiet NaN 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ci Dbl_copytoptr(leftp1,leftp2,dstptr); 1158c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci } /* End left NaN or Infinity processing */ 1188c2ecf20Sopenharmony_ci /* 1198c2ecf20Sopenharmony_ci * check second operand for NaN's or infinity 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci if (Dbl_isinfinity_exponent(rightp1)) 1228c2ecf20Sopenharmony_ci { 1238c2ecf20Sopenharmony_ci if (Dbl_iszero_mantissa(rightp1,rightp2)) 1248c2ecf20Sopenharmony_ci { 1258c2ecf20Sopenharmony_ci /* return infinity */ 1268c2ecf20Sopenharmony_ci Dbl_invert_sign(rightp1); 1278c2ecf20Sopenharmony_ci Dbl_copytoptr(rightp1,rightp2,dstptr); 1288c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci /* 1318c2ecf20Sopenharmony_ci * is NaN; signaling or quiet? 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci if (Dbl_isone_signaling(rightp1)) 1348c2ecf20Sopenharmony_ci { 1358c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 1368c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 1378c2ecf20Sopenharmony_ci /* make NaN quiet */ 1388c2ecf20Sopenharmony_ci Set_invalidflag(); 1398c2ecf20Sopenharmony_ci Dbl_set_quiet(rightp1); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci /* 1428c2ecf20Sopenharmony_ci * return quiet NaN 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci Dbl_copytoptr(rightp1,rightp2,dstptr); 1458c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1468c2ecf20Sopenharmony_ci } /* End right NaN or Infinity processing */ 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* Invariant: Must be dealing with finite numbers */ 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* Compare operands by removing the sign */ 1518c2ecf20Sopenharmony_ci Dbl_copytoint_exponentmantissap1(leftp1,signless_upper_left); 1528c2ecf20Sopenharmony_ci Dbl_copytoint_exponentmantissap1(rightp1,signless_upper_right); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* sign difference selects add or sub operation. */ 1558c2ecf20Sopenharmony_ci if(Dbl_ismagnitudeless(leftp2,rightp2,signless_upper_left,signless_upper_right)) 1568c2ecf20Sopenharmony_ci { 1578c2ecf20Sopenharmony_ci /* Set the left operand to the larger one by XOR swap * 1588c2ecf20Sopenharmony_ci * First finish the first word using "save" */ 1598c2ecf20Sopenharmony_ci Dbl_xorfromintp1(save,rightp1,/*to*/rightp1); 1608c2ecf20Sopenharmony_ci Dbl_xorfromintp1(save,leftp1,/*to*/leftp1); 1618c2ecf20Sopenharmony_ci Dbl_swap_lower(leftp2,rightp2); 1628c2ecf20Sopenharmony_ci result_exponent = Dbl_exponent(leftp1); 1638c2ecf20Sopenharmony_ci Dbl_invert_sign(leftp1); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci /* Invariant: left is not smaller than right. */ 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if((right_exponent = Dbl_exponent(rightp1)) == 0) 1688c2ecf20Sopenharmony_ci { 1698c2ecf20Sopenharmony_ci /* Denormalized operands. First look for zeroes */ 1708c2ecf20Sopenharmony_ci if(Dbl_iszero_mantissa(rightp1,rightp2)) 1718c2ecf20Sopenharmony_ci { 1728c2ecf20Sopenharmony_ci /* right is zero */ 1738c2ecf20Sopenharmony_ci if(Dbl_iszero_exponentmantissa(leftp1,leftp2)) 1748c2ecf20Sopenharmony_ci { 1758c2ecf20Sopenharmony_ci /* Both operands are zeros */ 1768c2ecf20Sopenharmony_ci Dbl_invert_sign(rightp1); 1778c2ecf20Sopenharmony_ci if(Is_rounding_mode(ROUNDMINUS)) 1788c2ecf20Sopenharmony_ci { 1798c2ecf20Sopenharmony_ci Dbl_or_signs(leftp1,/*with*/rightp1); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci else 1828c2ecf20Sopenharmony_ci { 1838c2ecf20Sopenharmony_ci Dbl_and_signs(leftp1,/*with*/rightp1); 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci else 1878c2ecf20Sopenharmony_ci { 1888c2ecf20Sopenharmony_ci /* Left is not a zero and must be the result. Trapped 1898c2ecf20Sopenharmony_ci * underflows are signaled if left is denormalized. Result 1908c2ecf20Sopenharmony_ci * is always exact. */ 1918c2ecf20Sopenharmony_ci if( (result_exponent == 0) && Is_underflowtrap_enabled() ) 1928c2ecf20Sopenharmony_ci { 1938c2ecf20Sopenharmony_ci /* need to normalize results mantissa */ 1948c2ecf20Sopenharmony_ci sign_save = Dbl_signextendedsign(leftp1); 1958c2ecf20Sopenharmony_ci Dbl_leftshiftby1(leftp1,leftp2); 1968c2ecf20Sopenharmony_ci Dbl_normalize(leftp1,leftp2,result_exponent); 1978c2ecf20Sopenharmony_ci Dbl_set_sign(leftp1,/*using*/sign_save); 1988c2ecf20Sopenharmony_ci Dbl_setwrapped_exponent(leftp1,result_exponent,unfl); 1998c2ecf20Sopenharmony_ci Dbl_copytoptr(leftp1,leftp2,dstptr); 2008c2ecf20Sopenharmony_ci /* inexact = FALSE */ 2018c2ecf20Sopenharmony_ci return(UNDERFLOWEXCEPTION); 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci Dbl_copytoptr(leftp1,leftp2,dstptr); 2058c2ecf20Sopenharmony_ci return(NOEXCEPTION); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* Neither are zeroes */ 2098c2ecf20Sopenharmony_ci Dbl_clear_sign(rightp1); /* Exponent is already cleared */ 2108c2ecf20Sopenharmony_ci if(result_exponent == 0 ) 2118c2ecf20Sopenharmony_ci { 2128c2ecf20Sopenharmony_ci /* Both operands are denormalized. The result must be exact 2138c2ecf20Sopenharmony_ci * and is simply calculated. A sum could become normalized and a 2148c2ecf20Sopenharmony_ci * difference could cancel to a true zero. */ 2158c2ecf20Sopenharmony_ci if( (/*signed*/int) save >= 0 ) 2168c2ecf20Sopenharmony_ci { 2178c2ecf20Sopenharmony_ci Dbl_subtract(leftp1,leftp2,/*minus*/rightp1,rightp2, 2188c2ecf20Sopenharmony_ci /*into*/resultp1,resultp2); 2198c2ecf20Sopenharmony_ci if(Dbl_iszero_mantissa(resultp1,resultp2)) 2208c2ecf20Sopenharmony_ci { 2218c2ecf20Sopenharmony_ci if(Is_rounding_mode(ROUNDMINUS)) 2228c2ecf20Sopenharmony_ci { 2238c2ecf20Sopenharmony_ci Dbl_setone_sign(resultp1); 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci else 2268c2ecf20Sopenharmony_ci { 2278c2ecf20Sopenharmony_ci Dbl_setzero_sign(resultp1); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 2308c2ecf20Sopenharmony_ci return(NOEXCEPTION); 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci else 2348c2ecf20Sopenharmony_ci { 2358c2ecf20Sopenharmony_ci Dbl_addition(leftp1,leftp2,rightp1,rightp2, 2368c2ecf20Sopenharmony_ci /*into*/resultp1,resultp2); 2378c2ecf20Sopenharmony_ci if(Dbl_isone_hidden(resultp1)) 2388c2ecf20Sopenharmony_ci { 2398c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 2408c2ecf20Sopenharmony_ci return(NOEXCEPTION); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci if(Is_underflowtrap_enabled()) 2448c2ecf20Sopenharmony_ci { 2458c2ecf20Sopenharmony_ci /* need to normalize result */ 2468c2ecf20Sopenharmony_ci sign_save = Dbl_signextendedsign(resultp1); 2478c2ecf20Sopenharmony_ci Dbl_leftshiftby1(resultp1,resultp2); 2488c2ecf20Sopenharmony_ci Dbl_normalize(resultp1,resultp2,result_exponent); 2498c2ecf20Sopenharmony_ci Dbl_set_sign(resultp1,/*using*/sign_save); 2508c2ecf20Sopenharmony_ci Dbl_setwrapped_exponent(resultp1,result_exponent,unfl); 2518c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 2528c2ecf20Sopenharmony_ci /* inexact = FALSE */ 2538c2ecf20Sopenharmony_ci return(UNDERFLOWEXCEPTION); 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 2568c2ecf20Sopenharmony_ci return(NOEXCEPTION); 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci right_exponent = 1; /* Set exponent to reflect different bias 2598c2ecf20Sopenharmony_ci * with denomalized numbers. */ 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci else 2628c2ecf20Sopenharmony_ci { 2638c2ecf20Sopenharmony_ci Dbl_clear_signexponent_set_hidden(rightp1); 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci Dbl_clear_exponent_set_hidden(leftp1); 2668c2ecf20Sopenharmony_ci diff_exponent = result_exponent - right_exponent; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * Special case alignment of operands that would force alignment 2708c2ecf20Sopenharmony_ci * beyond the extent of the extension. A further optimization 2718c2ecf20Sopenharmony_ci * could special case this but only reduces the path length for this 2728c2ecf20Sopenharmony_ci * infrequent case. 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ci if(diff_exponent > DBL_THRESHOLD) 2758c2ecf20Sopenharmony_ci { 2768c2ecf20Sopenharmony_ci diff_exponent = DBL_THRESHOLD; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* Align right operand by shifting to right */ 2808c2ecf20Sopenharmony_ci Dbl_right_align(/*operand*/rightp1,rightp2,/*shifted by*/diff_exponent, 2818c2ecf20Sopenharmony_ci /*and lower to*/extent); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* Treat sum and difference of the operands separately. */ 2848c2ecf20Sopenharmony_ci if( (/*signed*/int) save >= 0 ) 2858c2ecf20Sopenharmony_ci { 2868c2ecf20Sopenharmony_ci /* 2878c2ecf20Sopenharmony_ci * Difference of the two operands. Their can be no overflow. A 2888c2ecf20Sopenharmony_ci * borrow can occur out of the hidden bit and force a post 2898c2ecf20Sopenharmony_ci * normalization phase. 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_ci Dbl_subtract_withextension(leftp1,leftp2,/*minus*/rightp1,rightp2, 2928c2ecf20Sopenharmony_ci /*with*/extent,/*into*/resultp1,resultp2); 2938c2ecf20Sopenharmony_ci if(Dbl_iszero_hidden(resultp1)) 2948c2ecf20Sopenharmony_ci { 2958c2ecf20Sopenharmony_ci /* Handle normalization */ 2968c2ecf20Sopenharmony_ci /* A straight forward algorithm would now shift the result 2978c2ecf20Sopenharmony_ci * and extension left until the hidden bit becomes one. Not 2988c2ecf20Sopenharmony_ci * all of the extension bits need participate in the shift. 2998c2ecf20Sopenharmony_ci * Only the two most significant bits (round and guard) are 3008c2ecf20Sopenharmony_ci * needed. If only a single shift is needed then the guard 3018c2ecf20Sopenharmony_ci * bit becomes a significant low order bit and the extension 3028c2ecf20Sopenharmony_ci * must participate in the rounding. If more than a single 3038c2ecf20Sopenharmony_ci * shift is needed, then all bits to the right of the guard 3048c2ecf20Sopenharmony_ci * bit are zeros, and the guard bit may or may not be zero. */ 3058c2ecf20Sopenharmony_ci sign_save = Dbl_signextendedsign(resultp1); 3068c2ecf20Sopenharmony_ci Dbl_leftshiftby1_withextent(resultp1,resultp2,extent,resultp1,resultp2); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Need to check for a zero result. The sign and exponent 3098c2ecf20Sopenharmony_ci * fields have already been zeroed. The more efficient test 3108c2ecf20Sopenharmony_ci * of the full object can be used. 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_ci if(Dbl_iszero(resultp1,resultp2)) 3138c2ecf20Sopenharmony_ci /* Must have been "x-x" or "x+(-x)". */ 3148c2ecf20Sopenharmony_ci { 3158c2ecf20Sopenharmony_ci if(Is_rounding_mode(ROUNDMINUS)) Dbl_setone_sign(resultp1); 3168c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 3178c2ecf20Sopenharmony_ci return(NOEXCEPTION); 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci result_exponent--; 3208c2ecf20Sopenharmony_ci /* Look to see if normalization is finished. */ 3218c2ecf20Sopenharmony_ci if(Dbl_isone_hidden(resultp1)) 3228c2ecf20Sopenharmony_ci { 3238c2ecf20Sopenharmony_ci if(result_exponent==0) 3248c2ecf20Sopenharmony_ci { 3258c2ecf20Sopenharmony_ci /* Denormalized, exponent should be zero. Left operand * 3268c2ecf20Sopenharmony_ci * was normalized, so extent (guard, round) was zero */ 3278c2ecf20Sopenharmony_ci goto underflow; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci else 3308c2ecf20Sopenharmony_ci { 3318c2ecf20Sopenharmony_ci /* No further normalization is needed. */ 3328c2ecf20Sopenharmony_ci Dbl_set_sign(resultp1,/*using*/sign_save); 3338c2ecf20Sopenharmony_ci Ext_leftshiftby1(extent); 3348c2ecf20Sopenharmony_ci goto round; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* Check for denormalized, exponent should be zero. Left * 3398c2ecf20Sopenharmony_ci * operand was normalized, so extent (guard, round) was zero */ 3408c2ecf20Sopenharmony_ci if(!(underflowtrap = Is_underflowtrap_enabled()) && 3418c2ecf20Sopenharmony_ci result_exponent==0) goto underflow; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Shift extension to complete one bit of normalization and 3448c2ecf20Sopenharmony_ci * update exponent. */ 3458c2ecf20Sopenharmony_ci Ext_leftshiftby1(extent); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Discover first one bit to determine shift amount. Use a 3488c2ecf20Sopenharmony_ci * modified binary search. We have already shifted the result 3498c2ecf20Sopenharmony_ci * one position right and still not found a one so the remainder 3508c2ecf20Sopenharmony_ci * of the extension must be zero and simplifies rounding. */ 3518c2ecf20Sopenharmony_ci /* Scan bytes */ 3528c2ecf20Sopenharmony_ci while(Dbl_iszero_hiddenhigh7mantissa(resultp1)) 3538c2ecf20Sopenharmony_ci { 3548c2ecf20Sopenharmony_ci Dbl_leftshiftby8(resultp1,resultp2); 3558c2ecf20Sopenharmony_ci if((result_exponent -= 8) <= 0 && !underflowtrap) 3568c2ecf20Sopenharmony_ci goto underflow; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci /* Now narrow it down to the nibble */ 3598c2ecf20Sopenharmony_ci if(Dbl_iszero_hiddenhigh3mantissa(resultp1)) 3608c2ecf20Sopenharmony_ci { 3618c2ecf20Sopenharmony_ci /* The lower nibble contains the normalizing one */ 3628c2ecf20Sopenharmony_ci Dbl_leftshiftby4(resultp1,resultp2); 3638c2ecf20Sopenharmony_ci if((result_exponent -= 4) <= 0 && !underflowtrap) 3648c2ecf20Sopenharmony_ci goto underflow; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci /* Select case were first bit is set (already normalized) 3678c2ecf20Sopenharmony_ci * otherwise select the proper shift. */ 3688c2ecf20Sopenharmony_ci if((jumpsize = Dbl_hiddenhigh3mantissa(resultp1)) > 7) 3698c2ecf20Sopenharmony_ci { 3708c2ecf20Sopenharmony_ci /* Already normalized */ 3718c2ecf20Sopenharmony_ci if(result_exponent <= 0) goto underflow; 3728c2ecf20Sopenharmony_ci Dbl_set_sign(resultp1,/*using*/sign_save); 3738c2ecf20Sopenharmony_ci Dbl_set_exponent(resultp1,/*using*/result_exponent); 3748c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 3758c2ecf20Sopenharmony_ci return(NOEXCEPTION); 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci Dbl_sethigh4bits(resultp1,/*using*/sign_save); 3788c2ecf20Sopenharmony_ci switch(jumpsize) 3798c2ecf20Sopenharmony_ci { 3808c2ecf20Sopenharmony_ci case 1: 3818c2ecf20Sopenharmony_ci { 3828c2ecf20Sopenharmony_ci Dbl_leftshiftby3(resultp1,resultp2); 3838c2ecf20Sopenharmony_ci result_exponent -= 3; 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci case 2: 3878c2ecf20Sopenharmony_ci case 3: 3888c2ecf20Sopenharmony_ci { 3898c2ecf20Sopenharmony_ci Dbl_leftshiftby2(resultp1,resultp2); 3908c2ecf20Sopenharmony_ci result_exponent -= 2; 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci case 4: 3948c2ecf20Sopenharmony_ci case 5: 3958c2ecf20Sopenharmony_ci case 6: 3968c2ecf20Sopenharmony_ci case 7: 3978c2ecf20Sopenharmony_ci { 3988c2ecf20Sopenharmony_ci Dbl_leftshiftby1(resultp1,resultp2); 3998c2ecf20Sopenharmony_ci result_exponent -= 1; 4008c2ecf20Sopenharmony_ci break; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci if(result_exponent > 0) 4048c2ecf20Sopenharmony_ci { 4058c2ecf20Sopenharmony_ci Dbl_set_exponent(resultp1,/*using*/result_exponent); 4068c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 4078c2ecf20Sopenharmony_ci return(NOEXCEPTION); /* Sign bit is already set */ 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci /* Fixup potential underflows */ 4108c2ecf20Sopenharmony_ci underflow: 4118c2ecf20Sopenharmony_ci if(Is_underflowtrap_enabled()) 4128c2ecf20Sopenharmony_ci { 4138c2ecf20Sopenharmony_ci Dbl_set_sign(resultp1,sign_save); 4148c2ecf20Sopenharmony_ci Dbl_setwrapped_exponent(resultp1,result_exponent,unfl); 4158c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 4168c2ecf20Sopenharmony_ci /* inexact = FALSE */ 4178c2ecf20Sopenharmony_ci return(UNDERFLOWEXCEPTION); 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci /* 4208c2ecf20Sopenharmony_ci * Since we cannot get an inexact denormalized result, 4218c2ecf20Sopenharmony_ci * we can now return. 4228c2ecf20Sopenharmony_ci */ 4238c2ecf20Sopenharmony_ci Dbl_fix_overshift(resultp1,resultp2,(1-result_exponent),extent); 4248c2ecf20Sopenharmony_ci Dbl_clear_signexponent(resultp1); 4258c2ecf20Sopenharmony_ci Dbl_set_sign(resultp1,sign_save); 4268c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 4278c2ecf20Sopenharmony_ci return(NOEXCEPTION); 4288c2ecf20Sopenharmony_ci } /* end if(hidden...)... */ 4298c2ecf20Sopenharmony_ci /* Fall through and round */ 4308c2ecf20Sopenharmony_ci } /* end if(save >= 0)... */ 4318c2ecf20Sopenharmony_ci else 4328c2ecf20Sopenharmony_ci { 4338c2ecf20Sopenharmony_ci /* Subtract magnitudes */ 4348c2ecf20Sopenharmony_ci Dbl_addition(leftp1,leftp2,rightp1,rightp2,/*to*/resultp1,resultp2); 4358c2ecf20Sopenharmony_ci if(Dbl_isone_hiddenoverflow(resultp1)) 4368c2ecf20Sopenharmony_ci { 4378c2ecf20Sopenharmony_ci /* Prenormalization required. */ 4388c2ecf20Sopenharmony_ci Dbl_rightshiftby1_withextent(resultp2,extent,extent); 4398c2ecf20Sopenharmony_ci Dbl_arithrightshiftby1(resultp1,resultp2); 4408c2ecf20Sopenharmony_ci result_exponent++; 4418c2ecf20Sopenharmony_ci } /* end if hiddenoverflow... */ 4428c2ecf20Sopenharmony_ci } /* end else ...subtract magnitudes... */ 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* Round the result. If the extension is all zeros,then the result is 4458c2ecf20Sopenharmony_ci * exact. Otherwise round in the correct direction. No underflow is 4468c2ecf20Sopenharmony_ci * possible. If a postnormalization is necessary, then the mantissa is 4478c2ecf20Sopenharmony_ci * all zeros so no shift is needed. */ 4488c2ecf20Sopenharmony_ci round: 4498c2ecf20Sopenharmony_ci if(Ext_isnotzero(extent)) 4508c2ecf20Sopenharmony_ci { 4518c2ecf20Sopenharmony_ci inexact = TRUE; 4528c2ecf20Sopenharmony_ci switch(Rounding_mode()) 4538c2ecf20Sopenharmony_ci { 4548c2ecf20Sopenharmony_ci case ROUNDNEAREST: /* The default. */ 4558c2ecf20Sopenharmony_ci if(Ext_isone_sign(extent)) 4568c2ecf20Sopenharmony_ci { 4578c2ecf20Sopenharmony_ci /* at least 1/2 ulp */ 4588c2ecf20Sopenharmony_ci if(Ext_isnotzero_lower(extent) || 4598c2ecf20Sopenharmony_ci Dbl_isone_lowmantissap2(resultp2)) 4608c2ecf20Sopenharmony_ci { 4618c2ecf20Sopenharmony_ci /* either exactly half way and odd or more than 1/2ulp */ 4628c2ecf20Sopenharmony_ci Dbl_increment(resultp1,resultp2); 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci break; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci case ROUNDPLUS: 4688c2ecf20Sopenharmony_ci if(Dbl_iszero_sign(resultp1)) 4698c2ecf20Sopenharmony_ci { 4708c2ecf20Sopenharmony_ci /* Round up positive results */ 4718c2ecf20Sopenharmony_ci Dbl_increment(resultp1,resultp2); 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci break; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci case ROUNDMINUS: 4768c2ecf20Sopenharmony_ci if(Dbl_isone_sign(resultp1)) 4778c2ecf20Sopenharmony_ci { 4788c2ecf20Sopenharmony_ci /* Round down negative results */ 4798c2ecf20Sopenharmony_ci Dbl_increment(resultp1,resultp2); 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci case ROUNDZERO:; 4838c2ecf20Sopenharmony_ci /* truncate is simple */ 4848c2ecf20Sopenharmony_ci } /* end switch... */ 4858c2ecf20Sopenharmony_ci if(Dbl_isone_hiddenoverflow(resultp1)) result_exponent++; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci if(result_exponent == DBL_INFINITY_EXPONENT) 4888c2ecf20Sopenharmony_ci { 4898c2ecf20Sopenharmony_ci /* Overflow */ 4908c2ecf20Sopenharmony_ci if(Is_overflowtrap_enabled()) 4918c2ecf20Sopenharmony_ci { 4928c2ecf20Sopenharmony_ci Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl); 4938c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 4948c2ecf20Sopenharmony_ci if (inexact) 4958c2ecf20Sopenharmony_ci if (Is_inexacttrap_enabled()) 4968c2ecf20Sopenharmony_ci return(OVERFLOWEXCEPTION | INEXACTEXCEPTION); 4978c2ecf20Sopenharmony_ci else Set_inexactflag(); 4988c2ecf20Sopenharmony_ci return(OVERFLOWEXCEPTION); 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci else 5018c2ecf20Sopenharmony_ci { 5028c2ecf20Sopenharmony_ci inexact = TRUE; 5038c2ecf20Sopenharmony_ci Set_overflowflag(); 5048c2ecf20Sopenharmony_ci Dbl_setoverflow(resultp1,resultp2); 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci else Dbl_set_exponent(resultp1,result_exponent); 5088c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 5098c2ecf20Sopenharmony_ci if(inexact) 5108c2ecf20Sopenharmony_ci if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION); 5118c2ecf20Sopenharmony_ci else Set_inexactflag(); 5128c2ecf20Sopenharmony_ci return(NOEXCEPTION); 5138c2ecf20Sopenharmony_ci } 514