162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Linux/PA-RISC Project (http://www.parisc-linux.org/)
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Floating-point emulation code
662306a36Sopenharmony_ci *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * BEGIN_DESC
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *  File:
1262306a36Sopenharmony_ci *	@(#)	pa/spmath/dfsub.c		$Revision: 1.1 $
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *  Purpose:
1562306a36Sopenharmony_ci *	Double_subtract: subtract two double precision values.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *  External Interfaces:
1862306a36Sopenharmony_ci *	dbl_fsub(leftptr, rightptr, dstptr, status)
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *  Internal Interfaces:
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci *  Theory:
2362306a36Sopenharmony_ci *	<<please update with a overview of the operation of this file>>
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * END_DESC
2662306a36Sopenharmony_ci*/
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "float.h"
3062306a36Sopenharmony_ci#include "dbl_float.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * Double_subtract: subtract two double precision values.
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ciint
3662306a36Sopenharmony_cidbl_fsub(
3762306a36Sopenharmony_ci	    dbl_floating_point *leftptr,
3862306a36Sopenharmony_ci	    dbl_floating_point *rightptr,
3962306a36Sopenharmony_ci	    dbl_floating_point *dstptr,
4062306a36Sopenharmony_ci	    unsigned int *status)
4162306a36Sopenharmony_ci    {
4262306a36Sopenharmony_ci    register unsigned int signless_upper_left, signless_upper_right, save;
4362306a36Sopenharmony_ci    register unsigned int leftp1, leftp2, rightp1, rightp2, extent;
4462306a36Sopenharmony_ci    register unsigned int resultp1 = 0, resultp2 = 0;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci    register int result_exponent, right_exponent, diff_exponent;
4762306a36Sopenharmony_ci    register int sign_save, jumpsize;
4862306a36Sopenharmony_ci    register boolean inexact = FALSE, underflowtrap;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci    /* Create local copies of the numbers */
5162306a36Sopenharmony_ci    Dbl_copyfromptr(leftptr,leftp1,leftp2);
5262306a36Sopenharmony_ci    Dbl_copyfromptr(rightptr,rightp1,rightp2);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci    /* A zero "save" helps discover equal operands (for later),  *
5562306a36Sopenharmony_ci     * and is used in swapping operands (if needed).             */
5662306a36Sopenharmony_ci    Dbl_xortointp1(leftp1,rightp1,/*to*/save);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci    /*
5962306a36Sopenharmony_ci     * check first operand for NaN's or infinity
6062306a36Sopenharmony_ci     */
6162306a36Sopenharmony_ci    if ((result_exponent = Dbl_exponent(leftp1)) == DBL_INFINITY_EXPONENT)
6262306a36Sopenharmony_ci	{
6362306a36Sopenharmony_ci	if (Dbl_iszero_mantissa(leftp1,leftp2))
6462306a36Sopenharmony_ci	    {
6562306a36Sopenharmony_ci	    if (Dbl_isnotnan(rightp1,rightp2))
6662306a36Sopenharmony_ci		{
6762306a36Sopenharmony_ci		if (Dbl_isinfinity(rightp1,rightp2) && save==0)
6862306a36Sopenharmony_ci		    {
6962306a36Sopenharmony_ci		    /*
7062306a36Sopenharmony_ci		     * invalid since operands are same signed infinity's
7162306a36Sopenharmony_ci		     */
7262306a36Sopenharmony_ci		    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
7362306a36Sopenharmony_ci                    Set_invalidflag();
7462306a36Sopenharmony_ci                    Dbl_makequietnan(resultp1,resultp2);
7562306a36Sopenharmony_ci		    Dbl_copytoptr(resultp1,resultp2,dstptr);
7662306a36Sopenharmony_ci		    return(NOEXCEPTION);
7762306a36Sopenharmony_ci		    }
7862306a36Sopenharmony_ci		/*
7962306a36Sopenharmony_ci	 	 * return infinity
8062306a36Sopenharmony_ci	 	 */
8162306a36Sopenharmony_ci		Dbl_copytoptr(leftp1,leftp2,dstptr);
8262306a36Sopenharmony_ci		return(NOEXCEPTION);
8362306a36Sopenharmony_ci		}
8462306a36Sopenharmony_ci	    }
8562306a36Sopenharmony_ci	else
8662306a36Sopenharmony_ci	    {
8762306a36Sopenharmony_ci            /*
8862306a36Sopenharmony_ci             * is NaN; signaling or quiet?
8962306a36Sopenharmony_ci             */
9062306a36Sopenharmony_ci            if (Dbl_isone_signaling(leftp1))
9162306a36Sopenharmony_ci		{
9262306a36Sopenharmony_ci               	/* trap if INVALIDTRAP enabled */
9362306a36Sopenharmony_ci		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
9462306a36Sopenharmony_ci        	/* make NaN quiet */
9562306a36Sopenharmony_ci        	Set_invalidflag();
9662306a36Sopenharmony_ci        	Dbl_set_quiet(leftp1);
9762306a36Sopenharmony_ci        	}
9862306a36Sopenharmony_ci	    /*
9962306a36Sopenharmony_ci	     * is second operand a signaling NaN?
10062306a36Sopenharmony_ci	     */
10162306a36Sopenharmony_ci	    else if (Dbl_is_signalingnan(rightp1))
10262306a36Sopenharmony_ci		{
10362306a36Sopenharmony_ci        	/* trap if INVALIDTRAP enabled */
10462306a36Sopenharmony_ci               	if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
10562306a36Sopenharmony_ci		/* make NaN quiet */
10662306a36Sopenharmony_ci		Set_invalidflag();
10762306a36Sopenharmony_ci		Dbl_set_quiet(rightp1);
10862306a36Sopenharmony_ci		Dbl_copytoptr(rightp1,rightp2,dstptr);
10962306a36Sopenharmony_ci		return(NOEXCEPTION);
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci	    /*
11262306a36Sopenharmony_ci 	     * return quiet NaN
11362306a36Sopenharmony_ci 	     */
11462306a36Sopenharmony_ci	    Dbl_copytoptr(leftp1,leftp2,dstptr);
11562306a36Sopenharmony_ci 	    return(NOEXCEPTION);
11662306a36Sopenharmony_ci	    }
11762306a36Sopenharmony_ci	} /* End left NaN or Infinity processing */
11862306a36Sopenharmony_ci    /*
11962306a36Sopenharmony_ci     * check second operand for NaN's or infinity
12062306a36Sopenharmony_ci     */
12162306a36Sopenharmony_ci    if (Dbl_isinfinity_exponent(rightp1))
12262306a36Sopenharmony_ci	{
12362306a36Sopenharmony_ci	if (Dbl_iszero_mantissa(rightp1,rightp2))
12462306a36Sopenharmony_ci	    {
12562306a36Sopenharmony_ci	    /* return infinity */
12662306a36Sopenharmony_ci	    Dbl_invert_sign(rightp1);
12762306a36Sopenharmony_ci	    Dbl_copytoptr(rightp1,rightp2,dstptr);
12862306a36Sopenharmony_ci	    return(NOEXCEPTION);
12962306a36Sopenharmony_ci	    }
13062306a36Sopenharmony_ci        /*
13162306a36Sopenharmony_ci         * is NaN; signaling or quiet?
13262306a36Sopenharmony_ci         */
13362306a36Sopenharmony_ci        if (Dbl_isone_signaling(rightp1))
13462306a36Sopenharmony_ci	    {
13562306a36Sopenharmony_ci            /* trap if INVALIDTRAP enabled */
13662306a36Sopenharmony_ci	    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
13762306a36Sopenharmony_ci	    /* make NaN quiet */
13862306a36Sopenharmony_ci	    Set_invalidflag();
13962306a36Sopenharmony_ci	    Dbl_set_quiet(rightp1);
14062306a36Sopenharmony_ci	    }
14162306a36Sopenharmony_ci	/*
14262306a36Sopenharmony_ci	 * return quiet NaN
14362306a36Sopenharmony_ci 	 */
14462306a36Sopenharmony_ci	Dbl_copytoptr(rightp1,rightp2,dstptr);
14562306a36Sopenharmony_ci	return(NOEXCEPTION);
14662306a36Sopenharmony_ci    	} /* End right NaN or Infinity processing */
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci    /* Invariant: Must be dealing with finite numbers */
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci    /* Compare operands by removing the sign */
15162306a36Sopenharmony_ci    Dbl_copytoint_exponentmantissap1(leftp1,signless_upper_left);
15262306a36Sopenharmony_ci    Dbl_copytoint_exponentmantissap1(rightp1,signless_upper_right);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci    /* sign difference selects add or sub operation. */
15562306a36Sopenharmony_ci    if(Dbl_ismagnitudeless(leftp2,rightp2,signless_upper_left,signless_upper_right))
15662306a36Sopenharmony_ci	{
15762306a36Sopenharmony_ci	/* Set the left operand to the larger one by XOR swap *
15862306a36Sopenharmony_ci	 *  First finish the first word using "save"          */
15962306a36Sopenharmony_ci	Dbl_xorfromintp1(save,rightp1,/*to*/rightp1);
16062306a36Sopenharmony_ci	Dbl_xorfromintp1(save,leftp1,/*to*/leftp1);
16162306a36Sopenharmony_ci     	Dbl_swap_lower(leftp2,rightp2);
16262306a36Sopenharmony_ci	result_exponent = Dbl_exponent(leftp1);
16362306a36Sopenharmony_ci	Dbl_invert_sign(leftp1);
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci    /* Invariant:  left is not smaller than right. */
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci    if((right_exponent = Dbl_exponent(rightp1)) == 0)
16862306a36Sopenharmony_ci        {
16962306a36Sopenharmony_ci	/* Denormalized operands.  First look for zeroes */
17062306a36Sopenharmony_ci	if(Dbl_iszero_mantissa(rightp1,rightp2))
17162306a36Sopenharmony_ci	    {
17262306a36Sopenharmony_ci	    /* right is zero */
17362306a36Sopenharmony_ci	    if(Dbl_iszero_exponentmantissa(leftp1,leftp2))
17462306a36Sopenharmony_ci		{
17562306a36Sopenharmony_ci		/* Both operands are zeros */
17662306a36Sopenharmony_ci		Dbl_invert_sign(rightp1);
17762306a36Sopenharmony_ci		if(Is_rounding_mode(ROUNDMINUS))
17862306a36Sopenharmony_ci		    {
17962306a36Sopenharmony_ci		    Dbl_or_signs(leftp1,/*with*/rightp1);
18062306a36Sopenharmony_ci		    }
18162306a36Sopenharmony_ci		else
18262306a36Sopenharmony_ci		    {
18362306a36Sopenharmony_ci		    Dbl_and_signs(leftp1,/*with*/rightp1);
18462306a36Sopenharmony_ci		    }
18562306a36Sopenharmony_ci		}
18662306a36Sopenharmony_ci	    else
18762306a36Sopenharmony_ci		{
18862306a36Sopenharmony_ci		/* Left is not a zero and must be the result.  Trapped
18962306a36Sopenharmony_ci		 * underflows are signaled if left is denormalized.  Result
19062306a36Sopenharmony_ci		 * is always exact. */
19162306a36Sopenharmony_ci		if( (result_exponent == 0) && Is_underflowtrap_enabled() )
19262306a36Sopenharmony_ci		    {
19362306a36Sopenharmony_ci		    /* need to normalize results mantissa */
19462306a36Sopenharmony_ci	    	    sign_save = Dbl_signextendedsign(leftp1);
19562306a36Sopenharmony_ci		    Dbl_leftshiftby1(leftp1,leftp2);
19662306a36Sopenharmony_ci		    Dbl_normalize(leftp1,leftp2,result_exponent);
19762306a36Sopenharmony_ci		    Dbl_set_sign(leftp1,/*using*/sign_save);
19862306a36Sopenharmony_ci                    Dbl_setwrapped_exponent(leftp1,result_exponent,unfl);
19962306a36Sopenharmony_ci		    Dbl_copytoptr(leftp1,leftp2,dstptr);
20062306a36Sopenharmony_ci		    /* inexact = FALSE */
20162306a36Sopenharmony_ci		    return(UNDERFLOWEXCEPTION);
20262306a36Sopenharmony_ci		    }
20362306a36Sopenharmony_ci		}
20462306a36Sopenharmony_ci	    Dbl_copytoptr(leftp1,leftp2,dstptr);
20562306a36Sopenharmony_ci	    return(NOEXCEPTION);
20662306a36Sopenharmony_ci	    }
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* Neither are zeroes */
20962306a36Sopenharmony_ci	Dbl_clear_sign(rightp1);	/* Exponent is already cleared */
21062306a36Sopenharmony_ci	if(result_exponent == 0 )
21162306a36Sopenharmony_ci	    {
21262306a36Sopenharmony_ci	    /* Both operands are denormalized.  The result must be exact
21362306a36Sopenharmony_ci	     * and is simply calculated.  A sum could become normalized and a
21462306a36Sopenharmony_ci	     * difference could cancel to a true zero. */
21562306a36Sopenharmony_ci	    if( (/*signed*/int) save >= 0 )
21662306a36Sopenharmony_ci		{
21762306a36Sopenharmony_ci		Dbl_subtract(leftp1,leftp2,/*minus*/rightp1,rightp2,
21862306a36Sopenharmony_ci		 /*into*/resultp1,resultp2);
21962306a36Sopenharmony_ci		if(Dbl_iszero_mantissa(resultp1,resultp2))
22062306a36Sopenharmony_ci		    {
22162306a36Sopenharmony_ci		    if(Is_rounding_mode(ROUNDMINUS))
22262306a36Sopenharmony_ci			{
22362306a36Sopenharmony_ci			Dbl_setone_sign(resultp1);
22462306a36Sopenharmony_ci			}
22562306a36Sopenharmony_ci		    else
22662306a36Sopenharmony_ci			{
22762306a36Sopenharmony_ci			Dbl_setzero_sign(resultp1);
22862306a36Sopenharmony_ci			}
22962306a36Sopenharmony_ci		    Dbl_copytoptr(resultp1,resultp2,dstptr);
23062306a36Sopenharmony_ci		    return(NOEXCEPTION);
23162306a36Sopenharmony_ci		    }
23262306a36Sopenharmony_ci		}
23362306a36Sopenharmony_ci	    else
23462306a36Sopenharmony_ci		{
23562306a36Sopenharmony_ci		Dbl_addition(leftp1,leftp2,rightp1,rightp2,
23662306a36Sopenharmony_ci		 /*into*/resultp1,resultp2);
23762306a36Sopenharmony_ci		if(Dbl_isone_hidden(resultp1))
23862306a36Sopenharmony_ci		    {
23962306a36Sopenharmony_ci		    Dbl_copytoptr(resultp1,resultp2,dstptr);
24062306a36Sopenharmony_ci		    return(NOEXCEPTION);
24162306a36Sopenharmony_ci		    }
24262306a36Sopenharmony_ci		}
24362306a36Sopenharmony_ci	    if(Is_underflowtrap_enabled())
24462306a36Sopenharmony_ci		{
24562306a36Sopenharmony_ci		/* need to normalize result */
24662306a36Sopenharmony_ci	    	sign_save = Dbl_signextendedsign(resultp1);
24762306a36Sopenharmony_ci		Dbl_leftshiftby1(resultp1,resultp2);
24862306a36Sopenharmony_ci		Dbl_normalize(resultp1,resultp2,result_exponent);
24962306a36Sopenharmony_ci		Dbl_set_sign(resultp1,/*using*/sign_save);
25062306a36Sopenharmony_ci                Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
25162306a36Sopenharmony_ci		Dbl_copytoptr(resultp1,resultp2,dstptr);
25262306a36Sopenharmony_ci		/* inexact = FALSE */
25362306a36Sopenharmony_ci		return(UNDERFLOWEXCEPTION);
25462306a36Sopenharmony_ci		}
25562306a36Sopenharmony_ci	    Dbl_copytoptr(resultp1,resultp2,dstptr);
25662306a36Sopenharmony_ci	    return(NOEXCEPTION);
25762306a36Sopenharmony_ci	    }
25862306a36Sopenharmony_ci	right_exponent = 1;	/* Set exponent to reflect different bias
25962306a36Sopenharmony_ci				 * with denormalized numbers. */
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci    else
26262306a36Sopenharmony_ci	{
26362306a36Sopenharmony_ci	Dbl_clear_signexponent_set_hidden(rightp1);
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci    Dbl_clear_exponent_set_hidden(leftp1);
26662306a36Sopenharmony_ci    diff_exponent = result_exponent - right_exponent;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci    /*
26962306a36Sopenharmony_ci     * Special case alignment of operands that would force alignment
27062306a36Sopenharmony_ci     * beyond the extent of the extension.  A further optimization
27162306a36Sopenharmony_ci     * could special case this but only reduces the path length for this
27262306a36Sopenharmony_ci     * infrequent case.
27362306a36Sopenharmony_ci     */
27462306a36Sopenharmony_ci    if(diff_exponent > DBL_THRESHOLD)
27562306a36Sopenharmony_ci	{
27662306a36Sopenharmony_ci	diff_exponent = DBL_THRESHOLD;
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci    /* Align right operand by shifting to right */
28062306a36Sopenharmony_ci    Dbl_right_align(/*operand*/rightp1,rightp2,/*shifted by*/diff_exponent,
28162306a36Sopenharmony_ci     /*and lower to*/extent);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci    /* Treat sum and difference of the operands separately. */
28462306a36Sopenharmony_ci    if( (/*signed*/int) save >= 0 )
28562306a36Sopenharmony_ci	{
28662306a36Sopenharmony_ci	/*
28762306a36Sopenharmony_ci	 * Difference of the two operands.  Their can be no overflow.  A
28862306a36Sopenharmony_ci	 * borrow can occur out of the hidden bit and force a post
28962306a36Sopenharmony_ci	 * normalization phase.
29062306a36Sopenharmony_ci	 */
29162306a36Sopenharmony_ci	Dbl_subtract_withextension(leftp1,leftp2,/*minus*/rightp1,rightp2,
29262306a36Sopenharmony_ci	 /*with*/extent,/*into*/resultp1,resultp2);
29362306a36Sopenharmony_ci	if(Dbl_iszero_hidden(resultp1))
29462306a36Sopenharmony_ci	    {
29562306a36Sopenharmony_ci	    /* Handle normalization */
29662306a36Sopenharmony_ci	    /* A straight forward algorithm would now shift the result
29762306a36Sopenharmony_ci	     * and extension left until the hidden bit becomes one.  Not
29862306a36Sopenharmony_ci	     * all of the extension bits need participate in the shift.
29962306a36Sopenharmony_ci	     * Only the two most significant bits (round and guard) are
30062306a36Sopenharmony_ci	     * needed.  If only a single shift is needed then the guard
30162306a36Sopenharmony_ci	     * bit becomes a significant low order bit and the extension
30262306a36Sopenharmony_ci	     * must participate in the rounding.  If more than a single
30362306a36Sopenharmony_ci	     * shift is needed, then all bits to the right of the guard
30462306a36Sopenharmony_ci	     * bit are zeros, and the guard bit may or may not be zero. */
30562306a36Sopenharmony_ci	    sign_save = Dbl_signextendedsign(resultp1);
30662306a36Sopenharmony_ci            Dbl_leftshiftby1_withextent(resultp1,resultp2,extent,resultp1,resultp2);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci            /* Need to check for a zero result.  The sign and exponent
30962306a36Sopenharmony_ci	     * fields have already been zeroed.  The more efficient test
31062306a36Sopenharmony_ci	     * of the full object can be used.
31162306a36Sopenharmony_ci	     */
31262306a36Sopenharmony_ci    	    if(Dbl_iszero(resultp1,resultp2))
31362306a36Sopenharmony_ci		/* Must have been "x-x" or "x+(-x)". */
31462306a36Sopenharmony_ci		{
31562306a36Sopenharmony_ci		if(Is_rounding_mode(ROUNDMINUS)) Dbl_setone_sign(resultp1);
31662306a36Sopenharmony_ci		Dbl_copytoptr(resultp1,resultp2,dstptr);
31762306a36Sopenharmony_ci		return(NOEXCEPTION);
31862306a36Sopenharmony_ci		}
31962306a36Sopenharmony_ci	    result_exponent--;
32062306a36Sopenharmony_ci	    /* Look to see if normalization is finished. */
32162306a36Sopenharmony_ci	    if(Dbl_isone_hidden(resultp1))
32262306a36Sopenharmony_ci		{
32362306a36Sopenharmony_ci		if(result_exponent==0)
32462306a36Sopenharmony_ci		    {
32562306a36Sopenharmony_ci		    /* Denormalized, exponent should be zero.  Left operand *
32662306a36Sopenharmony_ci		     * was normalized, so extent (guard, round) was zero    */
32762306a36Sopenharmony_ci		    goto underflow;
32862306a36Sopenharmony_ci		    }
32962306a36Sopenharmony_ci		else
33062306a36Sopenharmony_ci		    {
33162306a36Sopenharmony_ci		    /* No further normalization is needed. */
33262306a36Sopenharmony_ci		    Dbl_set_sign(resultp1,/*using*/sign_save);
33362306a36Sopenharmony_ci	    	    Ext_leftshiftby1(extent);
33462306a36Sopenharmony_ci		    goto round;
33562306a36Sopenharmony_ci		    }
33662306a36Sopenharmony_ci		}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	    /* Check for denormalized, exponent should be zero.  Left    *
33962306a36Sopenharmony_ci	     * operand was normalized, so extent (guard, round) was zero */
34062306a36Sopenharmony_ci	    if(!(underflowtrap = Is_underflowtrap_enabled()) &&
34162306a36Sopenharmony_ci	       result_exponent==0) goto underflow;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	    /* Shift extension to complete one bit of normalization and
34462306a36Sopenharmony_ci	     * update exponent. */
34562306a36Sopenharmony_ci	    Ext_leftshiftby1(extent);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	    /* Discover first one bit to determine shift amount.  Use a
34862306a36Sopenharmony_ci	     * modified binary search.  We have already shifted the result
34962306a36Sopenharmony_ci	     * one position right and still not found a one so the remainder
35062306a36Sopenharmony_ci	     * of the extension must be zero and simplifies rounding. */
35162306a36Sopenharmony_ci	    /* Scan bytes */
35262306a36Sopenharmony_ci	    while(Dbl_iszero_hiddenhigh7mantissa(resultp1))
35362306a36Sopenharmony_ci		{
35462306a36Sopenharmony_ci		Dbl_leftshiftby8(resultp1,resultp2);
35562306a36Sopenharmony_ci		if((result_exponent -= 8) <= 0  && !underflowtrap)
35662306a36Sopenharmony_ci		    goto underflow;
35762306a36Sopenharmony_ci		}
35862306a36Sopenharmony_ci	    /* Now narrow it down to the nibble */
35962306a36Sopenharmony_ci	    if(Dbl_iszero_hiddenhigh3mantissa(resultp1))
36062306a36Sopenharmony_ci		{
36162306a36Sopenharmony_ci		/* The lower nibble contains the normalizing one */
36262306a36Sopenharmony_ci		Dbl_leftshiftby4(resultp1,resultp2);
36362306a36Sopenharmony_ci		if((result_exponent -= 4) <= 0 && !underflowtrap)
36462306a36Sopenharmony_ci		    goto underflow;
36562306a36Sopenharmony_ci		}
36662306a36Sopenharmony_ci	    /* Select case were first bit is set (already normalized)
36762306a36Sopenharmony_ci	     * otherwise select the proper shift. */
36862306a36Sopenharmony_ci	    if((jumpsize = Dbl_hiddenhigh3mantissa(resultp1)) > 7)
36962306a36Sopenharmony_ci		{
37062306a36Sopenharmony_ci		/* Already normalized */
37162306a36Sopenharmony_ci		if(result_exponent <= 0) goto underflow;
37262306a36Sopenharmony_ci		Dbl_set_sign(resultp1,/*using*/sign_save);
37362306a36Sopenharmony_ci		Dbl_set_exponent(resultp1,/*using*/result_exponent);
37462306a36Sopenharmony_ci		Dbl_copytoptr(resultp1,resultp2,dstptr);
37562306a36Sopenharmony_ci		return(NOEXCEPTION);
37662306a36Sopenharmony_ci		}
37762306a36Sopenharmony_ci	    Dbl_sethigh4bits(resultp1,/*using*/sign_save);
37862306a36Sopenharmony_ci	    switch(jumpsize)
37962306a36Sopenharmony_ci		{
38062306a36Sopenharmony_ci		case 1:
38162306a36Sopenharmony_ci		    {
38262306a36Sopenharmony_ci		    Dbl_leftshiftby3(resultp1,resultp2);
38362306a36Sopenharmony_ci		    result_exponent -= 3;
38462306a36Sopenharmony_ci		    break;
38562306a36Sopenharmony_ci		    }
38662306a36Sopenharmony_ci		case 2:
38762306a36Sopenharmony_ci		case 3:
38862306a36Sopenharmony_ci		    {
38962306a36Sopenharmony_ci		    Dbl_leftshiftby2(resultp1,resultp2);
39062306a36Sopenharmony_ci		    result_exponent -= 2;
39162306a36Sopenharmony_ci		    break;
39262306a36Sopenharmony_ci		    }
39362306a36Sopenharmony_ci		case 4:
39462306a36Sopenharmony_ci		case 5:
39562306a36Sopenharmony_ci		case 6:
39662306a36Sopenharmony_ci		case 7:
39762306a36Sopenharmony_ci		    {
39862306a36Sopenharmony_ci		    Dbl_leftshiftby1(resultp1,resultp2);
39962306a36Sopenharmony_ci		    result_exponent -= 1;
40062306a36Sopenharmony_ci		    break;
40162306a36Sopenharmony_ci		    }
40262306a36Sopenharmony_ci		}
40362306a36Sopenharmony_ci	    if(result_exponent > 0)
40462306a36Sopenharmony_ci		{
40562306a36Sopenharmony_ci		Dbl_set_exponent(resultp1,/*using*/result_exponent);
40662306a36Sopenharmony_ci		Dbl_copytoptr(resultp1,resultp2,dstptr);
40762306a36Sopenharmony_ci		return(NOEXCEPTION);		/* Sign bit is already set */
40862306a36Sopenharmony_ci		}
40962306a36Sopenharmony_ci	    /* Fixup potential underflows */
41062306a36Sopenharmony_ci	  underflow:
41162306a36Sopenharmony_ci	    if(Is_underflowtrap_enabled())
41262306a36Sopenharmony_ci		{
41362306a36Sopenharmony_ci		Dbl_set_sign(resultp1,sign_save);
41462306a36Sopenharmony_ci                Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
41562306a36Sopenharmony_ci		Dbl_copytoptr(resultp1,resultp2,dstptr);
41662306a36Sopenharmony_ci		/* inexact = FALSE */
41762306a36Sopenharmony_ci		return(UNDERFLOWEXCEPTION);
41862306a36Sopenharmony_ci		}
41962306a36Sopenharmony_ci	    /*
42062306a36Sopenharmony_ci	     * Since we cannot get an inexact denormalized result,
42162306a36Sopenharmony_ci	     * we can now return.
42262306a36Sopenharmony_ci	     */
42362306a36Sopenharmony_ci	    Dbl_fix_overshift(resultp1,resultp2,(1-result_exponent),extent);
42462306a36Sopenharmony_ci	    Dbl_clear_signexponent(resultp1);
42562306a36Sopenharmony_ci	    Dbl_set_sign(resultp1,sign_save);
42662306a36Sopenharmony_ci	    Dbl_copytoptr(resultp1,resultp2,dstptr);
42762306a36Sopenharmony_ci	    return(NOEXCEPTION);
42862306a36Sopenharmony_ci	    } /* end if(hidden...)... */
42962306a36Sopenharmony_ci	/* Fall through and round */
43062306a36Sopenharmony_ci	} /* end if(save >= 0)... */
43162306a36Sopenharmony_ci    else
43262306a36Sopenharmony_ci	{
43362306a36Sopenharmony_ci	/* Subtract magnitudes */
43462306a36Sopenharmony_ci	Dbl_addition(leftp1,leftp2,rightp1,rightp2,/*to*/resultp1,resultp2);
43562306a36Sopenharmony_ci	if(Dbl_isone_hiddenoverflow(resultp1))
43662306a36Sopenharmony_ci	    {
43762306a36Sopenharmony_ci	    /* Prenormalization required. */
43862306a36Sopenharmony_ci	    Dbl_rightshiftby1_withextent(resultp2,extent,extent);
43962306a36Sopenharmony_ci	    Dbl_arithrightshiftby1(resultp1,resultp2);
44062306a36Sopenharmony_ci	    result_exponent++;
44162306a36Sopenharmony_ci	    } /* end if hiddenoverflow... */
44262306a36Sopenharmony_ci	} /* end else ...subtract magnitudes... */
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci    /* Round the result.  If the extension is all zeros,then the result is
44562306a36Sopenharmony_ci     * exact.  Otherwise round in the correct direction.  No underflow is
44662306a36Sopenharmony_ci     * possible. If a postnormalization is necessary, then the mantissa is
44762306a36Sopenharmony_ci     * all zeros so no shift is needed. */
44862306a36Sopenharmony_ci  round:
44962306a36Sopenharmony_ci    if(Ext_isnotzero(extent))
45062306a36Sopenharmony_ci	{
45162306a36Sopenharmony_ci	inexact = TRUE;
45262306a36Sopenharmony_ci	switch(Rounding_mode())
45362306a36Sopenharmony_ci	    {
45462306a36Sopenharmony_ci	    case ROUNDNEAREST: /* The default. */
45562306a36Sopenharmony_ci	    if(Ext_isone_sign(extent))
45662306a36Sopenharmony_ci		{
45762306a36Sopenharmony_ci		/* at least 1/2 ulp */
45862306a36Sopenharmony_ci		if(Ext_isnotzero_lower(extent)  ||
45962306a36Sopenharmony_ci		  Dbl_isone_lowmantissap2(resultp2))
46062306a36Sopenharmony_ci		    {
46162306a36Sopenharmony_ci		    /* either exactly half way and odd or more than 1/2ulp */
46262306a36Sopenharmony_ci		    Dbl_increment(resultp1,resultp2);
46362306a36Sopenharmony_ci		    }
46462306a36Sopenharmony_ci		}
46562306a36Sopenharmony_ci	    break;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	    case ROUNDPLUS:
46862306a36Sopenharmony_ci	    if(Dbl_iszero_sign(resultp1))
46962306a36Sopenharmony_ci		{
47062306a36Sopenharmony_ci		/* Round up positive results */
47162306a36Sopenharmony_ci		Dbl_increment(resultp1,resultp2);
47262306a36Sopenharmony_ci		}
47362306a36Sopenharmony_ci	    break;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	    case ROUNDMINUS:
47662306a36Sopenharmony_ci	    if(Dbl_isone_sign(resultp1))
47762306a36Sopenharmony_ci		{
47862306a36Sopenharmony_ci		/* Round down negative results */
47962306a36Sopenharmony_ci		Dbl_increment(resultp1,resultp2);
48062306a36Sopenharmony_ci		}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	    case ROUNDZERO:;
48362306a36Sopenharmony_ci	    /* truncate is simple */
48462306a36Sopenharmony_ci	    } /* end switch... */
48562306a36Sopenharmony_ci	if(Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci    if(result_exponent == DBL_INFINITY_EXPONENT)
48862306a36Sopenharmony_ci        {
48962306a36Sopenharmony_ci        /* Overflow */
49062306a36Sopenharmony_ci        if(Is_overflowtrap_enabled())
49162306a36Sopenharmony_ci	    {
49262306a36Sopenharmony_ci	    Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
49362306a36Sopenharmony_ci	    Dbl_copytoptr(resultp1,resultp2,dstptr);
49462306a36Sopenharmony_ci	    if (inexact)
49562306a36Sopenharmony_ci	    if (Is_inexacttrap_enabled())
49662306a36Sopenharmony_ci		return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
49762306a36Sopenharmony_ci		else Set_inexactflag();
49862306a36Sopenharmony_ci	    return(OVERFLOWEXCEPTION);
49962306a36Sopenharmony_ci	    }
50062306a36Sopenharmony_ci        else
50162306a36Sopenharmony_ci	    {
50262306a36Sopenharmony_ci	    inexact = TRUE;
50362306a36Sopenharmony_ci	    Set_overflowflag();
50462306a36Sopenharmony_ci	    Dbl_setoverflow(resultp1,resultp2);
50562306a36Sopenharmony_ci	    }
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci    else Dbl_set_exponent(resultp1,result_exponent);
50862306a36Sopenharmony_ci    Dbl_copytoptr(resultp1,resultp2,dstptr);
50962306a36Sopenharmony_ci    if(inexact)
51062306a36Sopenharmony_ci	if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
51162306a36Sopenharmony_ci	else Set_inexactflag();
51262306a36Sopenharmony_ci    return(NOEXCEPTION);
51362306a36Sopenharmony_ci    }
514