/ src / ref / llround.c
llround.c
  1  /*
  2   * Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved.
  3   *
  4   * Redistribution and use in source and binary forms, with or without modification,
  5   * are permitted provided that the following conditions are met:
  6   * 1. Redistributions of source code must retain the above copyright notice,
  7   *    this list of conditions and the following disclaimer.
  8   * 2. Redistributions in binary form must reproduce the above copyright notice,
  9   *    this list of conditions and the following disclaimer in the documentation
 10   *    and/or other materials provided with the distribution.
 11   * 3. Neither the name of the copyright holder nor the names of its contributors
 12   *    may be used to endorse or promote products derived from this software without
 13   *    specific prior written permission.
 14   *
 15   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 16   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 17   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 18   * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 19   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 20   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 21   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 22   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 23   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 24   * POSSIBILITY OF SUCH DAMAGE.
 25   *
 26   */
 27  
 28  #include "libm_amd.h"
 29  #include "libm_util_amd.h"
 30  #include "libm_special.h"
 31  
 32  #ifdef WINDOWS
 33  /*In windows llong long int is 64 bit and long int is 32 bit.
 34    In Linux long long int and long int both are of size 64 bit*/
 35  long long int FN_PROTOTYPE_REF(llround)(double d)
 36  {
 37      UT64 u64d;
 38      UT64 u64Temp,u64result;
 39      int intexp, shift;
 40      U64 sign;
 41      long long int result;
 42  
 43      u64d.f64 = u64Temp.f64 = d;
 44  
 45      if ((u64d.u32[1] & 0X7FF00000) == 0x7FF00000)
 46      {
 47          /*the number is infinity*/
 48          //Got to raise range or domain error
 49  		__amd_handle_error("llround", __amd_lround, u64d.u64, _DOMAIN, AMD_F_NONE, EDOM, d, 0.0, 1);
 50  		return SIGNBIT_DP64; /*GCC returns this when the number is out of range*/
 51      }
 52  
 53      u64Temp.u32[1] &= 0x7FFFFFFF;
 54      intexp = (u64d.u32[1] & 0x7FF00000) >> 20;
 55      sign = u64d.u64 & 0x8000000000000000;
 56      intexp -= 0x3FF;
 57  
 58      /* 1.0 x 2^-1 is the smallest number which can be rounded to 1 */
 59      if (intexp < -1)
 60          return (0);
 61  
 62      /* 1.0 x 2^31 (or 2^63) is already too large */
 63      if (intexp >= 63)
 64      {
 65          /*Based on the sign of the input value return the MAX and MIN*/
 66          result = 0x8000000000000000; /*Return LONG MIN*/
 67  		__amd_handle_error("llround", __amd_lround, result, _DOMAIN, AMD_F_NONE, EDOM, d, 0.0, 1);
 68          return result;
 69      }
 70  
 71      u64result.f64 = u64Temp.f64;
 72      /* >= 2^52 is already an exact integer */
 73      if (intexp < 52)
 74      {
 75          /* add 0.5, extraction below will truncate */
 76          u64result.f64 = u64Temp.f64 + 0.5;
 77      }
 78  
 79      intexp = ((u64result.u32[1] >> 20) & 0x7ff) - 0x3FF;
 80  
 81      u64result.u32[1] &= 0xfffff;
 82      u64result.u32[1] |= 0x00100000; /*Mask the last exp bit to 1*/
 83      shift = intexp - 52;
 84  
 85      if(shift < 0)
 86          u64result.u64 = u64result.u64 >> (-shift);
 87      if(shift > 0)
 88          u64result.u64 = u64result.u64 << (shift);
 89  
 90      result = u64result.u64;
 91  
 92      if (sign)
 93          result = -result;
 94  
 95      return result;
 96  }
 97  
 98  #else //WINDOWS 
 99  /*llroundf is equivalent to the linux implementation of 
100    lroundf. Both long int and long long int are of the same size*/
101  long long int FN_PROTOTYPE_REF(llround)(double d)
102  {
103      long long int result;
104      result = FN_PROTOTYPE(lround)(d);
105      return result;
106  }
107  
108  #endif