diff options
Diffstat (limited to 'source/s_roundPackToExtF80.c')
-rw-r--r-- | source/s_roundPackToExtF80.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/source/s_roundPackToExtF80.c b/source/s_roundPackToExtF80.c new file mode 100644 index 0000000..9e54d8e --- /dev/null +++ b/source/s_roundPackToExtF80.c @@ -0,0 +1,209 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014 The Regents of the University of California +(Regents). All Rights Reserved. Redistribution and use in source and binary +forms, with or without modification, are permitted provided that the following +conditions are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions, and the following two paragraphs of disclaimer. +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions, and the following two paragraphs of disclaimer in the +documentation and/or other materials provided with the distribution. Neither +the name of the Regents nor the names of its contributors may be used to +endorse or promote products derived from this software without specific prior +written permission. + +IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING +OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED +HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +=============================================================================*/ + +#include <stdbool.h> +#include <stdint.h> +#include "platform.h" +#include "internals.h" +#include "softfloat.h" + +extFloat80_t + softfloat_roundPackToExtF80( + bool sign, + int_fast32_t exp, + uint_fast64_t sig, + uint_fast64_t sigExtra, + uint_fast8_t roundingPrecision + ) +{ + uint_fast8_t roundingMode; + bool roundNearEven; + uint_fast64_t roundIncrement, roundMask, roundBits; + bool isTiny, doIncrement; + struct uint64_extra sig64Extra; + union { struct extFloat80M s; extFloat80_t f; } uZ; + + roundingMode = softfloat_roundingMode; + roundNearEven = (roundingMode == softfloat_round_near_even); + if ( roundingPrecision == 80 ) goto precision80; + if ( roundingPrecision == 64 ) { + roundIncrement = UINT64_C( 0x0000000000000400 ); + roundMask = UINT64_C( 0x00000000000007FF ); + } else if ( roundingPrecision == 32 ) { + roundIncrement = UINT64_C( 0x0000008000000000 ); + roundMask = UINT64_C( 0x000000FFFFFFFFFF ); + } else { + goto precision80; + } + sig |= (sigExtra != 0); + if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { + roundIncrement = + (roundingMode + == (sign ? softfloat_round_min : softfloat_round_max)) + ? roundMask + : 0; + } + roundBits = sig & roundMask; + if ( 0x7FFD <= (uint32_t) (exp - 1) ) { + if ( exp <= 0 ) { + isTiny = + (softfloat_detectTininess + == softfloat_tininess_beforeRounding) + || (exp < 0) + || (sig <= (uint64_t) (sig + roundIncrement)); + sig = softfloat_shiftRightJam64( sig, 1 - exp ); + roundBits = sig & roundMask; + if ( isTiny && roundBits ) { + softfloat_raiseFlags( softfloat_flag_underflow ); + } + if ( roundBits ) { + softfloat_exceptionFlags |= softfloat_flag_inexact; + } + sig += roundIncrement; + exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); + roundIncrement = roundMask + 1; + if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { + roundMask |= roundIncrement; + } + sig &= ~roundMask; + goto packReturn; + } + if ( + (0x7FFE < exp) + || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig)) + ) { + goto overflow; + } + } + if ( roundBits ) softfloat_exceptionFlags |= softfloat_flag_inexact; + sig = (uint64_t) (sig + roundIncrement); + if ( sig < roundIncrement ) { + ++exp; + sig = UINT64_C( 0x8000000000000000 ); + } + roundIncrement = roundMask + 1; + if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { + roundMask |= roundIncrement; + } + sig &= ~roundMask; + if ( ! sig ) exp = 0; + goto packReturn; + precision80: + doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); + if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { + doIncrement = + (roundingMode + == (sign ? softfloat_round_min : softfloat_round_max)) + && sigExtra; + } + if ( 0x7FFD <= (uint32_t) (exp - 1) ) { + if ( exp <= 0 ) { + isTiny = + (softfloat_detectTininess + == softfloat_tininess_beforeRounding) + || (exp < 0) + || ! doIncrement + || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF )); + sig64Extra = + softfloat_shiftRightJam64Extra( sig, sigExtra, 1 - exp ); + sig = sig64Extra.v; + sigExtra = sig64Extra.extra; + if ( isTiny && sigExtra ) { + softfloat_raiseFlags( softfloat_flag_underflow ); + } + if ( sigExtra ) softfloat_exceptionFlags |= softfloat_flag_inexact; + doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); + if ( + ! roundNearEven + && (roundingMode != softfloat_round_near_maxMag) + ) { + doIncrement = + (roundingMode + == (sign ? softfloat_round_min : softfloat_round_max)) + && sigExtra; + } + exp = 0; + if ( doIncrement ) { + ++sig; + sig &= + ~(! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) + & roundNearEven); + exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); + } + goto packReturn; + } + if ( + (0x7FFE < exp) + || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF )) + && doIncrement) + ) { + roundMask = 0; + overflow: + softfloat_raiseFlags( + softfloat_flag_overflow | softfloat_flag_inexact ); + if ( + roundNearEven + || (roundingMode == softfloat_round_near_maxMag) + || (roundingMode + == (sign ? softfloat_round_min : softfloat_round_max)) + ) { + exp = 0x7FFF; + sig = UINT64_C( 0x8000000000000000 ); + } else { + exp = 0x7FFE; + sig = ~roundMask; + } + goto packReturn; + } + } + if ( sigExtra ) softfloat_exceptionFlags |= softfloat_flag_inexact; + if ( doIncrement ) { + ++sig; + if ( ! sig ) { + ++exp; + sig = UINT64_C( 0x8000000000000000 ); + } else { + sig &= + ~(! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) + & roundNearEven); + } + } else { + if ( ! sig ) exp = 0; + } + packReturn: + uZ.s.signExp = packToExtF80UI64( sign, exp ); + uZ.s.signif = sig; + return uZ.f; + +} + |