1*c2feb252Smickey /* $OpenBSD: sfmpy.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 /* @(#)sfmpy.c: Revision: 2.9.88.1 Date: 93/12/07 15:07:07 */
16b94afd46Smickey
17*c2feb252Smickey #include "float.h"
18*c2feb252Smickey #include "sgl_float.h"
198a472b3eSmickey
208a472b3eSmickey /*
218a472b3eSmickey * Single Precision Floating-point Multiply
228a472b3eSmickey */
23b94afd46Smickey int
sgl_fmpy(srcptr1,srcptr2,dstptr,status)248a472b3eSmickey sgl_fmpy(srcptr1,srcptr2,dstptr,status)
258a472b3eSmickey sgl_floating_point *srcptr1, *srcptr2, *dstptr;
268a472b3eSmickey unsigned int *status;
278a472b3eSmickey {
288a472b3eSmickey register unsigned int opnd1, opnd2, opnd3, result;
298a472b3eSmickey register int dest_exponent, count;
30628bbdd4Smickey register int inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
31628bbdd4Smickey int is_tiny;
328a472b3eSmickey
338a472b3eSmickey opnd1 = *srcptr1;
348a472b3eSmickey opnd2 = *srcptr2;
358a472b3eSmickey /*
368a472b3eSmickey * set sign bit of result
378a472b3eSmickey */
388a472b3eSmickey if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);
398a472b3eSmickey else Sgl_setzero(result);
408a472b3eSmickey /*
418a472b3eSmickey * check first operand for NaN's or infinity
428a472b3eSmickey */
438a472b3eSmickey if (Sgl_isinfinity_exponent(opnd1)) {
448a472b3eSmickey if (Sgl_iszero_mantissa(opnd1)) {
458a472b3eSmickey if (Sgl_isnotnan(opnd2)) {
468a472b3eSmickey if (Sgl_iszero_exponentmantissa(opnd2)) {
478a472b3eSmickey /*
488a472b3eSmickey * invalid since operands are infinity
498a472b3eSmickey * and zero
508a472b3eSmickey */
518a472b3eSmickey if (Is_invalidtrap_enabled())
528a472b3eSmickey return(INVALIDEXCEPTION);
538a472b3eSmickey Set_invalidflag();
548a472b3eSmickey Sgl_makequietnan(result);
558a472b3eSmickey *dstptr = result;
568a472b3eSmickey return(NOEXCEPTION);
578a472b3eSmickey }
588a472b3eSmickey /*
598a472b3eSmickey * return infinity
608a472b3eSmickey */
618a472b3eSmickey Sgl_setinfinity_exponentmantissa(result);
628a472b3eSmickey *dstptr = result;
638a472b3eSmickey return(NOEXCEPTION);
648a472b3eSmickey }
658a472b3eSmickey }
668a472b3eSmickey else {
678a472b3eSmickey /*
688a472b3eSmickey * is NaN; signaling or quiet?
698a472b3eSmickey */
708a472b3eSmickey if (Sgl_isone_signaling(opnd1)) {
718a472b3eSmickey /* trap if INVALIDTRAP enabled */
728a472b3eSmickey if (Is_invalidtrap_enabled())
738a472b3eSmickey return(INVALIDEXCEPTION);
748a472b3eSmickey /* make NaN quiet */
758a472b3eSmickey Set_invalidflag();
768a472b3eSmickey Sgl_set_quiet(opnd1);
778a472b3eSmickey }
788a472b3eSmickey /*
798a472b3eSmickey * is second operand a signaling NaN?
808a472b3eSmickey */
818a472b3eSmickey else if (Sgl_is_signalingnan(opnd2)) {
828a472b3eSmickey /* trap if INVALIDTRAP enabled */
838a472b3eSmickey if (Is_invalidtrap_enabled())
848a472b3eSmickey return(INVALIDEXCEPTION);
858a472b3eSmickey /* make NaN quiet */
868a472b3eSmickey Set_invalidflag();
878a472b3eSmickey Sgl_set_quiet(opnd2);
888a472b3eSmickey *dstptr = opnd2;
898a472b3eSmickey return(NOEXCEPTION);
908a472b3eSmickey }
918a472b3eSmickey /*
928a472b3eSmickey * return quiet NaN
938a472b3eSmickey */
948a472b3eSmickey *dstptr = opnd1;
958a472b3eSmickey return(NOEXCEPTION);
968a472b3eSmickey }
978a472b3eSmickey }
988a472b3eSmickey /*
998a472b3eSmickey * check second operand for NaN's or infinity
1008a472b3eSmickey */
1018a472b3eSmickey if (Sgl_isinfinity_exponent(opnd2)) {
1028a472b3eSmickey if (Sgl_iszero_mantissa(opnd2)) {
1038a472b3eSmickey if (Sgl_iszero_exponentmantissa(opnd1)) {
1048a472b3eSmickey /* invalid since operands are zero & infinity */
1058a472b3eSmickey if (Is_invalidtrap_enabled())
1068a472b3eSmickey return(INVALIDEXCEPTION);
1078a472b3eSmickey Set_invalidflag();
1088a472b3eSmickey Sgl_makequietnan(opnd2);
1098a472b3eSmickey *dstptr = opnd2;
1108a472b3eSmickey return(NOEXCEPTION);
1118a472b3eSmickey }
1128a472b3eSmickey /*
1138a472b3eSmickey * return infinity
1148a472b3eSmickey */
1158a472b3eSmickey Sgl_setinfinity_exponentmantissa(result);
1168a472b3eSmickey *dstptr = result;
1178a472b3eSmickey return(NOEXCEPTION);
1188a472b3eSmickey }
1198a472b3eSmickey /*
1208a472b3eSmickey * is NaN; signaling or quiet?
1218a472b3eSmickey */
1228a472b3eSmickey if (Sgl_isone_signaling(opnd2)) {
1238a472b3eSmickey /* trap if INVALIDTRAP enabled */
1248a472b3eSmickey if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
1258a472b3eSmickey
1268a472b3eSmickey /* make NaN quiet */
1278a472b3eSmickey Set_invalidflag();
1288a472b3eSmickey Sgl_set_quiet(opnd2);
1298a472b3eSmickey }
1308a472b3eSmickey /*
1318a472b3eSmickey * return quiet NaN
1328a472b3eSmickey */
1338a472b3eSmickey *dstptr = opnd2;
1348a472b3eSmickey return(NOEXCEPTION);
1358a472b3eSmickey }
1368a472b3eSmickey /*
1378a472b3eSmickey * Generate exponent
1388a472b3eSmickey */
1398a472b3eSmickey dest_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
1408a472b3eSmickey
1418a472b3eSmickey /*
1428a472b3eSmickey * Generate mantissa
1438a472b3eSmickey */
1448a472b3eSmickey if (Sgl_isnotzero_exponent(opnd1)) {
1458a472b3eSmickey /* set hidden bit */
1468a472b3eSmickey Sgl_clear_signexponent_set_hidden(opnd1);
1478a472b3eSmickey }
1488a472b3eSmickey else {
1498a472b3eSmickey /* check for zero */
1508a472b3eSmickey if (Sgl_iszero_mantissa(opnd1)) {
1518a472b3eSmickey Sgl_setzero_exponentmantissa(result);
1528a472b3eSmickey *dstptr = result;
1538a472b3eSmickey return(NOEXCEPTION);
1548a472b3eSmickey }
1558a472b3eSmickey /* is denormalized, adjust exponent */
1568a472b3eSmickey Sgl_clear_signexponent(opnd1);
1578a472b3eSmickey Sgl_leftshiftby1(opnd1);
1588a472b3eSmickey Sgl_normalize(opnd1,dest_exponent);
1598a472b3eSmickey }
1608a472b3eSmickey /* opnd2 needs to have hidden bit set with msb in hidden bit */
1618a472b3eSmickey if (Sgl_isnotzero_exponent(opnd2)) {
1628a472b3eSmickey Sgl_clear_signexponent_set_hidden(opnd2);
1638a472b3eSmickey }
1648a472b3eSmickey else {
1658a472b3eSmickey /* check for zero */
1668a472b3eSmickey if (Sgl_iszero_mantissa(opnd2)) {
1678a472b3eSmickey Sgl_setzero_exponentmantissa(result);
1688a472b3eSmickey *dstptr = result;
1698a472b3eSmickey return(NOEXCEPTION);
1708a472b3eSmickey }
1718a472b3eSmickey /* is denormalized; want to normalize */
1728a472b3eSmickey Sgl_clear_signexponent(opnd2);
1738a472b3eSmickey Sgl_leftshiftby1(opnd2);
1748a472b3eSmickey Sgl_normalize(opnd2,dest_exponent);
1758a472b3eSmickey }
1768a472b3eSmickey
1778a472b3eSmickey /* Multiply two source mantissas together */
1788a472b3eSmickey
1798a472b3eSmickey Sgl_leftshiftby4(opnd2); /* make room for guard bits */
1808a472b3eSmickey Sgl_setzero(opnd3);
1818a472b3eSmickey /*
1828a472b3eSmickey * Four bits at a time are inspected in each loop, and a
1838a472b3eSmickey * simple shift and add multiply algorithm is used.
1848a472b3eSmickey */
1858a472b3eSmickey for (count=1;count<SGL_P;count+=4) {
1868a472b3eSmickey stickybit |= Slow4(opnd3);
1878a472b3eSmickey Sgl_rightshiftby4(opnd3);
1888a472b3eSmickey if (Sbit28(opnd1)) Sall(opnd3) += (Sall(opnd2) << 3);
1898a472b3eSmickey if (Sbit29(opnd1)) Sall(opnd3) += (Sall(opnd2) << 2);
1908a472b3eSmickey if (Sbit30(opnd1)) Sall(opnd3) += (Sall(opnd2) << 1);
1918a472b3eSmickey if (Sbit31(opnd1)) Sall(opnd3) += Sall(opnd2);
1928a472b3eSmickey Sgl_rightshiftby4(opnd1);
1938a472b3eSmickey }
1948a472b3eSmickey /* make sure result is left-justified */
1958a472b3eSmickey if (Sgl_iszero_sign(opnd3)) {
1968a472b3eSmickey Sgl_leftshiftby1(opnd3);
1978a472b3eSmickey }
1988a472b3eSmickey else {
1998a472b3eSmickey /* result mantissa >= 2. */
2008a472b3eSmickey dest_exponent++;
2018a472b3eSmickey }
2028a472b3eSmickey /* check for denormalized result */
2038a472b3eSmickey while (Sgl_iszero_sign(opnd3)) {
2048a472b3eSmickey Sgl_leftshiftby1(opnd3);
2058a472b3eSmickey dest_exponent--;
2068a472b3eSmickey }
2078a472b3eSmickey /*
2088a472b3eSmickey * check for guard, sticky and inexact bits
2098a472b3eSmickey */
2108a472b3eSmickey stickybit |= Sgl_all(opnd3) << (SGL_BITLENGTH - SGL_EXP_LENGTH + 1);
2118a472b3eSmickey guardbit = Sbit24(opnd3);
2128a472b3eSmickey inexact = guardbit | stickybit;
2138a472b3eSmickey
2148a472b3eSmickey /* re-align mantissa */
2158a472b3eSmickey Sgl_rightshiftby8(opnd3);
2168a472b3eSmickey
2178a472b3eSmickey /*
2188a472b3eSmickey * round result
2198a472b3eSmickey */
2208a472b3eSmickey if (inexact && (dest_exponent>0 || Is_underflowtrap_enabled())) {
2218a472b3eSmickey Sgl_clear_signexponent(opnd3);
2228a472b3eSmickey switch (Rounding_mode()) {
2238a472b3eSmickey case ROUNDPLUS:
2248a472b3eSmickey if (Sgl_iszero_sign(result))
2258a472b3eSmickey Sgl_increment(opnd3);
2268a472b3eSmickey break;
2278a472b3eSmickey case ROUNDMINUS:
2288a472b3eSmickey if (Sgl_isone_sign(result))
2298a472b3eSmickey Sgl_increment(opnd3);
2308a472b3eSmickey break;
2318a472b3eSmickey case ROUNDNEAREST:
232628bbdd4Smickey if (guardbit &&
233628bbdd4Smickey (stickybit || Sgl_isone_lowmantissa(opnd3)))
2348a472b3eSmickey Sgl_increment(opnd3);
235628bbdd4Smickey break;
2368a472b3eSmickey }
2378a472b3eSmickey if (Sgl_isone_hidden(opnd3)) dest_exponent++;
2388a472b3eSmickey }
2398a472b3eSmickey Sgl_set_mantissa(result,opnd3);
2408a472b3eSmickey
2418a472b3eSmickey /*
2428a472b3eSmickey * Test for overflow
2438a472b3eSmickey */
2448a472b3eSmickey if (dest_exponent >= SGL_INFINITY_EXPONENT) {
2458a472b3eSmickey /* trap if OVERFLOWTRAP enabled */
2468a472b3eSmickey if (Is_overflowtrap_enabled()) {
2478a472b3eSmickey /*
2488a472b3eSmickey * Adjust bias of result
2498a472b3eSmickey */
2508a472b3eSmickey Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
2518a472b3eSmickey *dstptr = result;
252b94afd46Smickey if (inexact) {
2538a472b3eSmickey if (Is_inexacttrap_enabled())
2548a472b3eSmickey return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
2558a472b3eSmickey else Set_inexactflag();
256b94afd46Smickey }
2578a472b3eSmickey return(OVERFLOWEXCEPTION);
2588a472b3eSmickey }
2598a472b3eSmickey inexact = TRUE;
2608a472b3eSmickey Set_overflowflag();
2618a472b3eSmickey /* set result to infinity or largest number */
2628a472b3eSmickey Sgl_setoverflow(result);
2638a472b3eSmickey }
2648a472b3eSmickey /*
2658a472b3eSmickey * Test for underflow
2668a472b3eSmickey */
2678a472b3eSmickey else if (dest_exponent <= 0) {
2688a472b3eSmickey /* trap if UNDERFLOWTRAP enabled */
2698a472b3eSmickey if (Is_underflowtrap_enabled()) {
2708a472b3eSmickey /*
2718a472b3eSmickey * Adjust bias of result
2728a472b3eSmickey */
2738a472b3eSmickey Sgl_setwrapped_exponent(result,dest_exponent,unfl);
2748a472b3eSmickey *dstptr = result;
275b94afd46Smickey if (inexact) {
2768a472b3eSmickey if (Is_inexacttrap_enabled())
2778a472b3eSmickey return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
2788a472b3eSmickey else Set_inexactflag();
279b94afd46Smickey }
2808a472b3eSmickey return(UNDERFLOWEXCEPTION);
2818a472b3eSmickey }
2828a472b3eSmickey
2838a472b3eSmickey /* Determine if should set underflow flag */
2848a472b3eSmickey is_tiny = TRUE;
2858a472b3eSmickey if (dest_exponent == 0 && inexact) {
2868a472b3eSmickey switch (Rounding_mode()) {
2878a472b3eSmickey case ROUNDPLUS:
2888a472b3eSmickey if (Sgl_iszero_sign(result)) {
2898a472b3eSmickey Sgl_increment(opnd3);
2908a472b3eSmickey if (Sgl_isone_hiddenoverflow(opnd3))
2918a472b3eSmickey is_tiny = FALSE;
2928a472b3eSmickey Sgl_decrement(opnd3);
2938a472b3eSmickey }
2948a472b3eSmickey break;
2958a472b3eSmickey case ROUNDMINUS:
2968a472b3eSmickey if (Sgl_isone_sign(result)) {
2978a472b3eSmickey Sgl_increment(opnd3);
2988a472b3eSmickey if (Sgl_isone_hiddenoverflow(opnd3))
2998a472b3eSmickey is_tiny = FALSE;
3008a472b3eSmickey Sgl_decrement(opnd3);
3018a472b3eSmickey }
3028a472b3eSmickey break;
3038a472b3eSmickey case ROUNDNEAREST:
3048a472b3eSmickey if (guardbit && (stickybit ||
3058a472b3eSmickey Sgl_isone_lowmantissa(opnd3))) {
3068a472b3eSmickey Sgl_increment(opnd3);
3078a472b3eSmickey if (Sgl_isone_hiddenoverflow(opnd3))
3088a472b3eSmickey is_tiny = FALSE;
3098a472b3eSmickey Sgl_decrement(opnd3);
3108a472b3eSmickey }
3118a472b3eSmickey break;
3128a472b3eSmickey }
3138a472b3eSmickey }
3148a472b3eSmickey
3158a472b3eSmickey /*
3168a472b3eSmickey * denormalize result or set to signed zero
3178a472b3eSmickey */
3188a472b3eSmickey stickybit = inexact;
3198a472b3eSmickey Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
3208a472b3eSmickey
3218a472b3eSmickey /* return zero or smallest number */
3228a472b3eSmickey if (inexact) {
3238a472b3eSmickey switch (Rounding_mode()) {
3248a472b3eSmickey case ROUNDPLUS:
325628bbdd4Smickey if (Sgl_iszero_sign(result))
3268a472b3eSmickey Sgl_increment(opnd3);
3278a472b3eSmickey break;
3288a472b3eSmickey case ROUNDMINUS:
329628bbdd4Smickey if (Sgl_isone_sign(result))
3308a472b3eSmickey Sgl_increment(opnd3);
3318a472b3eSmickey break;
3328a472b3eSmickey case ROUNDNEAREST:
3338a472b3eSmickey if (guardbit && (stickybit ||
334628bbdd4Smickey Sgl_isone_lowmantissa(opnd3)))
3358a472b3eSmickey Sgl_increment(opnd3);
3368a472b3eSmickey break;
3378a472b3eSmickey }
3388a472b3eSmickey if (is_tiny) Set_underflowflag();
3398a472b3eSmickey }
3408a472b3eSmickey Sgl_set_exponentmantissa(result,opnd3);
3418a472b3eSmickey }
3428a472b3eSmickey else Sgl_set_exponent(result,dest_exponent);
3438a472b3eSmickey *dstptr = result;
3448a472b3eSmickey
3458a472b3eSmickey /* check for inexact */
3468a472b3eSmickey if (inexact) {
3478a472b3eSmickey if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
3488a472b3eSmickey else Set_inexactflag();
3498a472b3eSmickey }
3508a472b3eSmickey return(NOEXCEPTION);
3518a472b3eSmickey }
352