rounding.h revision 7ec681f3
1/* 2 * Copyright © 2015 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#ifndef _ROUNDING_H 25#define _ROUNDING_H 26 27#include "c99_math.h" 28 29#include <limits.h> 30#include <stdint.h> 31 32#if defined(__SSE__) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1)) || (defined(_M_X64) && !defined(_M_ARM64EC)) 33#include <xmmintrin.h> 34#include <emmintrin.h> 35#endif 36 37#ifdef __SSE4_1__ 38#include <smmintrin.h> 39#endif 40 41/* The C standard library has functions round()/rint()/nearbyint() that round 42 * their arguments according to the rounding mode set in the floating-point 43 * control register. While there are trunc()/ceil()/floor() functions that do 44 * a specific operation without modifying the rounding mode, there is no 45 * roundeven() in any version of C. 46 * 47 * Technical Specification 18661 (ISO/IEC TS 18661-1:2014) adds roundeven(), 48 * but it's unfortunately not implemented by glibc. 49 * 50 * This implementation differs in that it does not raise the inexact exception. 51 * 52 * We use rint() to implement these functions, with the assumption that the 53 * floating-point rounding mode has not been changed from the default Round 54 * to Nearest. 55 */ 56 57/** 58 * \brief Rounds \c x to the nearest integer, with ties to the even integer. 59 */ 60static inline float 61_mesa_roundevenf(float x) 62{ 63#ifdef __SSE4_1__ 64 float ret; 65 __m128 m = _mm_load_ss(&x); 66 m = _mm_round_ss(m, m, _MM_FROUND_CUR_DIRECTION | _MM_FROUND_NO_EXC); 67 _mm_store_ss(&ret, m); 68 return ret; 69#else 70 return rintf(x); 71#endif 72} 73 74/** 75 * \brief Rounds \c x to the nearest integer, with ties to the even integer. 76 */ 77static inline double 78_mesa_roundeven(double x) 79{ 80#ifdef __SSE4_1__ 81 double ret; 82 __m128d m = _mm_load_sd(&x); 83 m = _mm_round_sd(m, m, _MM_FROUND_CUR_DIRECTION | _MM_FROUND_NO_EXC); 84 _mm_store_sd(&ret, m); 85 return ret; 86#else 87 return rint(x); 88#endif 89} 90 91/** 92 * \brief Rounds \c x to the nearest integer, with ties to the even integer, 93 * and returns the value as a long int. 94 */ 95static inline long 96_mesa_lroundevenf(float x) 97{ 98#if defined(__SSE__) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1)) || (defined(_M_X64) && !defined(_M_ARM64EC)) 99#if LONG_MAX == INT64_MAX 100 return _mm_cvtss_si64(_mm_load_ss(&x)); 101#elif LONG_MAX == INT32_MAX 102 return _mm_cvtss_si32(_mm_load_ss(&x)); 103#else 104#error "Unsupported long size" 105#endif 106#else 107 return lrintf(x); 108#endif 109} 110 111/** 112 * \brief Rounds \c x to the nearest integer, with ties to the even integer, 113 * and returns the value as a long int. 114 */ 115static inline long 116_mesa_lroundeven(double x) 117{ 118#if defined(__SSE2__) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || (defined(_M_X64) && !defined(_M_ARM64EC)) 119#if LONG_MAX == INT64_MAX 120 return _mm_cvtsd_si64(_mm_load_sd(&x)); 121#elif LONG_MAX == INT32_MAX 122 return _mm_cvtsd_si32(_mm_load_sd(&x)); 123#else 124#error "Unsupported long size" 125#endif 126#else 127 return lrint(x); 128#endif 129} 130 131/** 132 * \brief Rounds \c x to the nearest integer, with ties to the even integer, 133 * and returns the value as an int64_t. 134 */ 135static inline int64_t 136_mesa_i64roundevenf(float x) 137{ 138#if LONG_MAX == INT64_MAX 139 return _mesa_lroundevenf(x); 140#elif LONG_MAX == INT32_MAX 141 return llrintf(x); 142#else 143#error "Unsupported long size" 144#endif 145} 146 147#endif 148