Changeset c67aff2 in mainline for uspace/lib/softfloat/generic/div.c


Ignore:
Timestamp:
2011-08-06T07:04:50Z (13 years ago)
Author:
Petr Koupy <petr.koupy@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
d3e241a, e0e922d
Parents:
9a6034a
Message:

Quadruple-precision softfloat, coding style improvements. Details below…

Highlights:

  • completed double-precision support
  • added quadruple-precision support
  • added SPARC quadruple-precision wrappers
  • added doxygen comments
  • corrected and unified coding style

Current state of the softfloat library:

Support for single, double and quadruple precision is currently almost complete (apart from power, square root, complex multiplication and complex division) and provides the same set of features (i.e. the support for all three precisions is now aligned). In order to extend softfloat library consistently, addition of quadruple precision was done in the same spirit as already existing single and double precision written by Josef Cejka in 2006 - that is relaxed standard-compliance for corner cases while mission-critical code sections heavily inspired by the widely used softfloat library written by John R. Hauser (although I personally think it would be more appropriate for HelenOS to use something less optimized, shorter and more readable).

Most of the quadruple-precision code is just an adapted double-precision code to work on 128-bit variables. That means if there is TODO, FIXME or some defect in single or double-precision code, it is most likely also in the quadruple-precision code. Please note that quadruple-precision functions are currently not tested - it is challenging task for itself, especially when the ports that use them are either not finished (mips64) or badly supported by simulators (sparc64). To test whole softfloat library, one would probably have to either write very non-trivial native tester, or use some existing one (e.g. TestFloat from J. R. Hauser) and port it to HelenOS (or rip the softfloat library out of HelenOS and test it on a host system). At the time of writing this, the code dependent on quadruple-precision functions (on mips64 and sparc64) is just a libposix strtold() function (and its callers, most notably scanf backend).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/softfloat/generic/div.c

    r9a6034a rc67aff2  
    11/*
    22 * Copyright (c) 2005 Josef Cejka
     3 * Copyright (c) 2011 Petr Koupy
    34 * All rights reserved.
    45 *
     
    3031 * @{
    3132 */
    32 /** @file
     33/** @file Division functions.
    3334 */
    3435
     
    4041#include <common.h>
    4142
     43/**
     44 * Divide two single-precision floats.
     45 *
     46 * @param a Nominator.
     47 * @param b Denominator.
     48 * @return Result of division.
     49 */
    4250float32 divFloat32(float32 a, float32 b)
    4351{
     
    100108                return result;
    101109        }
    102 
    103110       
    104111        afrac = a.parts.fraction;
     
    110117        if (aexp == 0) {
    111118                if (afrac == 0) {
    112                 result.parts.exp = 0;
    113                 result.parts.fraction = 0;
    114                 return result;
    115                 }
     119                        result.parts.exp = 0;
     120                        result.parts.fraction = 0;
     121                        return result;
     122                }
     123
    116124                /* normalize it*/
    117                
    118125                afrac <<= 1;
    119                         /* afrac is nonzero => it must stop */ 
    120                 while (! (afrac & FLOAT32_HIDDEN_BIT_MASK) ) {
     126                /* afrac is nonzero => it must stop */ 
     127                while (!(afrac & FLOAT32_HIDDEN_BIT_MASK)) {
    121128                        afrac <<= 1;
    122129                        aexp--;
     
    126133        if (bexp == 0) {
    127134                bfrac <<= 1;
    128                         /* bfrac is nonzero => it must stop */ 
    129                 while (! (bfrac & FLOAT32_HIDDEN_BIT_MASK) ) {
     135                /* bfrac is nonzero => it must stop */ 
     136                while (!(bfrac & FLOAT32_HIDDEN_BIT_MASK)) {
    130137                        bfrac <<= 1;
    131138                        bexp--;
     
    133140        }
    134141
    135         afrac = (afrac | FLOAT32_HIDDEN_BIT_MASK ) << (32 - FLOAT32_FRACTION_SIZE - 1 );
    136         bfrac = (bfrac | FLOAT32_HIDDEN_BIT_MASK ) << (32 - FLOAT32_FRACTION_SIZE );
    137 
    138         if ( bfrac <= (afrac << 1) ) {
     142        afrac = (afrac | FLOAT32_HIDDEN_BIT_MASK) << (32 - FLOAT32_FRACTION_SIZE - 1);
     143        bfrac = (bfrac | FLOAT32_HIDDEN_BIT_MASK) << (32 - FLOAT32_FRACTION_SIZE);
     144
     145        if (bfrac <= (afrac << 1)) {
    139146                afrac >>= 1;
    140147                aexp++;
     
    144151       
    145152        cfrac = (afrac << 32) / bfrac;
    146         if ((  cfrac & 0x3F ) == 0) {
    147                 cfrac |= ( bfrac * cfrac != afrac << 32 );
     153        if ((cfrac & 0x3F) == 0) {
     154                cfrac |= (bfrac * cfrac != afrac << 32);
    148155        }
    149156       
     
    151158       
    152159        /* find first nonzero digit and shift result and detect possibly underflow */
    153         while ((cexp > 0) && (cfrac) && (!(cfrac & (FLOAT32_HIDDEN_BIT_MASK << 7 )))) {
     160        while ((cexp > 0) && (cfrac) && (!(cfrac & (FLOAT32_HIDDEN_BIT_MASK << 7)))) {
    154161                cexp--;
    155162                cfrac <<= 1;
    156                         /* TODO: fix underflow */
    157         };
     163                /* TODO: fix underflow */
     164        }
    158165       
    159166        cfrac += (0x1 << 6); /* FIXME: 7 is not sure*/
     
    162169                ++cexp;
    163170                cfrac >>= 1;
    164                 }       
     171        }       
    165172
    166173        /* check overflow */
    167         if (cexp >= FLOAT32_MAX_EXPONENT ) {
     174        if (cexp >= FLOAT32_MAX_EXPONENT) {
    168175                /* FIXME: overflow, return infinity */
    169176                result.parts.exp = FLOAT32_MAX_EXPONENT;
     
    181188                cfrac >>= 1;
    182189                while (cexp < 0) {
    183                         cexp ++;
     190                        cexp++;
    184191                        cfrac >>= 1;
    185                 }
    186                
     192                }       
    187193        } else {
    188                 result.parts.exp = (uint32_t)cexp;
     194                result.parts.exp = (uint32_t) cexp;
    189195        }
    190196       
     
    194200}
    195201
     202/**
     203 * Divide two double-precision floats.
     204 *
     205 * @param a Nominator.
     206 * @param b Denominator.
     207 * @return Result of division.
     208 */
    196209float64 divFloat64(float64 a, float64 b)
    197210{
     
    200213        uint64_t afrac, bfrac, cfrac;
    201214        uint64_t remlo, remhi;
     215        uint64_t tmplo, tmphi;
    202216       
    203217        result.parts.sign = a.parts.sign ^ b.parts.sign;
    204218       
    205219        if (isFloat64NaN(a)) {
    206                
    207220                if (isFloat64SigNaN(b)) {
    208221                        /*FIXME: SigNaN*/
     
    262275        }
    263276
    264        
    265277        afrac = a.parts.fraction;
    266278        aexp = a.parts.exp;
     
    275287                        return result;
    276288                }
     289
    277290                /* normalize it*/
    278                
    279291                aexp++;
    280                         /* afrac is nonzero => it must stop */ 
    281                 while (! (afrac & FLOAT64_HIDDEN_BIT_MASK) ) {
     292                /* afrac is nonzero => it must stop */ 
     293                while (!(afrac & FLOAT64_HIDDEN_BIT_MASK)) {
    282294                        afrac <<= 1;
    283295                        aexp--;
     
    287299        if (bexp == 0) {
    288300                bexp++;
    289                         /* bfrac is nonzero => it must stop */ 
    290                 while (! (bfrac & FLOAT64_HIDDEN_BIT_MASK) ) {
     301                /* bfrac is nonzero => it must stop */ 
     302                while (!(bfrac & FLOAT64_HIDDEN_BIT_MASK)) {
    291303                        bfrac <<= 1;
    292304                        bexp--;
     
    294306        }
    295307
    296         afrac = (afrac | FLOAT64_HIDDEN_BIT_MASK ) << (64 - FLOAT64_FRACTION_SIZE - 2 );
    297         bfrac = (bfrac | FLOAT64_HIDDEN_BIT_MASK ) << (64 - FLOAT64_FRACTION_SIZE - 1);
    298 
    299         if ( bfrac <= (afrac << 1) ) {
     308        afrac = (afrac | FLOAT64_HIDDEN_BIT_MASK) << (64 - FLOAT64_FRACTION_SIZE - 2);
     309        bfrac = (bfrac | FLOAT64_HIDDEN_BIT_MASK) << (64 - FLOAT64_FRACTION_SIZE - 1);
     310
     311        if (bfrac <= (afrac << 1)) {
    300312                afrac >>= 1;
    301313                aexp++;
     
    304316        cexp = aexp - bexp + FLOAT64_BIAS - 2;
    305317       
    306         cfrac = divFloat64estim(afrac, bfrac);
    307        
    308         if ((  cfrac & 0x1FF ) <= 2) { /*FIXME:?? */
    309                 mul64integers( bfrac, cfrac, &remlo, &remhi);
    310                 /* (__u128)afrac << 64 - ( ((__u128)remhi<<64) + (__u128)remlo )*/     
    311                 remhi = afrac - remhi - ( remlo > 0);
    312                 remlo = - remlo;
     318        cfrac = div128est(afrac, 0x0ll, bfrac);
     319       
     320        if ((cfrac & 0x1FF) <= 2) {
     321                mul64(bfrac, cfrac, &tmphi, &tmplo);
     322                sub128(afrac, 0x0ll, tmphi, tmplo, &remhi, &remlo);
    313323               
    314324                while ((int64_t) remhi < 0) {
    315325                        cfrac--;
    316                         remlo += bfrac;
    317                         remhi += ( remlo < bfrac );
    318                 }
    319                 cfrac |= ( remlo != 0 );
     326                        add128(remhi, remlo, 0x0ll, bfrac, &remhi, &remlo);
     327                }
     328                cfrac |= (remlo != 0);
    320329        }
    321330       
     
    323332        result = finishFloat64(cexp, cfrac, result.parts.sign);
    324333        return result;
    325 
    326334}
    327335
    328 uint64_t divFloat64estim(uint64_t a, uint64_t b)
     336/**
     337 * Divide two quadruple-precision floats.
     338 *
     339 * @param a Nominator.
     340 * @param b Denominator.
     341 * @return Result of division.
     342 */
     343float128 divFloat128(float128 a, float128 b)
    329344{
    330         uint64_t bhi;
    331         uint64_t remhi, remlo;
    332         uint64_t result;
    333        
    334         if ( b <= a ) {
    335                 return 0xFFFFFFFFFFFFFFFFull;
    336         }
    337        
    338         bhi = b >> 32;
    339         result = ((bhi << 32) <= a) ?( 0xFFFFFFFFull << 32) : ( a / bhi) << 32;
    340         mul64integers(b, result, &remlo, &remhi);
    341        
    342         remhi = a - remhi - (remlo > 0);
    343         remlo = - remlo;
    344 
    345         b <<= 32;
    346         while ( (int64_t) remhi < 0 ) {
    347                         result -= 0x1ll << 32; 
    348                         remlo += b;
    349                         remhi += bhi + ( remlo < b );
    350                 }
    351         remhi = (remhi << 32) | (remlo >> 32);
    352         if (( bhi << 32) <= remhi) {
    353                 result |= 0xFFFFFFFF;
    354         } else {
    355                 result |= remhi / bhi;
    356         }
    357        
    358        
     345        float128 result;
     346        int64_t aexp, bexp, cexp;
     347        uint64_t afrac_hi, afrac_lo, bfrac_hi, bfrac_lo, cfrac_hi, cfrac_lo;
     348        uint64_t shift_out;
     349        uint64_t rem_hihi, rem_hilo, rem_lohi, rem_lolo;
     350        uint64_t tmp_hihi, tmp_hilo, tmp_lohi, tmp_lolo;
     351
     352        result.parts.sign = a.parts.sign ^ b.parts.sign;
     353
     354        if (isFloat128NaN(a)) {
     355                if (isFloat128SigNaN(b)) {
     356                        /*FIXME: SigNaN*/
     357                        return b;
     358                }
     359
     360                if (isFloat128SigNaN(a)) {
     361                        /*FIXME: SigNaN*/
     362                }
     363                /*NaN*/
     364                return a;
     365        }
     366
     367        if (isFloat128NaN(b)) {
     368                if (isFloat128SigNaN(b)) {
     369                        /*FIXME: SigNaN*/
     370                }
     371                /*NaN*/
     372                return b;
     373        }
     374
     375        if (isFloat128Infinity(a)) {
     376                if (isFloat128Infinity(b) || isFloat128Zero(b)) {
     377                        /*FIXME: inf / inf */
     378                        result.binary.hi = FLOAT128_NAN_HI;
     379                        result.binary.lo = FLOAT128_NAN_LO;
     380                        return result;
     381                }
     382                /* inf / num */
     383                result.parts.exp = a.parts.exp;
     384                result.parts.frac_hi = a.parts.frac_hi;
     385                result.parts.frac_lo = a.parts.frac_lo;
     386                return result;
     387        }
     388
     389        if (isFloat128Infinity(b)) {
     390                if (isFloat128Zero(a)) {
     391                        /* FIXME 0 / inf */
     392                        result.parts.exp = 0;
     393                        result.parts.frac_hi = 0;
     394                        result.parts.frac_lo = 0;
     395                        return result;
     396                }
     397                /* FIXME: num / inf*/
     398                result.parts.exp = 0;
     399                result.parts.frac_hi = 0;
     400                result.parts.frac_lo = 0;
     401                return result;
     402        }
     403
     404        if (isFloat128Zero(b)) {
     405                if (isFloat128Zero(a)) {
     406                        /*FIXME: 0 / 0*/
     407                        result.binary.hi = FLOAT128_NAN_HI;
     408                        result.binary.lo = FLOAT128_NAN_LO;
     409                        return result;
     410                }
     411                /* FIXME: division by zero */
     412                result.parts.exp = 0;
     413                result.parts.frac_hi = 0;
     414                result.parts.frac_lo = 0;
     415                return result;
     416        }
     417
     418        afrac_hi = a.parts.frac_hi;
     419        afrac_lo = a.parts.frac_lo;
     420        aexp = a.parts.exp;
     421        bfrac_hi = b.parts.frac_hi;
     422        bfrac_lo = b.parts.frac_lo;
     423        bexp = b.parts.exp;
     424
     425        /* denormalized numbers */
     426        if (aexp == 0) {
     427                if (eq128(afrac_hi, afrac_lo, 0x0ll, 0x0ll)) {
     428                        result.parts.exp = 0;
     429                        result.parts.frac_hi = 0;
     430                        result.parts.frac_lo = 0;
     431                        return result;
     432                }
     433
     434                /* normalize it*/
     435                aexp++;
     436                /* afrac is nonzero => it must stop */
     437                and128(afrac_hi, afrac_lo,
     438                    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
     439                    &tmp_hihi, &tmp_lolo);
     440                while (!lt128(0x0ll, 0x0ll, tmp_hihi, tmp_lolo)) {
     441                        lshift128(afrac_hi, afrac_lo, 1, &afrac_hi, &afrac_lo);
     442                        aexp--;
     443                }
     444        }
     445
     446        if (bexp == 0) {
     447                bexp++;
     448                /* bfrac is nonzero => it must stop */
     449                and128(bfrac_hi, bfrac_lo,
     450                    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
     451                    &tmp_hihi, &tmp_lolo);
     452                while (!lt128(0x0ll, 0x0ll, tmp_hihi, tmp_lolo)) {
     453                        lshift128(bfrac_hi, bfrac_lo, 1, &bfrac_hi, &bfrac_lo);
     454                        bexp--;
     455                }
     456        }
     457
     458        or128(afrac_hi, afrac_lo,
     459            FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
     460            &afrac_hi, &afrac_lo);
     461        lshift128(afrac_hi, afrac_lo,
     462            (128 - FLOAT128_FRACTION_SIZE - 1), &afrac_hi, &afrac_lo);
     463        or128(bfrac_hi, bfrac_lo,
     464            FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
     465            &bfrac_hi, &bfrac_lo);
     466        lshift128(bfrac_hi, bfrac_lo,
     467            (128 - FLOAT128_FRACTION_SIZE - 1), &bfrac_hi, &bfrac_lo);
     468
     469        if (le128(bfrac_hi, bfrac_lo, afrac_hi, afrac_lo)) {
     470                rshift128(afrac_hi, afrac_lo, 1, &afrac_hi, &afrac_lo);
     471                aexp++;
     472        }
     473
     474        cexp = aexp - bexp + FLOAT128_BIAS - 2;
     475
     476        cfrac_hi = div128est(afrac_hi, afrac_lo, bfrac_hi);
     477
     478        mul128(bfrac_hi, bfrac_lo, 0x0ll, cfrac_hi,
     479            &tmp_lolo /* dummy */, &tmp_hihi, &tmp_hilo, &tmp_lohi);
     480
     481        /* sub192(afrac_hi, afrac_lo, 0,
     482         *     tmp_hihi, tmp_hilo, tmp_lohi
     483         *     &rem_hihi, &rem_hilo, &rem_lohi); */
     484        sub128(afrac_hi, afrac_lo, tmp_hihi, tmp_hilo, &rem_hihi, &rem_hilo);
     485        if (tmp_lohi > 0) {
     486                sub128(rem_hihi, rem_hilo, 0x0ll, 0x1ll, &rem_hihi, &rem_hilo);
     487        }
     488        rem_lohi = -tmp_lohi;
     489
     490        while ((int64_t) rem_hihi < 0) {
     491                --cfrac_hi;
     492                /* add192(rem_hihi, rem_hilo, rem_lohi,
     493                 *     0, bfrac_hi, bfrac_lo,
     494                 *     &rem_hihi, &rem_hilo, &rem_lohi); */
     495                add128(rem_hilo, rem_lohi, bfrac_hi, bfrac_lo, &rem_hilo, &rem_lohi);
     496                if (lt128(rem_hilo, rem_lohi, bfrac_hi, bfrac_lo)) {
     497                        ++rem_hihi;
     498                }
     499        }
     500
     501        cfrac_lo = div128est(rem_hilo, rem_lohi, bfrac_lo);
     502
     503        if ((cfrac_lo & 0x3FFF) <= 4) {
     504                mul128(bfrac_hi, bfrac_lo, 0x0ll, cfrac_lo,
     505                &tmp_hihi /* dummy */, &tmp_hilo, &tmp_lohi, &tmp_lolo);
     506
     507                /* sub192(rem_hilo, rem_lohi, 0,
     508                 *     tmp_hilo, tmp_lohi, tmp_lolo,
     509                 *     &rem_hilo, &rem_lohi, &rem_lolo); */
     510                sub128(rem_hilo, rem_lohi, tmp_hilo, tmp_lohi, &rem_hilo, &rem_lohi);
     511                if (tmp_lolo > 0) {
     512                        sub128(rem_hilo, rem_lohi, 0x0ll, 0x1ll, &rem_hilo, &rem_lohi);
     513                }
     514                rem_lolo = -tmp_lolo;
     515
     516                while ((int64_t) rem_hilo < 0) {
     517                        --cfrac_lo;
     518                        /* add192(rem_hilo, rem_lohi, rem_lolo,
     519                         *     0, bfrac_hi, bfrac_lo,
     520                         *     &rem_hilo, &rem_lohi, &rem_lolo); */
     521                        add128(rem_lohi, rem_lolo, bfrac_hi, bfrac_lo, &rem_lohi, &rem_lolo);
     522                        if (lt128(rem_lohi, rem_lolo, bfrac_hi, bfrac_lo)) {
     523                                ++rem_hilo;
     524                        }
     525                }
     526
     527                cfrac_lo |= ((rem_hilo | rem_lohi | rem_lolo) != 0 );
     528        }
     529
     530        shift_out = cfrac_lo << (64 - (128 - FLOAT128_FRACTION_SIZE - 1));
     531        rshift128(cfrac_hi, cfrac_lo, (128 - FLOAT128_FRACTION_SIZE - 1),
     532            &cfrac_hi, &cfrac_lo);
     533
     534        result = finishFloat128(cexp, cfrac_hi, cfrac_lo, result.parts.sign, shift_out);
    359535        return result;
    360536}
Note: See TracChangeset for help on using the changeset viewer.