linux/arch/parisc/math-emu/dfrem.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Linux/PA-RISC Project (http://www.parisc-linux.org/)
   4 *
   5 * Floating-point emulation code
   6 *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
   7 */
   8/*
   9 * BEGIN_DESC
  10 *
  11 *  File:
  12 *      @(#)    pa/spmath/dfrem.c               $Revision: 1.1 $
  13 *
  14 *  Purpose:
  15 *      Double Precision Floating-point Remainder
  16 *
  17 *  External Interfaces:
  18 *      dbl_frem(srcptr1,srcptr2,dstptr,status)
  19 *
  20 *  Internal Interfaces:
  21 *
  22 *  Theory:
  23 *      <<please update with a overview of the operation of this file>>
  24 *
  25 * END_DESC
  26*/
  27
  28
  29
  30#include "float.h"
  31#include "dbl_float.h"
  32
  33/*
  34 *  Double Precision Floating-point Remainder
  35 */
  36
  37int
  38dbl_frem (dbl_floating_point * srcptr1, dbl_floating_point * srcptr2,
  39          dbl_floating_point * dstptr, unsigned int *status)
  40{
  41        register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
  42        register unsigned int resultp1, resultp2;
  43        register int opnd1_exponent, opnd2_exponent, dest_exponent, stepcount;
  44        register boolean roundup = FALSE;
  45
  46        Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
  47        Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
  48        /*
  49         * check first operand for NaN's or infinity
  50         */
  51        if ((opnd1_exponent = Dbl_exponent(opnd1p1)) == DBL_INFINITY_EXPONENT) {
  52                if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
  53                        if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
  54                                /* invalid since first operand is infinity */
  55                                if (Is_invalidtrap_enabled()) 
  56                                        return(INVALIDEXCEPTION);
  57                                Set_invalidflag();
  58                                Dbl_makequietnan(resultp1,resultp2);
  59                                Dbl_copytoptr(resultp1,resultp2,dstptr);
  60                                return(NOEXCEPTION);
  61                        }
  62                }
  63                else {
  64                        /*
  65                         * is NaN; signaling or quiet?
  66                         */
  67                        if (Dbl_isone_signaling(opnd1p1)) {
  68                                /* trap if INVALIDTRAP enabled */
  69                                if (Is_invalidtrap_enabled()) 
  70                                        return(INVALIDEXCEPTION);
  71                                /* make NaN quiet */
  72                                Set_invalidflag();
  73                                Dbl_set_quiet(opnd1p1);
  74                        }
  75                        /* 
  76                         * is second operand a signaling NaN? 
  77                         */
  78                        else if (Dbl_is_signalingnan(opnd2p1)) {
  79                                /* trap if INVALIDTRAP enabled */
  80                                if (Is_invalidtrap_enabled()) 
  81                                        return(INVALIDEXCEPTION);
  82                                /* make NaN quiet */
  83                                Set_invalidflag();
  84                                Dbl_set_quiet(opnd2p1);
  85                                Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
  86                                return(NOEXCEPTION);
  87                        }
  88                        /*
  89                         * return quiet NaN
  90                         */
  91                        Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
  92                        return(NOEXCEPTION);
  93                }
  94        } 
  95        /*
  96         * check second operand for NaN's or infinity
  97         */
  98        if ((opnd2_exponent = Dbl_exponent(opnd2p1)) == DBL_INFINITY_EXPONENT) {
  99                if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
 100                        /*
 101                         * return first operand
 102                         */
 103                        Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
 104                        return(NOEXCEPTION);
 105                }
 106                /*
 107                 * is NaN; signaling or quiet?
 108                 */
 109                if (Dbl_isone_signaling(opnd2p1)) {
 110                        /* trap if INVALIDTRAP enabled */
 111                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
 112                        /* make NaN quiet */
 113                        Set_invalidflag();
 114                        Dbl_set_quiet(opnd2p1);
 115                }
 116                /*
 117                 * return quiet NaN
 118                 */
 119                Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
 120                return(NOEXCEPTION);
 121        }
 122        /*
 123         * check second operand for zero
 124         */
 125        if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
 126                /* invalid since second operand is zero */
 127                if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
 128                Set_invalidflag();
 129                Dbl_makequietnan(resultp1,resultp2);
 130                Dbl_copytoptr(resultp1,resultp2,dstptr);
 131                return(NOEXCEPTION);
 132        }
 133
 134        /* 
 135         * get sign of result
 136         */
 137        resultp1 = opnd1p1;  
 138
 139        /* 
 140         * check for denormalized operands
 141         */
 142        if (opnd1_exponent == 0) {
 143                /* check for zero */
 144                if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
 145                        Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
 146                        return(NOEXCEPTION);
 147                }
 148                /* normalize, then continue */
 149                opnd1_exponent = 1;
 150                Dbl_normalize(opnd1p1,opnd1p2,opnd1_exponent);
 151        }
 152        else {
 153                Dbl_clear_signexponent_set_hidden(opnd1p1);
 154        }
 155        if (opnd2_exponent == 0) {
 156                /* normalize, then continue */
 157                opnd2_exponent = 1;
 158                Dbl_normalize(opnd2p1,opnd2p2,opnd2_exponent);
 159        }
 160        else {
 161                Dbl_clear_signexponent_set_hidden(opnd2p1);
 162        }
 163
 164        /* find result exponent and divide step loop count */
 165        dest_exponent = opnd2_exponent - 1;
 166        stepcount = opnd1_exponent - opnd2_exponent;
 167
 168        /*
 169         * check for opnd1/opnd2 < 1
 170         */
 171        if (stepcount < 0) {
 172                /*
 173                 * check for opnd1/opnd2 > 1/2
 174                 *
 175                 * In this case n will round to 1, so 
 176                 *    r = opnd1 - opnd2 
 177                 */
 178                if (stepcount == -1 && 
 179                    Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
 180                        /* set sign */
 181                        Dbl_allp1(resultp1) = ~Dbl_allp1(resultp1);
 182                        /* align opnd2 with opnd1 */
 183                        Dbl_leftshiftby1(opnd2p1,opnd2p2); 
 184                        Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2,
 185                         opnd2p1,opnd2p2);
 186                        /* now normalize */
 187                        while (Dbl_iszero_hidden(opnd2p1)) {
 188                                Dbl_leftshiftby1(opnd2p1,opnd2p2);
 189                                dest_exponent--;
 190                        }
 191                        Dbl_set_exponentmantissa(resultp1,resultp2,opnd2p1,opnd2p2);
 192                        goto testforunderflow;
 193                }
 194                /*
 195                 * opnd1/opnd2 <= 1/2
 196                 *
 197                 * In this case n will round to zero, so 
 198                 *    r = opnd1
 199                 */
 200                Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2);
 201                dest_exponent = opnd1_exponent;
 202                goto testforunderflow;
 203        }
 204
 205        /*
 206         * Generate result
 207         *
 208         * Do iterative subtract until remainder is less than operand 2.
 209         */
 210        while (stepcount-- > 0 && (Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2))) {
 211                if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
 212                        Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2);
 213                }
 214                Dbl_leftshiftby1(opnd1p1,opnd1p2);
 215        }
 216        /*
 217         * Do last subtract, then determine which way to round if remainder 
 218         * is exactly 1/2 of opnd2 
 219         */
 220        if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
 221                Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2);
 222                roundup = TRUE;
 223        }
 224        if (stepcount > 0 || Dbl_iszero(opnd1p1,opnd1p2)) {
 225                /* division is exact, remainder is zero */
 226                Dbl_setzero_exponentmantissa(resultp1,resultp2);
 227                Dbl_copytoptr(resultp1,resultp2,dstptr);
 228                return(NOEXCEPTION);
 229        }
 230
 231        /* 
 232         * Check for cases where opnd1/opnd2 < n 
 233         *
 234         * In this case the result's sign will be opposite that of
 235         * opnd1.  The mantissa also needs some correction.
 236         */
 237        Dbl_leftshiftby1(opnd1p1,opnd1p2);
 238        if (Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
 239                Dbl_invert_sign(resultp1);
 240                Dbl_leftshiftby1(opnd2p1,opnd2p2);
 241                Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2,opnd1p1,opnd1p2);
 242        }
 243        /* check for remainder being exactly 1/2 of opnd2 */
 244        else if (Dbl_isequal(opnd1p1,opnd1p2,opnd2p1,opnd2p2) && roundup) { 
 245                Dbl_invert_sign(resultp1);
 246        }
 247
 248        /* normalize result's mantissa */
 249        while (Dbl_iszero_hidden(opnd1p1)) {
 250                dest_exponent--;
 251                Dbl_leftshiftby1(opnd1p1,opnd1p2);
 252        }
 253        Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2);
 254
 255        /* 
 256         * Test for underflow
 257         */
 258    testforunderflow:
 259        if (dest_exponent <= 0) {
 260                /* trap if UNDERFLOWTRAP enabled */
 261                if (Is_underflowtrap_enabled()) {
 262                        /*
 263                         * Adjust bias of result
 264                         */
 265                        Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
 266                        /* frem is always exact */
 267                        Dbl_copytoptr(resultp1,resultp2,dstptr);
 268                        return(UNDERFLOWEXCEPTION);
 269                }
 270                /*
 271                 * denormalize result or set to signed zero
 272                 */
 273                if (dest_exponent >= (1 - DBL_P)) {
 274                        Dbl_rightshift_exponentmantissa(resultp1,resultp2,
 275                         1-dest_exponent);
 276                }
 277                else {
 278                        Dbl_setzero_exponentmantissa(resultp1,resultp2);
 279                }
 280        }
 281        else Dbl_set_exponent(resultp1,dest_exponent);
 282        Dbl_copytoptr(resultp1,resultp2,dstptr);
 283        return(NOEXCEPTION);
 284}
 285