diff options
Diffstat (limited to 'softfloat/f64_rem.c')
-rw-r--r--[-rwxr-xr-x] | softfloat/f64_rem.c | 160 |
1 files changed, 117 insertions, 43 deletions
diff --git a/softfloat/f64_rem.c b/softfloat/f64_rem.c index f738e5c..ca5350c 100755..100644 --- a/softfloat/f64_rem.c +++ b/softfloat/f64_rem.c @@ -1,10 +1,42 @@ -// See LICENSE.SoftFloat for license details. +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3e, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ #include <stdbool.h> #include <stdint.h> #include "platform.h" -#include "primitives.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" @@ -18,35 +50,44 @@ float64_t f64_rem( float64_t a, float64_t b ) uint_fast64_t sigA; union ui64_f64 uB; uint_fast64_t uiB; - bool signB; int_fast16_t expB; uint_fast64_t sigB; struct exp16_sig64 normExpSig; + uint64_t rem; int_fast16_t expDiff; - uint_fast64_t q, alternateSigA; - uint64_t sigMean; - bool signZ; + uint32_t q, recip32; + uint_fast64_t q64; + uint64_t altRem, meanRem; + bool signRem; uint_fast64_t uiZ; union ui64_f64 uZ; + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; signA = signF64UI( uiA ); - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); + expA = expF64UI( uiA ); + sigA = fracF64UI( uiA ); uB.f = b; uiB = uB.ui; - signB = signF64UI( uiB ); expB = expF64UI( uiB ); sigB = fracF64UI( uiB ); + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ if ( expA == 0x7FF ) { - if ( sigA || ( ( expB == 0x7FF ) && sigB ) ) goto propagateNaN; + if ( sigA || ((expB == 0x7FF) && sigB) ) goto propagateNaN; goto invalid; } if ( expB == 0x7FF ) { if ( sigB ) goto propagateNaN; return a; } + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + if ( expA < expB - 1 ) return a; + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ if ( ! expB ) { if ( ! sigB ) goto invalid; normExpSig = softfloat_normSubnormalF64Sig( sigB ); @@ -59,48 +100,81 @@ float64_t f64_rem( float64_t a, float64_t b ) expA = normExpSig.exp; sigA = normExpSig.sig; } + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + rem = sigA | UINT64_C( 0x0010000000000000 ); + sigB |= UINT64_C( 0x0010000000000000 ); expDiff = expA - expB; - sigA = ( sigA | UINT64_C( 0x0010000000000000 ) )<<11; - sigB = ( sigB | UINT64_C( 0x0010000000000000 ) )<<11; - if ( expDiff < 0 ) { + if ( expDiff < 1 ) { if ( expDiff < -1 ) return a; - sigA >>= 1; - } - q = ( sigB <= sigA ); - if ( q ) sigA -= sigB; - expDiff -= 64; - while ( 0 < expDiff ) { - q = softfloat_estimateDiv128To64( sigA, 0, sigB ); - q = ( 2 < q ) ? q - 2 : 0; - sigA = - ( ( sigB>>2 ) * q ); - expDiff -= 62; - } - expDiff += 64; - if ( 0 < expDiff ) { - q = softfloat_estimateDiv128To64( sigA, 0, sigB ); - q = ( 2 < q ) ? q - 2 : 0; - q >>= 64 - expDiff; - sigB >>= 2; - sigA = ( ( sigA>>1 )<<( expDiff - 1 ) ) - sigB * q; + sigB <<= 9; + if ( expDiff ) { + rem <<= 8; + q = 0; + } else { + rem <<= 9; + q = (sigB <= rem); + if ( q ) rem -= sigB; + } } else { - sigA >>= 2; - sigB >>= 2; + recip32 = softfloat_approxRecip32_1( sigB>>21 ); + /*-------------------------------------------------------------------- + | Changing the shift of `rem' here requires also changing the initial + | subtraction from `expDiff'. + *--------------------------------------------------------------------*/ + rem <<= 9; + expDiff -= 30; + /*-------------------------------------------------------------------- + | The scale of `sigB' affects how many bits are obtained during each + | cycle of the loop. Currently this is 29 bits per loop iteration, + | the maximum possible. + *--------------------------------------------------------------------*/ + sigB <<= 9; + for (;;) { + q64 = (uint32_t) (rem>>32) * (uint_fast64_t) recip32; + if ( expDiff < 0 ) break; + q = (q64 + 0x80000000)>>32; +#ifdef SOFTFLOAT_FAST_INT64 + rem <<= 29; +#else + rem = (uint_fast64_t) (uint32_t) (rem>>3)<<32; +#endif + rem -= q * (uint64_t) sigB; + if ( rem & UINT64_C( 0x8000000000000000 ) ) rem += sigB; + expDiff -= 29; + } + /*-------------------------------------------------------------------- + | (`expDiff' cannot be less than -29 here.) + *--------------------------------------------------------------------*/ + q = (uint32_t) (q64>>32)>>(~expDiff & 31); + rem = (rem<<(expDiff + 30)) - q * (uint64_t) sigB; + if ( rem & UINT64_C( 0x8000000000000000 ) ) { + altRem = rem + sigB; + goto selectRem; + } } + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ do { - alternateSigA = sigA; + altRem = rem; ++q; - sigA -= sigB; - } while ( sigA < UINT64_C( 0x8000000000000000 ) ); - sigMean = sigA + alternateSigA; + rem -= sigB; + } while ( ! (rem & UINT64_C( 0x8000000000000000 )) ); + selectRem: + meanRem = rem + altRem; if ( - ( UINT64_C( 0x8000000000000000 ) <= sigMean ) - || ( ! sigMean && ( q & 1 ) ) + (meanRem & UINT64_C( 0x8000000000000000 )) || (! meanRem && (q & 1)) ) { - sigA = alternateSigA; + rem = altRem; + } + signRem = signA; + if ( rem & UINT64_C( 0x8000000000000000 ) ) { + signRem = ! signRem; + rem = -rem; } - signZ = ( UINT64_C( 0x8000000000000000 ) <= sigA ); - if ( signZ ) sigA = - sigA; - return softfloat_normRoundPackToF64( signA ^ signZ, expB, sigA ); + return softfloat_normRoundPackToF64( signRem, expB, rem ); + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); goto uiZ; |