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/dfsqrt.c		$Revision: 1.1 $
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *  Purpose:
1562306a36Sopenharmony_ci *	Double Floating-point Square Root
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *  External Interfaces:
1862306a36Sopenharmony_ci *	dbl_fsqrt(srcptr,nullptr,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 Floating-point Square Root
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*ARGSUSED*/
3762306a36Sopenharmony_ciunsigned int
3862306a36Sopenharmony_cidbl_fsqrt(
3962306a36Sopenharmony_ci	    dbl_floating_point *srcptr,
4062306a36Sopenharmony_ci	    unsigned int *nullptr,
4162306a36Sopenharmony_ci	    dbl_floating_point *dstptr,
4262306a36Sopenharmony_ci	    unsigned int *status)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	register unsigned int srcp1, srcp2, resultp1, resultp2;
4562306a36Sopenharmony_ci	register unsigned int newbitp1, newbitp2, sump1, sump2;
4662306a36Sopenharmony_ci	register int src_exponent;
4762306a36Sopenharmony_ci	register boolean guardbit = FALSE, even_exponent;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	Dbl_copyfromptr(srcptr,srcp1,srcp2);
5062306a36Sopenharmony_ci        /*
5162306a36Sopenharmony_ci         * check source operand for NaN or infinity
5262306a36Sopenharmony_ci         */
5362306a36Sopenharmony_ci        if ((src_exponent = Dbl_exponent(srcp1)) == DBL_INFINITY_EXPONENT) {
5462306a36Sopenharmony_ci                /*
5562306a36Sopenharmony_ci                 * is signaling NaN?
5662306a36Sopenharmony_ci                 */
5762306a36Sopenharmony_ci                if (Dbl_isone_signaling(srcp1)) {
5862306a36Sopenharmony_ci                        /* trap if INVALIDTRAP enabled */
5962306a36Sopenharmony_ci                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
6062306a36Sopenharmony_ci                        /* make NaN quiet */
6162306a36Sopenharmony_ci                        Set_invalidflag();
6262306a36Sopenharmony_ci                        Dbl_set_quiet(srcp1);
6362306a36Sopenharmony_ci                }
6462306a36Sopenharmony_ci                /*
6562306a36Sopenharmony_ci                 * Return quiet NaN or positive infinity.
6662306a36Sopenharmony_ci		 *  Fall through to negative test if negative infinity.
6762306a36Sopenharmony_ci                 */
6862306a36Sopenharmony_ci		if (Dbl_iszero_sign(srcp1) ||
6962306a36Sopenharmony_ci		    Dbl_isnotzero_mantissa(srcp1,srcp2)) {
7062306a36Sopenharmony_ci                	Dbl_copytoptr(srcp1,srcp2,dstptr);
7162306a36Sopenharmony_ci                	return(NOEXCEPTION);
7262306a36Sopenharmony_ci		}
7362306a36Sopenharmony_ci        }
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci        /*
7662306a36Sopenharmony_ci         * check for zero source operand
7762306a36Sopenharmony_ci         */
7862306a36Sopenharmony_ci	if (Dbl_iszero_exponentmantissa(srcp1,srcp2)) {
7962306a36Sopenharmony_ci		Dbl_copytoptr(srcp1,srcp2,dstptr);
8062306a36Sopenharmony_ci		return(NOEXCEPTION);
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci        /*
8462306a36Sopenharmony_ci         * check for negative source operand
8562306a36Sopenharmony_ci         */
8662306a36Sopenharmony_ci	if (Dbl_isone_sign(srcp1)) {
8762306a36Sopenharmony_ci		/* trap if INVALIDTRAP enabled */
8862306a36Sopenharmony_ci		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
8962306a36Sopenharmony_ci		/* make NaN quiet */
9062306a36Sopenharmony_ci		Set_invalidflag();
9162306a36Sopenharmony_ci		Dbl_makequietnan(srcp1,srcp2);
9262306a36Sopenharmony_ci		Dbl_copytoptr(srcp1,srcp2,dstptr);
9362306a36Sopenharmony_ci		return(NOEXCEPTION);
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/*
9762306a36Sopenharmony_ci	 * Generate result
9862306a36Sopenharmony_ci	 */
9962306a36Sopenharmony_ci	if (src_exponent > 0) {
10062306a36Sopenharmony_ci		even_exponent = Dbl_hidden(srcp1);
10162306a36Sopenharmony_ci		Dbl_clear_signexponent_set_hidden(srcp1);
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci	else {
10462306a36Sopenharmony_ci		/* normalize operand */
10562306a36Sopenharmony_ci		Dbl_clear_signexponent(srcp1);
10662306a36Sopenharmony_ci		src_exponent++;
10762306a36Sopenharmony_ci		Dbl_normalize(srcp1,srcp2,src_exponent);
10862306a36Sopenharmony_ci		even_exponent = src_exponent & 1;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci	if (even_exponent) {
11162306a36Sopenharmony_ci		/* exponent is even */
11262306a36Sopenharmony_ci		/* Add comment here.  Explain why odd exponent needs correction */
11362306a36Sopenharmony_ci		Dbl_leftshiftby1(srcp1,srcp2);
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci	/*
11662306a36Sopenharmony_ci	 * Add comment here.  Explain following algorithm.
11762306a36Sopenharmony_ci	 *
11862306a36Sopenharmony_ci	 * Trust me, it works.
11962306a36Sopenharmony_ci	 *
12062306a36Sopenharmony_ci	 */
12162306a36Sopenharmony_ci	Dbl_setzero(resultp1,resultp2);
12262306a36Sopenharmony_ci	Dbl_allp1(newbitp1) = 1 << (DBL_P - 32);
12362306a36Sopenharmony_ci	Dbl_setzero_mantissap2(newbitp2);
12462306a36Sopenharmony_ci	while (Dbl_isnotzero(newbitp1,newbitp2) && Dbl_isnotzero(srcp1,srcp2)) {
12562306a36Sopenharmony_ci		Dbl_addition(resultp1,resultp2,newbitp1,newbitp2,sump1,sump2);
12662306a36Sopenharmony_ci		if(Dbl_isnotgreaterthan(sump1,sump2,srcp1,srcp2)) {
12762306a36Sopenharmony_ci			Dbl_leftshiftby1(newbitp1,newbitp2);
12862306a36Sopenharmony_ci			/* update result */
12962306a36Sopenharmony_ci			Dbl_addition(resultp1,resultp2,newbitp1,newbitp2,
13062306a36Sopenharmony_ci			 resultp1,resultp2);
13162306a36Sopenharmony_ci			Dbl_subtract(srcp1,srcp2,sump1,sump2,srcp1,srcp2);
13262306a36Sopenharmony_ci			Dbl_rightshiftby2(newbitp1,newbitp2);
13362306a36Sopenharmony_ci		}
13462306a36Sopenharmony_ci		else {
13562306a36Sopenharmony_ci			Dbl_rightshiftby1(newbitp1,newbitp2);
13662306a36Sopenharmony_ci		}
13762306a36Sopenharmony_ci		Dbl_leftshiftby1(srcp1,srcp2);
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci	/* correct exponent for pre-shift */
14062306a36Sopenharmony_ci	if (even_exponent) {
14162306a36Sopenharmony_ci		Dbl_rightshiftby1(resultp1,resultp2);
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* check for inexact */
14562306a36Sopenharmony_ci	if (Dbl_isnotzero(srcp1,srcp2)) {
14662306a36Sopenharmony_ci		if (!even_exponent && Dbl_islessthan(resultp1,resultp2,srcp1,srcp2)) {
14762306a36Sopenharmony_ci			Dbl_increment(resultp1,resultp2);
14862306a36Sopenharmony_ci		}
14962306a36Sopenharmony_ci		guardbit = Dbl_lowmantissap2(resultp2);
15062306a36Sopenharmony_ci		Dbl_rightshiftby1(resultp1,resultp2);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci		/*  now round result  */
15362306a36Sopenharmony_ci		switch (Rounding_mode()) {
15462306a36Sopenharmony_ci		case ROUNDPLUS:
15562306a36Sopenharmony_ci		     Dbl_increment(resultp1,resultp2);
15662306a36Sopenharmony_ci		     break;
15762306a36Sopenharmony_ci		case ROUNDNEAREST:
15862306a36Sopenharmony_ci		     /* stickybit is always true, so guardbit
15962306a36Sopenharmony_ci		      * is enough to determine rounding */
16062306a36Sopenharmony_ci		     if (guardbit) {
16162306a36Sopenharmony_ci			    Dbl_increment(resultp1,resultp2);
16262306a36Sopenharmony_ci		     }
16362306a36Sopenharmony_ci		     break;
16462306a36Sopenharmony_ci		}
16562306a36Sopenharmony_ci		/* increment result exponent by 1 if mantissa overflowed */
16662306a36Sopenharmony_ci		if (Dbl_isone_hiddenoverflow(resultp1)) src_exponent+=2;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		if (Is_inexacttrap_enabled()) {
16962306a36Sopenharmony_ci			Dbl_set_exponent(resultp1,
17062306a36Sopenharmony_ci			 ((src_exponent-DBL_BIAS)>>1)+DBL_BIAS);
17162306a36Sopenharmony_ci			Dbl_copytoptr(resultp1,resultp2,dstptr);
17262306a36Sopenharmony_ci			return(INEXACTEXCEPTION);
17362306a36Sopenharmony_ci		}
17462306a36Sopenharmony_ci		else Set_inexactflag();
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci	else {
17762306a36Sopenharmony_ci		Dbl_rightshiftby1(resultp1,resultp2);
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci	Dbl_set_exponent(resultp1,((src_exponent-DBL_BIAS)>>1)+DBL_BIAS);
18062306a36Sopenharmony_ci	Dbl_copytoptr(resultp1,resultp2,dstptr);
18162306a36Sopenharmony_ci	return(NOEXCEPTION);
18262306a36Sopenharmony_ci}
183