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/dfsqrt.c		$Revision: 1.1 $
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *  Purpose:
158c2ecf20Sopenharmony_ci *	Double Floating-point Square Root
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci *  External Interfaces:
188c2ecf20Sopenharmony_ci *	dbl_fsqrt(srcptr,nullptr,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 Floating-point Square Root
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/*ARGSUSED*/
378c2ecf20Sopenharmony_ciunsigned int
388c2ecf20Sopenharmony_cidbl_fsqrt(
398c2ecf20Sopenharmony_ci	    dbl_floating_point *srcptr,
408c2ecf20Sopenharmony_ci	    unsigned int *nullptr,
418c2ecf20Sopenharmony_ci	    dbl_floating_point *dstptr,
428c2ecf20Sopenharmony_ci	    unsigned int *status)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	register unsigned int srcp1, srcp2, resultp1, resultp2;
458c2ecf20Sopenharmony_ci	register unsigned int newbitp1, newbitp2, sump1, sump2;
468c2ecf20Sopenharmony_ci	register int src_exponent;
478c2ecf20Sopenharmony_ci	register boolean guardbit = FALSE, even_exponent;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	Dbl_copyfromptr(srcptr,srcp1,srcp2);
508c2ecf20Sopenharmony_ci        /*
518c2ecf20Sopenharmony_ci         * check source operand for NaN or infinity
528c2ecf20Sopenharmony_ci         */
538c2ecf20Sopenharmony_ci        if ((src_exponent = Dbl_exponent(srcp1)) == DBL_INFINITY_EXPONENT) {
548c2ecf20Sopenharmony_ci                /*
558c2ecf20Sopenharmony_ci                 * is signaling NaN?
568c2ecf20Sopenharmony_ci                 */
578c2ecf20Sopenharmony_ci                if (Dbl_isone_signaling(srcp1)) {
588c2ecf20Sopenharmony_ci                        /* trap if INVALIDTRAP enabled */
598c2ecf20Sopenharmony_ci                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
608c2ecf20Sopenharmony_ci                        /* make NaN quiet */
618c2ecf20Sopenharmony_ci                        Set_invalidflag();
628c2ecf20Sopenharmony_ci                        Dbl_set_quiet(srcp1);
638c2ecf20Sopenharmony_ci                }
648c2ecf20Sopenharmony_ci                /*
658c2ecf20Sopenharmony_ci                 * Return quiet NaN or positive infinity.
668c2ecf20Sopenharmony_ci		 *  Fall through to negative test if negative infinity.
678c2ecf20Sopenharmony_ci                 */
688c2ecf20Sopenharmony_ci		if (Dbl_iszero_sign(srcp1) ||
698c2ecf20Sopenharmony_ci		    Dbl_isnotzero_mantissa(srcp1,srcp2)) {
708c2ecf20Sopenharmony_ci                	Dbl_copytoptr(srcp1,srcp2,dstptr);
718c2ecf20Sopenharmony_ci                	return(NOEXCEPTION);
728c2ecf20Sopenharmony_ci		}
738c2ecf20Sopenharmony_ci        }
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci        /*
768c2ecf20Sopenharmony_ci         * check for zero source operand
778c2ecf20Sopenharmony_ci         */
788c2ecf20Sopenharmony_ci	if (Dbl_iszero_exponentmantissa(srcp1,srcp2)) {
798c2ecf20Sopenharmony_ci		Dbl_copytoptr(srcp1,srcp2,dstptr);
808c2ecf20Sopenharmony_ci		return(NOEXCEPTION);
818c2ecf20Sopenharmony_ci	}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci        /*
848c2ecf20Sopenharmony_ci         * check for negative source operand
858c2ecf20Sopenharmony_ci         */
868c2ecf20Sopenharmony_ci	if (Dbl_isone_sign(srcp1)) {
878c2ecf20Sopenharmony_ci		/* trap if INVALIDTRAP enabled */
888c2ecf20Sopenharmony_ci		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
898c2ecf20Sopenharmony_ci		/* make NaN quiet */
908c2ecf20Sopenharmony_ci		Set_invalidflag();
918c2ecf20Sopenharmony_ci		Dbl_makequietnan(srcp1,srcp2);
928c2ecf20Sopenharmony_ci		Dbl_copytoptr(srcp1,srcp2,dstptr);
938c2ecf20Sopenharmony_ci		return(NOEXCEPTION);
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	/*
978c2ecf20Sopenharmony_ci	 * Generate result
988c2ecf20Sopenharmony_ci	 */
998c2ecf20Sopenharmony_ci	if (src_exponent > 0) {
1008c2ecf20Sopenharmony_ci		even_exponent = Dbl_hidden(srcp1);
1018c2ecf20Sopenharmony_ci		Dbl_clear_signexponent_set_hidden(srcp1);
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci	else {
1048c2ecf20Sopenharmony_ci		/* normalize operand */
1058c2ecf20Sopenharmony_ci		Dbl_clear_signexponent(srcp1);
1068c2ecf20Sopenharmony_ci		src_exponent++;
1078c2ecf20Sopenharmony_ci		Dbl_normalize(srcp1,srcp2,src_exponent);
1088c2ecf20Sopenharmony_ci		even_exponent = src_exponent & 1;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci	if (even_exponent) {
1118c2ecf20Sopenharmony_ci		/* exponent is even */
1128c2ecf20Sopenharmony_ci		/* Add comment here.  Explain why odd exponent needs correction */
1138c2ecf20Sopenharmony_ci		Dbl_leftshiftby1(srcp1,srcp2);
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci	/*
1168c2ecf20Sopenharmony_ci	 * Add comment here.  Explain following algorithm.
1178c2ecf20Sopenharmony_ci	 *
1188c2ecf20Sopenharmony_ci	 * Trust me, it works.
1198c2ecf20Sopenharmony_ci	 *
1208c2ecf20Sopenharmony_ci	 */
1218c2ecf20Sopenharmony_ci	Dbl_setzero(resultp1,resultp2);
1228c2ecf20Sopenharmony_ci	Dbl_allp1(newbitp1) = 1 << (DBL_P - 32);
1238c2ecf20Sopenharmony_ci	Dbl_setzero_mantissap2(newbitp2);
1248c2ecf20Sopenharmony_ci	while (Dbl_isnotzero(newbitp1,newbitp2) && Dbl_isnotzero(srcp1,srcp2)) {
1258c2ecf20Sopenharmony_ci		Dbl_addition(resultp1,resultp2,newbitp1,newbitp2,sump1,sump2);
1268c2ecf20Sopenharmony_ci		if(Dbl_isnotgreaterthan(sump1,sump2,srcp1,srcp2)) {
1278c2ecf20Sopenharmony_ci			Dbl_leftshiftby1(newbitp1,newbitp2);
1288c2ecf20Sopenharmony_ci			/* update result */
1298c2ecf20Sopenharmony_ci			Dbl_addition(resultp1,resultp2,newbitp1,newbitp2,
1308c2ecf20Sopenharmony_ci			 resultp1,resultp2);
1318c2ecf20Sopenharmony_ci			Dbl_subtract(srcp1,srcp2,sump1,sump2,srcp1,srcp2);
1328c2ecf20Sopenharmony_ci			Dbl_rightshiftby2(newbitp1,newbitp2);
1338c2ecf20Sopenharmony_ci		}
1348c2ecf20Sopenharmony_ci		else {
1358c2ecf20Sopenharmony_ci			Dbl_rightshiftby1(newbitp1,newbitp2);
1368c2ecf20Sopenharmony_ci		}
1378c2ecf20Sopenharmony_ci		Dbl_leftshiftby1(srcp1,srcp2);
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci	/* correct exponent for pre-shift */
1408c2ecf20Sopenharmony_ci	if (even_exponent) {
1418c2ecf20Sopenharmony_ci		Dbl_rightshiftby1(resultp1,resultp2);
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	/* check for inexact */
1458c2ecf20Sopenharmony_ci	if (Dbl_isnotzero(srcp1,srcp2)) {
1468c2ecf20Sopenharmony_ci		if (!even_exponent && Dbl_islessthan(resultp1,resultp2,srcp1,srcp2)) {
1478c2ecf20Sopenharmony_ci			Dbl_increment(resultp1,resultp2);
1488c2ecf20Sopenharmony_ci		}
1498c2ecf20Sopenharmony_ci		guardbit = Dbl_lowmantissap2(resultp2);
1508c2ecf20Sopenharmony_ci		Dbl_rightshiftby1(resultp1,resultp2);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci		/*  now round result  */
1538c2ecf20Sopenharmony_ci		switch (Rounding_mode()) {
1548c2ecf20Sopenharmony_ci		case ROUNDPLUS:
1558c2ecf20Sopenharmony_ci		     Dbl_increment(resultp1,resultp2);
1568c2ecf20Sopenharmony_ci		     break;
1578c2ecf20Sopenharmony_ci		case ROUNDNEAREST:
1588c2ecf20Sopenharmony_ci		     /* stickybit is always true, so guardbit
1598c2ecf20Sopenharmony_ci		      * is enough to determine rounding */
1608c2ecf20Sopenharmony_ci		     if (guardbit) {
1618c2ecf20Sopenharmony_ci			    Dbl_increment(resultp1,resultp2);
1628c2ecf20Sopenharmony_ci		     }
1638c2ecf20Sopenharmony_ci		     break;
1648c2ecf20Sopenharmony_ci		}
1658c2ecf20Sopenharmony_ci		/* increment result exponent by 1 if mantissa overflowed */
1668c2ecf20Sopenharmony_ci		if (Dbl_isone_hiddenoverflow(resultp1)) src_exponent+=2;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci		if (Is_inexacttrap_enabled()) {
1698c2ecf20Sopenharmony_ci			Dbl_set_exponent(resultp1,
1708c2ecf20Sopenharmony_ci			 ((src_exponent-DBL_BIAS)>>1)+DBL_BIAS);
1718c2ecf20Sopenharmony_ci			Dbl_copytoptr(resultp1,resultp2,dstptr);
1728c2ecf20Sopenharmony_ci			return(INEXACTEXCEPTION);
1738c2ecf20Sopenharmony_ci		}
1748c2ecf20Sopenharmony_ci		else Set_inexactflag();
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci	else {
1778c2ecf20Sopenharmony_ci		Dbl_rightshiftby1(resultp1,resultp2);
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci	Dbl_set_exponent(resultp1,((src_exponent-DBL_BIAS)>>1)+DBL_BIAS);
1808c2ecf20Sopenharmony_ci	Dbl_copytoptr(resultp1,resultp2,dstptr);
1818c2ecf20Sopenharmony_ci	return(NOEXCEPTION);
1828c2ecf20Sopenharmony_ci}
183