linux/arch/parisc/math-emu/sfrem.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/sfrem.c               $Revision: 1.1 $
  13 *
  14 *  Purpose:
  15 *      Single Precision Floating-point Remainder
  16 *
  17 *  External Interfaces:
  18 *      sgl_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 "sgl_float.h"
  32
  33/*
  34 *  Single Precision Floating-point Remainder
  35 */
  36
  37int
  38sgl_frem (sgl_floating_point * srcptr1, sgl_floating_point * srcptr2,
  39          sgl_floating_point * dstptr, unsigned int *status)
  40{
  41        register unsigned int opnd1, opnd2, result;
  42        register int opnd1_exponent, opnd2_exponent, dest_exponent, stepcount;
  43        register boolean roundup = FALSE;
  44
  45        opnd1 = *srcptr1;
  46        opnd2 = *srcptr2;
  47        /*
  48         * check first operand for NaN's or infinity
  49         */
  50        if ((opnd1_exponent = Sgl_exponent(opnd1)) == SGL_INFINITY_EXPONENT) {
  51                if (Sgl_iszero_mantissa(opnd1)) {
  52                        if (Sgl_isnotnan(opnd2)) {
  53                                /* invalid since first operand is infinity */
  54                                if (Is_invalidtrap_enabled()) 
  55                                        return(INVALIDEXCEPTION);
  56                                Set_invalidflag();
  57                                Sgl_makequietnan(result);
  58                                *dstptr = result;
  59                                return(NOEXCEPTION);
  60                        }
  61                }
  62                else {
  63                        /*
  64                         * is NaN; signaling or quiet?
  65                         */
  66                        if (Sgl_isone_signaling(opnd1)) {
  67                                /* trap if INVALIDTRAP enabled */
  68                                if (Is_invalidtrap_enabled()) 
  69                                        return(INVALIDEXCEPTION);
  70                                /* make NaN quiet */
  71                                Set_invalidflag();
  72                                Sgl_set_quiet(opnd1);
  73                        }
  74                        /* 
  75                         * is second operand a signaling NaN? 
  76                         */
  77                        else if (Sgl_is_signalingnan(opnd2)) {
  78                                /* trap if INVALIDTRAP enabled */
  79                                if (Is_invalidtrap_enabled()) 
  80                                        return(INVALIDEXCEPTION);
  81                                /* make NaN quiet */
  82                                Set_invalidflag();
  83                                Sgl_set_quiet(opnd2);
  84                                *dstptr = opnd2;
  85                                return(NOEXCEPTION);
  86                        }
  87                        /*
  88                         * return quiet NaN
  89                         */
  90                        *dstptr = opnd1;
  91                        return(NOEXCEPTION);
  92                }
  93        } 
  94        /*
  95         * check second operand for NaN's or infinity
  96         */
  97        if ((opnd2_exponent = Sgl_exponent(opnd2)) == SGL_INFINITY_EXPONENT) {
  98                if (Sgl_iszero_mantissa(opnd2)) {
  99                        /*
 100                         * return first operand
 101                         */
 102                        *dstptr = opnd1;
 103                        return(NOEXCEPTION);
 104                }
 105                /*
 106                 * is NaN; signaling or quiet?
 107                 */
 108                if (Sgl_isone_signaling(opnd2)) {
 109                        /* trap if INVALIDTRAP enabled */
 110                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
 111                        /* make NaN quiet */
 112                        Set_invalidflag();
 113                        Sgl_set_quiet(opnd2);
 114                }
 115                /*
 116                 * return quiet NaN
 117                 */
 118                *dstptr = opnd2;
 119                return(NOEXCEPTION);
 120        }
 121        /*
 122         * check second operand for zero
 123         */
 124        if (Sgl_iszero_exponentmantissa(opnd2)) {
 125                /* invalid since second operand is zero */
 126                if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
 127                Set_invalidflag();
 128                Sgl_makequietnan(result);
 129                *dstptr = result;
 130                return(NOEXCEPTION);
 131        }
 132
 133        /* 
 134         * get sign of result
 135         */
 136        result = opnd1;  
 137
 138        /* 
 139         * check for denormalized operands
 140         */
 141        if (opnd1_exponent == 0) {
 142                /* check for zero */
 143                if (Sgl_iszero_mantissa(opnd1)) {
 144                        *dstptr = opnd1;
 145                        return(NOEXCEPTION);
 146                }
 147                /* normalize, then continue */
 148                opnd1_exponent = 1;
 149                Sgl_normalize(opnd1,opnd1_exponent);
 150        }
 151        else {
 152                Sgl_clear_signexponent_set_hidden(opnd1);
 153        }
 154        if (opnd2_exponent == 0) {
 155                /* normalize, then continue */
 156                opnd2_exponent = 1;
 157                Sgl_normalize(opnd2,opnd2_exponent);
 158        }
 159        else {
 160                Sgl_clear_signexponent_set_hidden(opnd2);
 161        }
 162
 163        /* find result exponent and divide step loop count */
 164        dest_exponent = opnd2_exponent - 1;
 165        stepcount = opnd1_exponent - opnd2_exponent;
 166
 167        /*
 168         * check for opnd1/opnd2 < 1
 169         */
 170        if (stepcount < 0) {
 171                /*
 172                 * check for opnd1/opnd2 > 1/2
 173                 *
 174                 * In this case n will round to 1, so 
 175                 *    r = opnd1 - opnd2 
 176                 */
 177                if (stepcount == -1 && Sgl_isgreaterthan(opnd1,opnd2)) {
 178                        Sgl_all(result) = ~Sgl_all(result);   /* set sign */
 179                        /* align opnd2 with opnd1 */
 180                        Sgl_leftshiftby1(opnd2); 
 181                        Sgl_subtract(opnd2,opnd1,opnd2);
 182                        /* now normalize */
 183                        while (Sgl_iszero_hidden(opnd2)) {
 184                                Sgl_leftshiftby1(opnd2);
 185                                dest_exponent--;
 186                        }
 187                        Sgl_set_exponentmantissa(result,opnd2);
 188                        goto testforunderflow;
 189                }
 190                /*
 191                 * opnd1/opnd2 <= 1/2
 192                 *
 193                 * In this case n will round to zero, so 
 194                 *    r = opnd1
 195                 */
 196                Sgl_set_exponentmantissa(result,opnd1);
 197                dest_exponent = opnd1_exponent;
 198                goto testforunderflow;
 199        }
 200
 201        /*
 202         * Generate result
 203         *
 204         * Do iterative subtract until remainder is less than operand 2.
 205         */
 206        while (stepcount-- > 0 && Sgl_all(opnd1)) {
 207                if (Sgl_isnotlessthan(opnd1,opnd2))
 208                        Sgl_subtract(opnd1,opnd2,opnd1);
 209                Sgl_leftshiftby1(opnd1);
 210        }
 211        /*
 212         * Do last subtract, then determine which way to round if remainder 
 213         * is exactly 1/2 of opnd2 
 214         */
 215        if (Sgl_isnotlessthan(opnd1,opnd2)) {
 216                Sgl_subtract(opnd1,opnd2,opnd1);
 217                roundup = TRUE;
 218        }
 219        if (stepcount > 0 || Sgl_iszero(opnd1)) {
 220                /* division is exact, remainder is zero */
 221                Sgl_setzero_exponentmantissa(result);
 222                *dstptr = result;
 223                return(NOEXCEPTION);
 224        }
 225
 226        /* 
 227         * Check for cases where opnd1/opnd2 < n 
 228         *
 229         * In this case the result's sign will be opposite that of
 230         * opnd1.  The mantissa also needs some correction.
 231         */
 232        Sgl_leftshiftby1(opnd1);
 233        if (Sgl_isgreaterthan(opnd1,opnd2)) {
 234                Sgl_invert_sign(result);
 235                Sgl_subtract((opnd2<<1),opnd1,opnd1);
 236        }
 237        /* check for remainder being exactly 1/2 of opnd2 */
 238        else if (Sgl_isequal(opnd1,opnd2) && roundup) { 
 239                Sgl_invert_sign(result);
 240        }
 241
 242        /* normalize result's mantissa */
 243        while (Sgl_iszero_hidden(opnd1)) {
 244                dest_exponent--;
 245                Sgl_leftshiftby1(opnd1);
 246        }
 247        Sgl_set_exponentmantissa(result,opnd1);
 248
 249        /* 
 250         * Test for underflow
 251         */
 252    testforunderflow:
 253        if (dest_exponent <= 0) {
 254                /* trap if UNDERFLOWTRAP enabled */
 255                if (Is_underflowtrap_enabled()) {
 256                        /*
 257                         * Adjust bias of result
 258                         */
 259                        Sgl_setwrapped_exponent(result,dest_exponent,unfl);
 260                        *dstptr = result;
 261                        /* frem is always exact */
 262                        return(UNDERFLOWEXCEPTION);
 263                }
 264                /*
 265                 * denormalize result or set to signed zero
 266                 */
 267                if (dest_exponent >= (1 - SGL_P)) {
 268                        Sgl_rightshift_exponentmantissa(result,1-dest_exponent);
 269                }
 270                else {
 271                        Sgl_setzero_exponentmantissa(result);
 272                }
 273        }
 274        else Sgl_set_exponent(result,dest_exponent);
 275        *dstptr = result;
 276        return(NOEXCEPTION);
 277}
 278