1*c2feb252Smickey /* $OpenBSD: dfdiv.c,v 1.5 2002/05/07 22:19:30 mickey Exp $ */
2*c2feb252Smickey /*
3*c2feb252Smickey (c) Copyright 1986 HEWLETT-PACKARD COMPANY
4*c2feb252Smickey To anyone who acknowledges that this file is provided "AS IS"
5*c2feb252Smickey without any express or implied warranty:
6*c2feb252Smickey permission to use, copy, modify, and distribute this file
7*c2feb252Smickey for any purpose is hereby granted without fee, provided that
8*c2feb252Smickey the above copyright notice and this notice appears in all
9*c2feb252Smickey copies, and that the name of Hewlett-Packard Company not be
10*c2feb252Smickey used in advertising or publicity pertaining to distribution
11*c2feb252Smickey of the software without specific, written prior permission.
12*c2feb252Smickey Hewlett-Packard Company makes no representations about the
13*c2feb252Smickey suitability of this software for any purpose.
14*c2feb252Smickey */
15*c2feb252Smickey /* @(#)dfdiv.c: Revision: 2.11.88.1 Date: 93/12/07 15:05:39 */
16b94afd46Smickey
17*c2feb252Smickey #include "float.h"
18*c2feb252Smickey #include "dbl_float.h"
198a472b3eSmickey
208a472b3eSmickey /*
218a472b3eSmickey * Double Precision Floating-point Divide
228a472b3eSmickey */
238a472b3eSmickey
24b94afd46Smickey int
dbl_fdiv(srcptr1,srcptr2,dstptr,status)258a472b3eSmickey dbl_fdiv(srcptr1,srcptr2,dstptr,status)
268a472b3eSmickey dbl_floating_point *srcptr1, *srcptr2, *dstptr;
278a472b3eSmickey unsigned int *status;
288a472b3eSmickey {
298a472b3eSmickey register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
308a472b3eSmickey register unsigned int opnd3p1, opnd3p2, resultp1, resultp2;
318a472b3eSmickey register int dest_exponent, count;
32628bbdd4Smickey register int inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
33628bbdd4Smickey int is_tiny;
348a472b3eSmickey
358a472b3eSmickey Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
368a472b3eSmickey Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
378a472b3eSmickey /*
388a472b3eSmickey * set sign bit of result
398a472b3eSmickey */
408a472b3eSmickey if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1))
418a472b3eSmickey Dbl_setnegativezerop1(resultp1);
428a472b3eSmickey else Dbl_setzerop1(resultp1);
438a472b3eSmickey /*
448a472b3eSmickey * check first operand for NaN's or infinity
458a472b3eSmickey */
468a472b3eSmickey if (Dbl_isinfinity_exponent(opnd1p1)) {
478a472b3eSmickey if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
488a472b3eSmickey if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
498a472b3eSmickey if (Dbl_isinfinity(opnd2p1,opnd2p2)) {
508a472b3eSmickey /*
518a472b3eSmickey * invalid since both operands
528a472b3eSmickey * are infinity
538a472b3eSmickey */
548a472b3eSmickey if (Is_invalidtrap_enabled())
558a472b3eSmickey return(INVALIDEXCEPTION);
568a472b3eSmickey Set_invalidflag();
578a472b3eSmickey Dbl_makequietnan(resultp1,resultp2);
588a472b3eSmickey Dbl_copytoptr(resultp1,resultp2,dstptr);
598a472b3eSmickey return(NOEXCEPTION);
608a472b3eSmickey }
618a472b3eSmickey /*
628a472b3eSmickey * return infinity
638a472b3eSmickey */
648a472b3eSmickey Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
658a472b3eSmickey Dbl_copytoptr(resultp1,resultp2,dstptr);
668a472b3eSmickey return(NOEXCEPTION);
678a472b3eSmickey }
688a472b3eSmickey }
698a472b3eSmickey else {
708a472b3eSmickey /*
718a472b3eSmickey * is NaN; signaling or quiet?
728a472b3eSmickey */
738a472b3eSmickey if (Dbl_isone_signaling(opnd1p1)) {
748a472b3eSmickey /* trap if INVALIDTRAP enabled */
758a472b3eSmickey if (Is_invalidtrap_enabled())
768a472b3eSmickey return(INVALIDEXCEPTION);
778a472b3eSmickey /* make NaN quiet */
788a472b3eSmickey Set_invalidflag();
798a472b3eSmickey Dbl_set_quiet(opnd1p1);
808a472b3eSmickey }
818a472b3eSmickey /*
828a472b3eSmickey * is second operand a signaling NaN?
838a472b3eSmickey */
848a472b3eSmickey else if (Dbl_is_signalingnan(opnd2p1)) {
858a472b3eSmickey /* trap if INVALIDTRAP enabled */
868a472b3eSmickey if (Is_invalidtrap_enabled())
878a472b3eSmickey return(INVALIDEXCEPTION);
888a472b3eSmickey /* make NaN quiet */
898a472b3eSmickey Set_invalidflag();
908a472b3eSmickey Dbl_set_quiet(opnd2p1);
918a472b3eSmickey Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
928a472b3eSmickey return(NOEXCEPTION);
938a472b3eSmickey }
948a472b3eSmickey /*
958a472b3eSmickey * return quiet NaN
968a472b3eSmickey */
978a472b3eSmickey Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
988a472b3eSmickey return(NOEXCEPTION);
998a472b3eSmickey }
1008a472b3eSmickey }
1018a472b3eSmickey /*
1028a472b3eSmickey * check second operand for NaN's or infinity
1038a472b3eSmickey */
1048a472b3eSmickey if (Dbl_isinfinity_exponent(opnd2p1)) {
1058a472b3eSmickey if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
1068a472b3eSmickey /*
1078a472b3eSmickey * return zero
1088a472b3eSmickey */
1098a472b3eSmickey Dbl_setzero_exponentmantissa(resultp1,resultp2);
1108a472b3eSmickey Dbl_copytoptr(resultp1,resultp2,dstptr);
1118a472b3eSmickey return(NOEXCEPTION);
1128a472b3eSmickey }
1138a472b3eSmickey /*
1148a472b3eSmickey * is NaN; signaling or quiet?
1158a472b3eSmickey */
1168a472b3eSmickey if (Dbl_isone_signaling(opnd2p1)) {
1178a472b3eSmickey /* trap if INVALIDTRAP enabled */
1188a472b3eSmickey if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
1198a472b3eSmickey /* make NaN quiet */
1208a472b3eSmickey Set_invalidflag();
1218a472b3eSmickey Dbl_set_quiet(opnd2p1);
1228a472b3eSmickey }
1238a472b3eSmickey /*
1248a472b3eSmickey * return quiet NaN
1258a472b3eSmickey */
1268a472b3eSmickey Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
1278a472b3eSmickey return(NOEXCEPTION);
1288a472b3eSmickey }
1298a472b3eSmickey /*
1308a472b3eSmickey * check for division by zero
1318a472b3eSmickey */
1328a472b3eSmickey if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
1338a472b3eSmickey if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
1348a472b3eSmickey /* invalid since both operands are zero */
1358a472b3eSmickey if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
1368a472b3eSmickey Set_invalidflag();
1378a472b3eSmickey Dbl_makequietnan(resultp1,resultp2);
1388a472b3eSmickey Dbl_copytoptr(resultp1,resultp2,dstptr);
1398a472b3eSmickey return(NOEXCEPTION);
1408a472b3eSmickey }
1418a472b3eSmickey if (Is_divisionbyzerotrap_enabled())
1428a472b3eSmickey return(DIVISIONBYZEROEXCEPTION);
1438a472b3eSmickey Set_divisionbyzeroflag();
1448a472b3eSmickey Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
1458a472b3eSmickey Dbl_copytoptr(resultp1,resultp2,dstptr);
1468a472b3eSmickey return(NOEXCEPTION);
1478a472b3eSmickey }
1488a472b3eSmickey /*
1498a472b3eSmickey * Generate exponent
1508a472b3eSmickey */
1518a472b3eSmickey dest_exponent = Dbl_exponent(opnd1p1) - Dbl_exponent(opnd2p1) + DBL_BIAS;
1528a472b3eSmickey
1538a472b3eSmickey /*
1548a472b3eSmickey * Generate mantissa
1558a472b3eSmickey */
1568a472b3eSmickey if (Dbl_isnotzero_exponent(opnd1p1)) {
1578a472b3eSmickey /* set hidden bit */
1588a472b3eSmickey Dbl_clear_signexponent_set_hidden(opnd1p1);
1598a472b3eSmickey }
1608a472b3eSmickey else {
1618a472b3eSmickey /* check for zero */
1628a472b3eSmickey if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
1638a472b3eSmickey Dbl_setzero_exponentmantissa(resultp1,resultp2);
1648a472b3eSmickey Dbl_copytoptr(resultp1,resultp2,dstptr);
1658a472b3eSmickey return(NOEXCEPTION);
1668a472b3eSmickey }
1678a472b3eSmickey /* is denormalized, want to normalize */
1688a472b3eSmickey Dbl_clear_signexponent(opnd1p1);
1698a472b3eSmickey Dbl_leftshiftby1(opnd1p1,opnd1p2);
1708a472b3eSmickey Dbl_normalize(opnd1p1,opnd1p2,dest_exponent);
1718a472b3eSmickey }
1728a472b3eSmickey /* opnd2 needs to have hidden bit set with msb in hidden bit */
1738a472b3eSmickey if (Dbl_isnotzero_exponent(opnd2p1)) {
1748a472b3eSmickey Dbl_clear_signexponent_set_hidden(opnd2p1);
1758a472b3eSmickey }
1768a472b3eSmickey else {
1778a472b3eSmickey /* is denormalized; want to normalize */
1788a472b3eSmickey Dbl_clear_signexponent(opnd2p1);
1798a472b3eSmickey Dbl_leftshiftby1(opnd2p1,opnd2p2);
1808a472b3eSmickey while (Dbl_iszero_hiddenhigh7mantissa(opnd2p1)) {
1818a472b3eSmickey dest_exponent+=8;
1828a472b3eSmickey Dbl_leftshiftby8(opnd2p1,opnd2p2);
1838a472b3eSmickey }
1848a472b3eSmickey if (Dbl_iszero_hiddenhigh3mantissa(opnd2p1)) {
1858a472b3eSmickey dest_exponent+=4;
1868a472b3eSmickey Dbl_leftshiftby4(opnd2p1,opnd2p2);
1878a472b3eSmickey }
1888a472b3eSmickey while (Dbl_iszero_hidden(opnd2p1)) {
1898a472b3eSmickey dest_exponent++;
1908a472b3eSmickey Dbl_leftshiftby1(opnd2p1,opnd2p2);
1918a472b3eSmickey }
1928a472b3eSmickey }
1938a472b3eSmickey
1948a472b3eSmickey /* Divide the source mantissas */
1958a472b3eSmickey
1968a472b3eSmickey /*
1978a472b3eSmickey * A non-restoring divide algorithm is used.
1988a472b3eSmickey */
1998a472b3eSmickey Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
2008a472b3eSmickey Dbl_setzero(opnd3p1,opnd3p2);
2018a472b3eSmickey for (count=1; count <= DBL_P && (opnd1p1 || opnd1p2); count++) {
2028a472b3eSmickey Dbl_leftshiftby1(opnd1p1,opnd1p2);
2038a472b3eSmickey Dbl_leftshiftby1(opnd3p1,opnd3p2);
2048a472b3eSmickey if (Dbl_iszero_sign(opnd1p1)) {
2058a472b3eSmickey Dbl_setone_lowmantissap2(opnd3p2);
2068a472b3eSmickey Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
2078a472b3eSmickey }
2088a472b3eSmickey else {
2098a472b3eSmickey Twoword_add(opnd1p1, opnd1p2, opnd2p1, opnd2p2);
2108a472b3eSmickey }
2118a472b3eSmickey }
2128a472b3eSmickey if (count <= DBL_P) {
2138a472b3eSmickey Dbl_leftshiftby1(opnd3p1,opnd3p2);
2148a472b3eSmickey Dbl_setone_lowmantissap2(opnd3p2);
2158a472b3eSmickey Dbl_leftshift(opnd3p1,opnd3p2,(DBL_P-count));
2168a472b3eSmickey if (Dbl_iszero_hidden(opnd3p1)) {
2178a472b3eSmickey Dbl_leftshiftby1(opnd3p1,opnd3p2);
2188a472b3eSmickey dest_exponent--;
2198a472b3eSmickey }
2208a472b3eSmickey }
2218a472b3eSmickey else {
2228a472b3eSmickey if (Dbl_iszero_hidden(opnd3p1)) {
2238a472b3eSmickey /* need to get one more bit of result */
2248a472b3eSmickey Dbl_leftshiftby1(opnd1p1,opnd1p2);
2258a472b3eSmickey Dbl_leftshiftby1(opnd3p1,opnd3p2);
2268a472b3eSmickey if (Dbl_iszero_sign(opnd1p1)) {
2278a472b3eSmickey Dbl_setone_lowmantissap2(opnd3p2);
2288a472b3eSmickey Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
2298a472b3eSmickey }
2308a472b3eSmickey else {
2318a472b3eSmickey Twoword_add(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
2328a472b3eSmickey }
2338a472b3eSmickey dest_exponent--;
2348a472b3eSmickey }
2358a472b3eSmickey if (Dbl_iszero_sign(opnd1p1)) guardbit = TRUE;
2368a472b3eSmickey stickybit = Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2);
2378a472b3eSmickey }
2388a472b3eSmickey inexact = guardbit | stickybit;
2398a472b3eSmickey
2408a472b3eSmickey /*
2418a472b3eSmickey * round result
2428a472b3eSmickey */
2438a472b3eSmickey if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) {
2448a472b3eSmickey Dbl_clear_signexponent(opnd3p1);
2458a472b3eSmickey switch (Rounding_mode()) {
2468a472b3eSmickey case ROUNDPLUS:
2478a472b3eSmickey if (Dbl_iszero_sign(resultp1))
2488a472b3eSmickey Dbl_increment(opnd3p1,opnd3p2);
2498a472b3eSmickey break;
2508a472b3eSmickey case ROUNDMINUS:
2518a472b3eSmickey if (Dbl_isone_sign(resultp1))
2528a472b3eSmickey Dbl_increment(opnd3p1,opnd3p2);
2538a472b3eSmickey break;
2548a472b3eSmickey case ROUNDNEAREST:
2558a472b3eSmickey if (guardbit && (stickybit ||
2568a472b3eSmickey Dbl_isone_lowmantissap2(opnd3p2))) {
2578a472b3eSmickey Dbl_increment(opnd3p1,opnd3p2);
2588a472b3eSmickey }
2598a472b3eSmickey }
2608a472b3eSmickey if (Dbl_isone_hidden(opnd3p1)) dest_exponent++;
2618a472b3eSmickey }
2628a472b3eSmickey Dbl_set_mantissa(resultp1,resultp2,opnd3p1,opnd3p2);
2638a472b3eSmickey
2648a472b3eSmickey /*
2658a472b3eSmickey * Test for overflow
2668a472b3eSmickey */
2678a472b3eSmickey if (dest_exponent >= DBL_INFINITY_EXPONENT) {
2688a472b3eSmickey /* trap if OVERFLOWTRAP enabled */
2698a472b3eSmickey if (Is_overflowtrap_enabled()) {
2708a472b3eSmickey /*
2718a472b3eSmickey * Adjust bias of result
2728a472b3eSmickey */
2738a472b3eSmickey Dbl_setwrapped_exponent(resultp1,dest_exponent,ovfl);
2748a472b3eSmickey Dbl_copytoptr(resultp1,resultp2,dstptr);
275b94afd46Smickey if (inexact) {
2768a472b3eSmickey if (Is_inexacttrap_enabled())
2778a472b3eSmickey return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
278b94afd46Smickey else
279b94afd46Smickey Set_inexactflag();
280b94afd46Smickey }
2818a472b3eSmickey return(OVERFLOWEXCEPTION);
2828a472b3eSmickey }
2838a472b3eSmickey Set_overflowflag();
2848a472b3eSmickey /* set result to infinity or largest number */
2858a472b3eSmickey Dbl_setoverflow(resultp1,resultp2);
2868a472b3eSmickey inexact = TRUE;
2878a472b3eSmickey }
2888a472b3eSmickey /*
2898a472b3eSmickey * Test for underflow
2908a472b3eSmickey */
2918a472b3eSmickey else if (dest_exponent <= 0) {
2928a472b3eSmickey /* trap if UNDERFLOWTRAP enabled */
2938a472b3eSmickey if (Is_underflowtrap_enabled()) {
2948a472b3eSmickey /*
2958a472b3eSmickey * Adjust bias of result
2968a472b3eSmickey */
2978a472b3eSmickey Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
2988a472b3eSmickey Dbl_copytoptr(resultp1,resultp2,dstptr);
299b94afd46Smickey if (inexact) {
3008a472b3eSmickey if (Is_inexacttrap_enabled())
3018a472b3eSmickey return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
302b94afd46Smickey else
303b94afd46Smickey Set_inexactflag();
304b94afd46Smickey }
3058a472b3eSmickey return(UNDERFLOWEXCEPTION);
3068a472b3eSmickey }
3078a472b3eSmickey
3088a472b3eSmickey /* Determine if should set underflow flag */
3098a472b3eSmickey is_tiny = TRUE;
3108a472b3eSmickey if (dest_exponent == 0 && inexact) {
3118a472b3eSmickey switch (Rounding_mode()) {
3128a472b3eSmickey case ROUNDPLUS:
3138a472b3eSmickey if (Dbl_iszero_sign(resultp1)) {
3148a472b3eSmickey Dbl_increment(opnd3p1,opnd3p2);
3158a472b3eSmickey if (Dbl_isone_hiddenoverflow(opnd3p1))
3168a472b3eSmickey is_tiny = FALSE;
3178a472b3eSmickey Dbl_decrement(opnd3p1,opnd3p2);
3188a472b3eSmickey }
3198a472b3eSmickey break;
3208a472b3eSmickey case ROUNDMINUS:
3218a472b3eSmickey if (Dbl_isone_sign(resultp1)) {
3228a472b3eSmickey Dbl_increment(opnd3p1,opnd3p2);
3238a472b3eSmickey if (Dbl_isone_hiddenoverflow(opnd3p1))
3248a472b3eSmickey is_tiny = FALSE;
3258a472b3eSmickey Dbl_decrement(opnd3p1,opnd3p2);
3268a472b3eSmickey }
3278a472b3eSmickey break;
3288a472b3eSmickey case ROUNDNEAREST:
3298a472b3eSmickey if (guardbit && (stickybit ||
3308a472b3eSmickey Dbl_isone_lowmantissap2(opnd3p2))) {
3318a472b3eSmickey Dbl_increment(opnd3p1,opnd3p2);
3328a472b3eSmickey if (Dbl_isone_hiddenoverflow(opnd3p1))
3338a472b3eSmickey is_tiny = FALSE;
3348a472b3eSmickey Dbl_decrement(opnd3p1,opnd3p2);
3358a472b3eSmickey }
3368a472b3eSmickey break;
3378a472b3eSmickey }
3388a472b3eSmickey }
3398a472b3eSmickey
3408a472b3eSmickey /*
3418a472b3eSmickey * denormalize result or set to signed zero
3428a472b3eSmickey */
3438a472b3eSmickey stickybit = inexact;
3448a472b3eSmickey Dbl_denormalize(opnd3p1,opnd3p2,dest_exponent,guardbit,
3458a472b3eSmickey stickybit,inexact);
3468a472b3eSmickey
3478a472b3eSmickey /* return rounded number */
3488a472b3eSmickey if (inexact) {
3498a472b3eSmickey switch (Rounding_mode()) {
3508a472b3eSmickey case ROUNDPLUS:
3518a472b3eSmickey if (Dbl_iszero_sign(resultp1)) {
3528a472b3eSmickey Dbl_increment(opnd3p1,opnd3p2);
3538a472b3eSmickey }
3548a472b3eSmickey break;
3558a472b3eSmickey case ROUNDMINUS:
3568a472b3eSmickey if (Dbl_isone_sign(resultp1)) {
3578a472b3eSmickey Dbl_increment(opnd3p1,opnd3p2);
3588a472b3eSmickey }
3598a472b3eSmickey break;
3608a472b3eSmickey case ROUNDNEAREST:
3618a472b3eSmickey if (guardbit && (stickybit ||
3628a472b3eSmickey Dbl_isone_lowmantissap2(opnd3p2))) {
3638a472b3eSmickey Dbl_increment(opnd3p1,opnd3p2);
3648a472b3eSmickey }
3658a472b3eSmickey break;
3668a472b3eSmickey }
367628bbdd4Smickey if (is_tiny)
368628bbdd4Smickey Set_underflowflag();
3698a472b3eSmickey }
3708a472b3eSmickey Dbl_set_exponentmantissa(resultp1,resultp2,opnd3p1,opnd3p2);
3718a472b3eSmickey }
3728a472b3eSmickey else Dbl_set_exponent(resultp1,dest_exponent);
3738a472b3eSmickey Dbl_copytoptr(resultp1,resultp2,dstptr);
3748a472b3eSmickey
3758a472b3eSmickey /* check for inexact */
3768a472b3eSmickey if (inexact) {
3778a472b3eSmickey if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
3788a472b3eSmickey else Set_inexactflag();
3798a472b3eSmickey }
3808a472b3eSmickey return(NOEXCEPTION);
3818a472b3eSmickey }
382