/ src / ref / lround.c
lround.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  
 33  long int FN_PROTOTYPE_REF(lround)(double d)
 34  {
 35      UT64 u64d;
 36      UT64 u64Temp,u64result;
 37      int intexp, shift;
 38      U64 sign;
 39      long int result;
 40  
 41      u64d.f64 = u64Temp.f64 = d;
 42  
 43      if ((u64d.u32[1] & 0X7FF00000) == 0x7FF00000)
 44      {
 45          /*else the number is infinity*/
 46          //Raise range or domain error
 47          #ifdef WIN64
 48  		    __amd_handle_error("lround", __amd_lround, SIGNBIT_SP32, _DOMAIN, AMD_F_NONE, EDOM, d, 0.0, 1);
 49  		    return (long int )SIGNBIT_SP32;
 50          #else
 51           if((u64d.u64 & 0x7fffffffffffffff) == 0x7ff0000000000000)
 52              return SIGNBIT_DP64;
 53           if((u64d.u64 & 0x7fffffffffffffff) >= 0x7ff8000000000000)
 54                  __amd_handle_error("lround", __amd_lround, (unsigned long long)SIGNBIT_DP64, _DOMAIN, AMD_F_NONE, EDOM, d, 0.0, 1);
 55           else
 56                  __amd_handle_error("lround", __amd_lround, (unsigned long long)SIGNBIT_DP64, _DOMAIN, AMD_F_INVALID, EDOM, d, 0.0, 1);
 57  
 58  		 return SIGNBIT_DP64; /*GCC returns this when the number is out of range*/
 59          #endif
 60  
 61      }
 62  
 63      u64Temp.u32[1] &= 0x7FFFFFFF;
 64      intexp = (u64d.u32[1] & 0x7FF00000) >> 20;
 65      sign = u64d.u64 & 0x8000000000000000;
 66      intexp -= 0x3FF;
 67  
 68      /* 1.0 x 2^-1 is the smallest number which can be rounded to 1 */
 69      if (intexp < -1)
 70          return (0);
 71  
 72  #ifdef WIN64
 73      /* 1.0 x 2^31 (or 2^63) is already too large */
 74      if (intexp >= 31)
 75      {
 76          /*Based on the sign of the input value return the MAX and MIN*/
 77          result = 0x80000000; /*Return LONG MIN*/
 78          __amd_handle_error("lround", __amd_lround, result, _DOMAIN, AMD_F_NONE, EDOM, d, 0.0, 1);
 79          return result;
 80      }
 81  
 82  #else
 83      /* 1.0 x 2^31 (or 2^63) is already too large */
 84      if (intexp >= 63)
 85      {
 86          /*Based on the sign of the input value return the MAX and MIN*/
 87          result = 0x8000000000000000; /*Return LONG MIN*/
 88          __amd_handle_error("lround", __amd_lround, result, _DOMAIN, AMD_F_NONE, EDOM, d, 0.0, 1);
 89          return result;
 90      }
 91  
 92  #endif
 93  
 94      u64result.f64 = u64Temp.f64;
 95      /* >= 2^52 is already an exact integer */
 96  #ifdef WIN64
 97      if (intexp < 23)
 98  #else
 99      if (intexp < 52)
100  #endif
101      {
102          /* add 0.5, extraction below will truncate */
103          u64result.f64 = u64Temp.f64 + 0.5;
104      }
105  
106      intexp = ((u64result.u32[1] >> 20) & 0x7ff) - 0x3FF;
107  
108      u64result.u32[1] &= 0xfffff;
109      u64result.u32[1] |= 0x00100000; /*Mask the last exp bit to 1*/
110      shift = intexp - 52;
111  
112  #ifdef WIN64
113  	/*The shift value will always be negative.*/
114      u64result.u64 = u64result.u64 >> (-shift);
115  	/*Result will be stored in the lower word due to the shift being performed*/
116      result = u64result.u32[0];
117  #else
118       if(shift < 0)
119          u64result.u64 = u64result.u64 >> (-shift);
120      if(shift > 0)
121          u64result.u64 = u64result.u64 << (shift);
122  
123      result = u64result.u64;
124  #endif
125  
126      if (sign)
127          result = -result;
128  
129      return result;
130  }
131  
132