1 //===-- Fast rounding to nearest integer for floating point -----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_NEAREST_INTEGER_H 10 #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_NEAREST_INTEGER_H 11 12 #include "src/__support/architectures.h" 13 #include "src/__support/common.h" 14 15 #if (defined(LLVM_LIBC_ARCH_X86_64) && defined(__SSE4_2__)) 16 #include "x86_64/nearest_integer.h" 17 #elif defined(LLVM_LIBC_ARCH_AARCH64) 18 #include "aarch64/nearest_integer.h" 19 #else 20 21 namespace __llvm_libc { 22 namespace fputil { 23 24 // This is a fast implementation for rounding to a nearest integer that. 25 // 26 // Notice that for AARCH64 and x86-64 with SSE4.2 support, we will use their 27 // corresponding rounding instruction instead. And in those cases, the results 28 // are rounded to the nearest integer, tie-to-even. 29 static inline float nearest_integer(float x) { 30 if (x < 0x1p24f && x > -0x1p24f) { 31 float r = x < 0 ? (x - 0x1.0p23f) + 0x1.0p23f : (x + 0x1.0p23f) - 0x1.0p23f; 32 float diff = x - r; 33 // The expression above is correct for the default rounding mode, round-to- 34 // nearest, tie-to-even. For other rounding modes, it might be off by 1, 35 // which is corrected below. 36 if (unlikely(diff > 0.5f)) 37 return r + 1.0f; 38 if (unlikely(diff < -0.5f)) 39 return r - 1.0f; 40 return r; 41 } 42 return x; 43 } 44 45 static inline double nearest_integer(double x) { 46 if (x < 0x1p53 && x > -0x1p53) { 47 double r = x < 0 ? (x - 0x1.0p52) + 0x1.0p52 : (x + 0x1.0p52) - 0x1.0p52; 48 double diff = x - r; 49 // The expression above is correct for the default rounding mode, round-to- 50 // nearest, tie-to-even. For other rounding modes, it might be off by 1, 51 // which is corrected below. 52 if (unlikely(diff > 0.5)) 53 return r + 1.0; 54 if (unlikely(diff < -0.5)) 55 return r - 1.0; 56 return r; 57 } 58 return x; 59 } 60 61 } // namespace fputil 62 } // namespace __llvm_libc 63 64 #endif 65 #endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_NEAREST_INTEGER_H 66