[BACK]Return to dfsub.c CVS log [TXT][DIR] Up to [local] / sys / arch / hppa / spmath

Annotation of sys/arch/hppa/spmath/dfsub.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: dfsub.c,v 1.7 2002/11/29 09:27:34 deraadt Exp $       */
        !             2: /*
        !             3:   (c) Copyright 1986 HEWLETT-PACKARD COMPANY
        !             4:   To anyone who acknowledges that this file is provided "AS IS"
        !             5:   without any express or implied warranty:
        !             6:       permission to use, copy, modify, and distribute this file
        !             7:   for any purpose is hereby granted without fee, provided that
        !             8:   the above copyright notice and this notice appears in all
        !             9:   copies, and that the name of Hewlett-Packard Company not be
        !            10:   used in advertising or publicity pertaining to distribution
        !            11:   of the software without specific, written prior permission.
        !            12:   Hewlett-Packard Company makes no representations about the
        !            13:   suitability of this software for any purpose.
        !            14: */
        !            15: /* @(#)dfsub.c: Revision: 2.8.88.1 Date: 93/12/07 15:05:48 */
        !            16:
        !            17: #include "float.h"
        !            18: #include "dbl_float.h"
        !            19:
        !            20: /*
        !            21:  * Double_subtract: subtract two double precision values.
        !            22:  */
        !            23: int
        !            24: dbl_fsub(leftptr, rightptr, dstptr, status)
        !            25:     dbl_floating_point *leftptr, *rightptr, *dstptr;
        !            26:     unsigned int *status;
        !            27: {
        !            28:     register unsigned int signless_upper_left, signless_upper_right, save;
        !            29:     register unsigned int leftp1, leftp2, rightp1, rightp2, extent;
        !            30:     register unsigned int resultp1 = 0, resultp2 = 0;
        !            31:
        !            32:     register int result_exponent, right_exponent, diff_exponent;
        !            33:     register int sign_save, jumpsize;
        !            34:     register int inexact = FALSE, underflowtrap;
        !            35:
        !            36:     /* Create local copies of the numbers */
        !            37:     Dbl_copyfromptr(leftptr,leftp1,leftp2);
        !            38:     Dbl_copyfromptr(rightptr,rightp1,rightp2);
        !            39:
        !            40:     /* A zero "save" helps discover equal operands (for later),  *
        !            41:      * and is used in swapping operands (if needed).        */
        !            42:     Dbl_xortointp1(leftp1,rightp1,/*to*/save);
        !            43:
        !            44:     /*
        !            45:      * check first operand for NaN's or infinity
        !            46:      */
        !            47:     if ((result_exponent = Dbl_exponent(leftp1)) == DBL_INFINITY_EXPONENT)
        !            48:        {
        !            49:        if (Dbl_iszero_mantissa(leftp1,leftp2))
        !            50:            {
        !            51:            if (Dbl_isnotnan(rightp1,rightp2))
        !            52:                {
        !            53:                if (Dbl_isinfinity(rightp1,rightp2) && save==0)
        !            54:                    {
        !            55:                    /*
        !            56:                     * invalid since operands are same signed infinity's
        !            57:                     */
        !            58:                    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
        !            59:                    Set_invalidflag();
        !            60:                    Dbl_makequietnan(resultp1,resultp2);
        !            61:                    Dbl_copytoptr(resultp1,resultp2,dstptr);
        !            62:                    return(NOEXCEPTION);
        !            63:                    }
        !            64:                /*
        !            65:                 * return infinity
        !            66:                 */
        !            67:                Dbl_copytoptr(leftp1,leftp2,dstptr);
        !            68:                return(NOEXCEPTION);
        !            69:                }
        !            70:            }
        !            71:        else
        !            72:            {
        !            73:            /*
        !            74:             * is NaN; signaling or quiet?
        !            75:             */
        !            76:            if (Dbl_isone_signaling(leftp1))
        !            77:                {
        !            78:                /* trap if INVALIDTRAP enabled */
        !            79:                if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
        !            80:                /* make NaN quiet */
        !            81:                Set_invalidflag();
        !            82:                Dbl_set_quiet(leftp1);
        !            83:                }
        !            84:            /*
        !            85:             * is second operand a signaling NaN?
        !            86:             */
        !            87:            else if (Dbl_is_signalingnan(rightp1))
        !            88:                {
        !            89:                /* trap if INVALIDTRAP enabled */
        !            90:                if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
        !            91:                /* make NaN quiet */
        !            92:                Set_invalidflag();
        !            93:                Dbl_set_quiet(rightp1);
        !            94:                Dbl_copytoptr(rightp1,rightp2,dstptr);
        !            95:                return(NOEXCEPTION);
        !            96:                }
        !            97:            /*
        !            98:             * return quiet NaN
        !            99:             */
        !           100:            Dbl_copytoptr(leftp1,leftp2,dstptr);
        !           101:            return(NOEXCEPTION);
        !           102:            }
        !           103:        } /* End left NaN or Infinity processing */
        !           104:     /*
        !           105:      * check second operand for NaN's or infinity
        !           106:      */
        !           107:     if (Dbl_isinfinity_exponent(rightp1))
        !           108:        {
        !           109:        if (Dbl_iszero_mantissa(rightp1,rightp2))
        !           110:            {
        !           111:            /* return infinity */
        !           112:            Dbl_invert_sign(rightp1);
        !           113:            Dbl_copytoptr(rightp1,rightp2,dstptr);
        !           114:            return(NOEXCEPTION);
        !           115:            }
        !           116:        /*
        !           117:         * is NaN; signaling or quiet?
        !           118:         */
        !           119:        if (Dbl_isone_signaling(rightp1))
        !           120:            {
        !           121:            /* trap if INVALIDTRAP enabled */
        !           122:            if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
        !           123:            /* make NaN quiet */
        !           124:            Set_invalidflag();
        !           125:            Dbl_set_quiet(rightp1);
        !           126:            }
        !           127:        /*
        !           128:         * return quiet NaN
        !           129:         */
        !           130:        Dbl_copytoptr(rightp1,rightp2,dstptr);
        !           131:        return(NOEXCEPTION);
        !           132:        } /* End right NaN or Infinity processing */
        !           133:
        !           134:     /* Invariant: Must be dealing with finite numbers */
        !           135:
        !           136:     /* Compare operands by removing the sign */
        !           137:     Dbl_copytoint_exponentmantissap1(leftp1,signless_upper_left);
        !           138:     Dbl_copytoint_exponentmantissap1(rightp1,signless_upper_right);
        !           139:
        !           140:     /* sign difference selects add or sub operation. */
        !           141:     if(Dbl_ismagnitudeless(leftp2,rightp2,signless_upper_left,signless_upper_right))
        !           142:        {
        !           143:        /* Set the left operand to the larger one by XOR swap *
        !           144:         *  First finish the first word using "save"      */
        !           145:        Dbl_xorfromintp1(save,rightp1,/*to*/rightp1);
        !           146:        Dbl_xorfromintp1(save,leftp1,/*to*/leftp1);
        !           147:        Dbl_swap_lower(leftp2,rightp2);
        !           148:        result_exponent = Dbl_exponent(leftp1);
        !           149:        Dbl_invert_sign(leftp1);
        !           150:        }
        !           151:     /* Invariant:  left is not smaller than right. */
        !           152:
        !           153:     if((right_exponent = Dbl_exponent(rightp1)) == 0)
        !           154:        {
        !           155:        /* Denormalized operands.  First look for zeroes */
        !           156:        if(Dbl_iszero_mantissa(rightp1,rightp2))
        !           157:            {
        !           158:            /* right is zero */
        !           159:            if(Dbl_iszero_exponentmantissa(leftp1,leftp2))
        !           160:                {
        !           161:                /* Both operands are zeros */
        !           162:                Dbl_invert_sign(rightp1);
        !           163:                if(Is_rounding_mode(ROUNDMINUS))
        !           164:                    {
        !           165:                    Dbl_or_signs(leftp1,/*with*/rightp1);
        !           166:                    }
        !           167:                else
        !           168:                    {
        !           169:                    Dbl_and_signs(leftp1,/*with*/rightp1);
        !           170:                    }
        !           171:                }
        !           172:            else
        !           173:                {
        !           174:                /* Left is not a zero and must be the result.  Trapped
        !           175:                 * underflows are signaled if left is denormalized.  Result
        !           176:                 * is always exact. */
        !           177:                if( (result_exponent == 0) && Is_underflowtrap_enabled() )
        !           178:                    {
        !           179:                    /* need to normalize results mantissa */
        !           180:                    sign_save = Dbl_signextendedsign(leftp1);
        !           181:                    Dbl_leftshiftby1(leftp1,leftp2);
        !           182:                    Dbl_normalize(leftp1,leftp2,result_exponent);
        !           183:                    Dbl_set_sign(leftp1,/*using*/sign_save);
        !           184:                    Dbl_setwrapped_exponent(leftp1,result_exponent,unfl);
        !           185:                    Dbl_copytoptr(leftp1,leftp2,dstptr);
        !           186:                    /* inexact = FALSE */
        !           187:                    return(UNDERFLOWEXCEPTION);
        !           188:                    }
        !           189:                }
        !           190:            Dbl_copytoptr(leftp1,leftp2,dstptr);
        !           191:            return(NOEXCEPTION);
        !           192:            }
        !           193:
        !           194:        /* Neither are zeroes */
        !           195:        Dbl_clear_sign(rightp1);        /* Exponent is already cleared */
        !           196:        if(result_exponent == 0 )
        !           197:            {
        !           198:            /* Both operands are denormalized.  The result must be exact
        !           199:             * and is simply calculated.  A sum could become normalized and a
        !           200:             * difference could cancel to a true zero. */
        !           201:            if( (/*signed*/int) save >= 0 )
        !           202:                {
        !           203:                Dbl_subtract(leftp1,leftp2,/*minus*/rightp1,rightp2,
        !           204:                 /*into*/resultp1,resultp2);
        !           205:                if(Dbl_iszero_mantissa(resultp1,resultp2))
        !           206:                    {
        !           207:                    if(Is_rounding_mode(ROUNDMINUS))
        !           208:                        {
        !           209:                        Dbl_setone_sign(resultp1);
        !           210:                        }
        !           211:                    else
        !           212:                        {
        !           213:                        Dbl_setzero_sign(resultp1);
        !           214:                        }
        !           215:                    Dbl_copytoptr(resultp1,resultp2,dstptr);
        !           216:                    return(NOEXCEPTION);
        !           217:                    }
        !           218:                }
        !           219:            else
        !           220:                {
        !           221:                Dbl_addition(leftp1,leftp2,rightp1,rightp2,
        !           222:                 /*into*/resultp1,resultp2);
        !           223:                if(Dbl_isone_hidden(resultp1))
        !           224:                    {
        !           225:                    Dbl_copytoptr(resultp1,resultp2,dstptr);
        !           226:                    return(NOEXCEPTION);
        !           227:                    }
        !           228:                }
        !           229:            if(Is_underflowtrap_enabled())
        !           230:                {
        !           231:                /* need to normalize result */
        !           232:                sign_save = Dbl_signextendedsign(resultp1);
        !           233:                Dbl_leftshiftby1(resultp1,resultp2);
        !           234:                Dbl_normalize(resultp1,resultp2,result_exponent);
        !           235:                Dbl_set_sign(resultp1,/*using*/sign_save);
        !           236:                Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
        !           237:                Dbl_copytoptr(resultp1,resultp2,dstptr);
        !           238:                /* inexact = FALSE */
        !           239:                return(UNDERFLOWEXCEPTION);
        !           240:                }
        !           241:            Dbl_copytoptr(resultp1,resultp2,dstptr);
        !           242:            return(NOEXCEPTION);
        !           243:            }
        !           244:        right_exponent = 1;     /* Set exponent to reflect different bias
        !           245:                                 * with denomalized numbers. */
        !           246:        }
        !           247:     else
        !           248:        {
        !           249:        Dbl_clear_signexponent_set_hidden(rightp1);
        !           250:        }
        !           251:     Dbl_clear_exponent_set_hidden(leftp1);
        !           252:     diff_exponent = result_exponent - right_exponent;
        !           253:
        !           254:     /*
        !           255:      * Special case alignment of operands that would force alignment
        !           256:      * beyond the extent of the extension.  A further optimization
        !           257:      * could special case this but only reduces the path length for this
        !           258:      * infrequent case.
        !           259:      */
        !           260:     if(diff_exponent > DBL_THRESHOLD)
        !           261:        {
        !           262:        diff_exponent = DBL_THRESHOLD;
        !           263:        }
        !           264:
        !           265:     /* Align right operand by shifting to right */
        !           266:     Dbl_right_align(/*operand*/rightp1,rightp2,/*shifted by*/diff_exponent,
        !           267:      /*and lower to*/extent);
        !           268:
        !           269:     /* Treat sum and difference of the operands separately. */
        !           270:     if( (/*signed*/int) save >= 0 )
        !           271:        {
        !           272:        /*
        !           273:         * Difference of the two operands.  Their can be no overflow.  A
        !           274:         * borrow can occur out of the hidden bit and force a post
        !           275:         * normalization phase.
        !           276:         */
        !           277:        Dbl_subtract_withextension(leftp1,leftp2,/*minus*/rightp1,rightp2,
        !           278:         /*with*/extent,/*into*/resultp1,resultp2);
        !           279:        if(Dbl_iszero_hidden(resultp1))
        !           280:            {
        !           281:            /* Handle normalization */
        !           282:            /* A straight forward algorithm would now shift the result
        !           283:             * and extension left until the hidden bit becomes one.  Not
        !           284:             * all of the extension bits need participate in the shift.
        !           285:             * Only the two most significant bits (round and guard) are
        !           286:             * needed.  If only a single shift is needed then the guard
        !           287:             * bit becomes a significant low order bit and the extension
        !           288:             * must participate in the rounding.  If more than a single
        !           289:             * shift is needed, then all bits to the right of the guard
        !           290:             * bit are zeros, and the guard bit may or may not be zero. */
        !           291:            sign_save = Dbl_signextendedsign(resultp1);
        !           292:            Dbl_leftshiftby1_withextent(resultp1,resultp2,extent,resultp1,resultp2);
        !           293:
        !           294:            /* Need to check for a zero result.  The sign and exponent
        !           295:             * fields have already been zeroed.  The more efficient test
        !           296:             * of the full object can be used.
        !           297:             */
        !           298:            if(Dbl_iszero(resultp1,resultp2))
        !           299:                /* Must have been "x-x" or "x+(-x)". */
        !           300:                {
        !           301:                if(Is_rounding_mode(ROUNDMINUS)) Dbl_setone_sign(resultp1);
        !           302:                Dbl_copytoptr(resultp1,resultp2,dstptr);
        !           303:                return(NOEXCEPTION);
        !           304:                }
        !           305:            result_exponent--;
        !           306:            /* Look to see if normalization is finished. */
        !           307:            if(Dbl_isone_hidden(resultp1)) {
        !           308:                if(result_exponent==0) {
        !           309:                    /* Denormalized, exponent should be zero.  Left operand *
        !           310:                     * was normalized, so extent (guard, round) was zero    */
        !           311:                    goto underflow;
        !           312:                } else {
        !           313:                        /* No further normalization is needed. */
        !           314:                        Dbl_set_sign(resultp1,/*using*/sign_save);
        !           315:                        Ext_leftshiftby1(extent);
        !           316:                        goto round;
        !           317:                }
        !           318:            }
        !           319:
        !           320:            /* Check for denormalized, exponent should be zero.  Left    *
        !           321:             * operand was normalized, so extent (guard, round) was zero */
        !           322:            if(!(underflowtrap = Is_underflowtrap_enabled()) &&
        !           323:               result_exponent==0) goto underflow;
        !           324:
        !           325:            /* Shift extension to complete one bit of normalization and
        !           326:             * update exponent. */
        !           327:            Ext_leftshiftby1(extent);
        !           328:
        !           329:            /* Discover first one bit to determine shift amount.  Use a
        !           330:             * modified binary search.  We have already shifted the result
        !           331:             * one position right and still not found a one so the remainder
        !           332:             * of the extension must be zero and simplifies rounding. */
        !           333:            /* Scan bytes */
        !           334:            while(Dbl_iszero_hiddenhigh7mantissa(resultp1))
        !           335:                {
        !           336:                Dbl_leftshiftby8(resultp1,resultp2);
        !           337:                if((result_exponent -= 8) <= 0  && !underflowtrap)
        !           338:                    goto underflow;
        !           339:                }
        !           340:            /* Now narrow it down to the nibble */
        !           341:            if(Dbl_iszero_hiddenhigh3mantissa(resultp1))
        !           342:                {
        !           343:                /* The lower nibble contains the normalizing one */
        !           344:                Dbl_leftshiftby4(resultp1,resultp2);
        !           345:                if((result_exponent -= 4) <= 0 && !underflowtrap)
        !           346:                    goto underflow;
        !           347:                }
        !           348:            /* Select case were first bit is set (already normalized)
        !           349:             * otherwise select the proper shift. */
        !           350:            if((jumpsize = Dbl_hiddenhigh3mantissa(resultp1)) > 7)
        !           351:                {
        !           352:                /* Already normalized */
        !           353:                if(result_exponent <= 0) goto underflow;
        !           354:                Dbl_set_sign(resultp1,/*using*/sign_save);
        !           355:                Dbl_set_exponent(resultp1,/*using*/result_exponent);
        !           356:                Dbl_copytoptr(resultp1,resultp2,dstptr);
        !           357:                return(NOEXCEPTION);
        !           358:                }
        !           359:            Dbl_sethigh4bits(resultp1,/*using*/sign_save);
        !           360:            switch(jumpsize)
        !           361:                {
        !           362:                case 1:
        !           363:                    {
        !           364:                    Dbl_leftshiftby3(resultp1,resultp2);
        !           365:                    result_exponent -= 3;
        !           366:                    break;
        !           367:                    }
        !           368:                case 2:
        !           369:                case 3:
        !           370:                    {
        !           371:                    Dbl_leftshiftby2(resultp1,resultp2);
        !           372:                    result_exponent -= 2;
        !           373:                    break;
        !           374:                    }
        !           375:                case 4:
        !           376:                case 5:
        !           377:                case 6:
        !           378:                case 7:
        !           379:                    {
        !           380:                    Dbl_leftshiftby1(resultp1,resultp2);
        !           381:                    result_exponent -= 1;
        !           382:                    break;
        !           383:                    }
        !           384:                }
        !           385:            if(result_exponent > 0)
        !           386:                {
        !           387:                Dbl_set_exponent(resultp1,/*using*/result_exponent);
        !           388:                Dbl_copytoptr(resultp1,resultp2,dstptr);
        !           389:                return(NOEXCEPTION);            /* Sign bit is already set */
        !           390:                }
        !           391:            /* Fixup potential underflows */
        !           392:          underflow:
        !           393:            if(Is_underflowtrap_enabled())
        !           394:                {
        !           395:                Dbl_set_sign(resultp1,sign_save);
        !           396:                Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
        !           397:                Dbl_copytoptr(resultp1,resultp2,dstptr);
        !           398:                /* inexact = FALSE */
        !           399:                return(UNDERFLOWEXCEPTION);
        !           400:                }
        !           401:            /*
        !           402:             * Since we cannot get an inexact denormalized result,
        !           403:             * we can now return.
        !           404:             */
        !           405:            Dbl_fix_overshift(resultp1,resultp2,(1-result_exponent),extent);
        !           406:            Dbl_clear_signexponent(resultp1);
        !           407:            Dbl_set_sign(resultp1,sign_save);
        !           408:            Dbl_copytoptr(resultp1,resultp2,dstptr);
        !           409:            return(NOEXCEPTION);
        !           410:            } /* end if(hidden...)... */
        !           411:        /* Fall through and round */
        !           412:        } /* end if(save >= 0)... */
        !           413:     else
        !           414:        {
        !           415:        /* Subtract magnitudes */
        !           416:        Dbl_addition(leftp1,leftp2,rightp1,rightp2,/*to*/resultp1,resultp2);
        !           417:        if(Dbl_isone_hiddenoverflow(resultp1))
        !           418:            {
        !           419:            /* Prenormalization required. */
        !           420:            Dbl_rightshiftby1_withextent(resultp2,extent,extent);
        !           421:            Dbl_arithrightshiftby1(resultp1,resultp2);
        !           422:            result_exponent++;
        !           423:            } /* end if hiddenoverflow... */
        !           424:        } /* end else ...subtract magnitudes... */
        !           425:
        !           426:     /* Round the result.  If the extension is all zeros,then the result is
        !           427:      * exact.  Otherwise round in the correct direction.  No underflow is
        !           428:      * possible. If a postnormalization is necessary, then the mantissa is
        !           429:      * all zeros so no shift is needed. */
        !           430:   round:
        !           431:     if(Ext_isnotzero(extent))
        !           432:        {
        !           433:        inexact = TRUE;
        !           434:        switch(Rounding_mode())
        !           435:            {
        !           436:            case ROUNDNEAREST: /* The default. */
        !           437:            if(Ext_isone_sign(extent))
        !           438:                {
        !           439:                /* at least 1/2 ulp */
        !           440:                if(Ext_isnotzero_lower(extent)  ||
        !           441:                  Dbl_isone_lowmantissap2(resultp2))
        !           442:                    {
        !           443:                    /* either exactly half way and odd or more than 1/2ulp */
        !           444:                    Dbl_increment(resultp1,resultp2);
        !           445:                    }
        !           446:                }
        !           447:            break;
        !           448:
        !           449:            case ROUNDPLUS:
        !           450:            if(Dbl_iszero_sign(resultp1))
        !           451:                {
        !           452:                /* Round up positive results */
        !           453:                Dbl_increment(resultp1,resultp2);
        !           454:                }
        !           455:            break;
        !           456:
        !           457:            case ROUNDMINUS:
        !           458:            if(Dbl_isone_sign(resultp1))
        !           459:                {
        !           460:                /* Round down negative results */
        !           461:                Dbl_increment(resultp1,resultp2);
        !           462:                }
        !           463:
        !           464:            case ROUNDZERO:;
        !           465:            /* truncate is simple */
        !           466:            } /* end switch... */
        !           467:        if(Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
        !           468:        }
        !           469:     if(result_exponent == DBL_INFINITY_EXPONENT)
        !           470:        {
        !           471:        /* Overflow */
        !           472:        if(Is_overflowtrap_enabled())
        !           473:            {
        !           474:            Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
        !           475:            Dbl_copytoptr(resultp1,resultp2,dstptr);
        !           476:            if (inexact) {
        !           477:                if (Is_inexacttrap_enabled())
        !           478:                    return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
        !           479:                else
        !           480:                    Set_inexactflag();
        !           481:            }
        !           482:            return(OVERFLOWEXCEPTION);
        !           483:            }
        !           484:        else
        !           485:            {
        !           486:            inexact = TRUE;
        !           487:            Set_overflowflag();
        !           488:            Dbl_setoverflow(resultp1,resultp2);
        !           489:            }
        !           490:        }
        !           491:     else Dbl_set_exponent(resultp1,result_exponent);
        !           492:     Dbl_copytoptr(resultp1,resultp2,dstptr);
        !           493:     if(inexact) {
        !           494:        if(Is_inexacttrap_enabled())
        !           495:                return(INEXACTEXCEPTION);
        !           496:        else
        !           497:                Set_inexactflag();
        !           498:     }
        !           499:     return(NOEXCEPTION);
        !           500: }

CVSweb