github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/3rd_party/SoftFloat-3e/source/s_roundPackMToExtF80M.c (about)

     1  
     2  /*============================================================================
     3  
     4  This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
     5  Package, Release 3e, by John R. Hauser.
     6  
     7  Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of
     8  California.  All rights reserved.
     9  
    10  Redistribution and use in source and binary forms, with or without
    11  modification, are permitted provided that the following conditions are met:
    12  
    13   1. Redistributions of source code must retain the above copyright notice,
    14      this list of conditions, and the following disclaimer.
    15  
    16   2. Redistributions in binary form must reproduce the above copyright notice,
    17      this list of conditions, and the following disclaimer in the documentation
    18      and/or other materials provided with the distribution.
    19  
    20   3. Neither the name of the University nor the names of its contributors may
    21      be used to endorse or promote products derived from this software without
    22      specific prior written permission.
    23  
    24  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY
    25  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    26  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
    27  DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
    28  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    29  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    30  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    31  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    32  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    33  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    34  
    35  =============================================================================*/
    36  
    37  #include <stdbool.h>
    38  #include <stdint.h>
    39  #include "platform.h"
    40  #include "internals.h"
    41  #include "softfloat.h"
    42  
    43  void
    44   softfloat_roundPackMToExtF80M(
    45       bool sign,
    46       int32_t exp,
    47       uint32_t *extSigPtr,
    48       uint_fast8_t roundingPrecision,
    49       struct extFloat80M *zSPtr
    50   )
    51  {
    52      uint_fast8_t roundingMode;
    53      bool roundNearEven;
    54      uint64_t sig, roundIncrement, roundMask, roundBits;
    55      bool isTiny;
    56      uint32_t sigExtra;
    57      bool doIncrement;
    58  
    59      /*------------------------------------------------------------------------
    60      *------------------------------------------------------------------------*/
    61      roundingMode = softfloat_roundingMode;
    62      roundNearEven = (roundingMode == softfloat_round_near_even);
    63      sig =
    64          (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32
    65              | extSigPtr[indexWord( 3, 1 )];
    66      if ( roundingPrecision == 80 ) goto precision80;
    67      if ( roundingPrecision == 64 ) {
    68          roundIncrement = UINT64_C( 0x0000000000000400 );
    69          roundMask = UINT64_C( 0x00000000000007FF );
    70      } else if ( roundingPrecision == 32 ) {
    71          roundIncrement = UINT64_C( 0x0000008000000000 );
    72          roundMask = UINT64_C( 0x000000FFFFFFFFFF );
    73      } else {
    74          goto precision80;
    75      }
    76      /*------------------------------------------------------------------------
    77      *------------------------------------------------------------------------*/
    78      if ( extSigPtr[indexWordLo( 3 )] ) sig |= 1;
    79      if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) {
    80          roundIncrement =
    81              (roundingMode
    82                   == (sign ? softfloat_round_min : softfloat_round_max))
    83                  ? roundMask
    84                  : 0;
    85      }
    86      roundBits = sig & roundMask;
    87      /*------------------------------------------------------------------------
    88      *------------------------------------------------------------------------*/
    89      if ( 0x7FFD <= (uint32_t) (exp - 1) ) {
    90          if ( exp <= 0 ) {
    91              /*----------------------------------------------------------------
    92              *----------------------------------------------------------------*/
    93              isTiny =
    94                     (softfloat_detectTininess
    95                          == softfloat_tininess_beforeRounding)
    96                  || (exp < 0)
    97                  || (sig <= (uint64_t) (sig + roundIncrement));
    98              sig = softfloat_shiftRightJam64( sig, 1 - exp );
    99              roundBits = sig & roundMask;
   100              if ( roundBits ) {
   101                  if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow );
   102                  softfloat_exceptionFlags |= softfloat_flag_inexact;
   103  #ifdef SOFTFLOAT_ROUND_ODD
   104                  if ( roundingMode == softfloat_round_odd ) {
   105                      sig |= roundMask + 1;
   106                  }
   107  #endif
   108              }
   109              sig += roundIncrement;
   110              exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0);
   111              roundIncrement = roundMask + 1;
   112              if ( roundNearEven && (roundBits<<1 == roundIncrement) ) {
   113                  roundMask |= roundIncrement;
   114              }
   115              sig &= ~roundMask;
   116              goto packReturn;
   117          }
   118          if (
   119                 (0x7FFE < exp)
   120              || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig))
   121          ) {
   122              goto overflow;
   123          }
   124      }
   125      /*------------------------------------------------------------------------
   126      *------------------------------------------------------------------------*/
   127      if ( roundBits ) {
   128          softfloat_exceptionFlags |= softfloat_flag_inexact;
   129  #ifdef SOFTFLOAT_ROUND_ODD
   130          if ( roundingMode == softfloat_round_odd ) {
   131              sig = (sig & ~roundMask) | (roundMask + 1);
   132              goto packReturn;
   133          }
   134  #endif
   135      }
   136      sig += roundIncrement;
   137      if ( sig < roundIncrement ) {
   138          ++exp;
   139          sig = UINT64_C( 0x8000000000000000 );
   140      }
   141      roundIncrement = roundMask + 1;
   142      if ( roundNearEven && (roundBits<<1 == roundIncrement) ) {
   143          roundMask |= roundIncrement;
   144      }
   145      sig &= ~roundMask;
   146      goto packReturn;
   147      /*------------------------------------------------------------------------
   148      *------------------------------------------------------------------------*/
   149   precision80:
   150      sigExtra = extSigPtr[indexWordLo( 3 )];
   151      doIncrement = (0x80000000 <= sigExtra);
   152      if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) {
   153          doIncrement =
   154              (roundingMode
   155                   == (sign ? softfloat_round_min : softfloat_round_max))
   156                  && sigExtra;
   157      }
   158      /*------------------------------------------------------------------------
   159      *------------------------------------------------------------------------*/
   160      if ( 0x7FFD <= (uint32_t) (exp - 1) ) {
   161          if ( exp <= 0 ) {
   162              /*----------------------------------------------------------------
   163              *----------------------------------------------------------------*/
   164              isTiny =
   165                     (softfloat_detectTininess
   166                          == softfloat_tininess_beforeRounding)
   167                  || (exp < 0)
   168                  || ! doIncrement
   169                  || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF ));
   170              softfloat_shiftRightJam96M( extSigPtr, 1 - exp, extSigPtr );
   171              exp = 0;
   172              sig =
   173                  (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32
   174                      | extSigPtr[indexWord( 3, 1 )];
   175              sigExtra = extSigPtr[indexWordLo( 3 )];
   176              if ( sigExtra ) {
   177                  if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow );
   178                  softfloat_exceptionFlags |= softfloat_flag_inexact;
   179  #ifdef SOFTFLOAT_ROUND_ODD
   180                  if ( roundingMode == softfloat_round_odd ) {
   181                      sig |= 1;
   182                      goto packReturn;
   183                  }
   184  #endif
   185              }
   186              doIncrement = (0x80000000 <= sigExtra);
   187              if (
   188                  ! roundNearEven
   189                      && (roundingMode != softfloat_round_near_maxMag)
   190              ) {
   191                  doIncrement =
   192                      (roundingMode
   193                           == (sign ? softfloat_round_min : softfloat_round_max))
   194                          && sigExtra;
   195              }
   196              if ( doIncrement ) {
   197                  ++sig;
   198                  sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven);
   199                  exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0);
   200              }
   201              goto packReturn;
   202          }
   203          if (
   204                 (0x7FFE < exp)
   205              || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF ))
   206                      && doIncrement)
   207          ) {
   208              /*----------------------------------------------------------------
   209              *----------------------------------------------------------------*/
   210              roundMask = 0;
   211   overflow:
   212              softfloat_raiseFlags(
   213                  softfloat_flag_overflow | softfloat_flag_inexact );
   214              if (
   215                     roundNearEven
   216                  || (roundingMode == softfloat_round_near_maxMag)
   217                  || (roundingMode
   218                          == (sign ? softfloat_round_min : softfloat_round_max))
   219              ) {
   220                  exp = 0x7FFF;
   221                  sig = UINT64_C( 0x8000000000000000 );
   222              } else {
   223                  exp = 0x7FFE;
   224                  sig = ~roundMask;
   225              }
   226              goto packReturn;
   227          }
   228      }
   229      /*------------------------------------------------------------------------
   230      *------------------------------------------------------------------------*/
   231      if ( sigExtra ) {
   232          softfloat_exceptionFlags |= softfloat_flag_inexact;
   233  #ifdef SOFTFLOAT_ROUND_ODD
   234          if ( roundingMode == softfloat_round_odd ) {
   235              sig |= 1;
   236              goto packReturn;
   237          }
   238  #endif
   239      }
   240      if ( doIncrement ) {
   241          ++sig;
   242          if ( ! sig ) {
   243              ++exp;
   244              sig = UINT64_C( 0x8000000000000000 );
   245          } else {
   246              sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven);
   247          }
   248      }
   249      /*------------------------------------------------------------------------
   250      *------------------------------------------------------------------------*/
   251   packReturn:
   252      zSPtr->signExp = packToExtF80UI64( sign, exp );
   253      zSPtr->signif = sig;
   254  
   255  }
   256