1 // rounding-algorithms.hpp 2 // 3 // General Rounding Algorithms 4 // Copyright (c) 2008 Michael Thomas Greer 5 // Boost Software License - Version 1.0 - August 17th, 2003 6 // 7 // Permission is hereby granted, free of charge, to any person or organization 8 // obtaining a copy of the software and accompanying documentation covered by 9 // this license (the "Software") to use, reproduce, display, distribute, 10 // execute, and transmit the Software, and to prepare derivative works of the 11 // Software, and to permit third-parties to whom the Software is furnished to 12 // do so, all subject to the following: 13 // 14 // The copyright notices in the Software and this entire statement, including 15 // the above license grant, this restriction and the following disclaimer, 16 // must be included in all copies of the Software, in whole or in part, and 17 // all derivative works of the Software, unless such copies or derivative 18 // works are solely in the form of machine-executable object code generated by 19 // a source language processor. 20 // 21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 24 // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 25 // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 26 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 // DEALINGS IN THE SOFTWARE. 28 // 29 //---------------------------------------------------------------------------- 30 // Reference 31 // <http://www.pldesignline.com/howto/showArticle.jhtml;?articleID=175801189> 32 // 33 //---------------------------------------------------------------------------- 34 // In this library, symmetric functions are indicated by a zero at the end 35 // of the function name. 36 // 37 // If you want a different default epsilon make sure to change 38 // 39 // #define ROUNDING_EPSILON 0.001 40 // 41 // to whatever you want it to be. (I wanted to make it so that you could 42 // define a different default epsilon each time you #included the file, but 43 // I haven't figured out how to get around the template restrictions yet.) 44 // 45 46 #ifndef ROUNDING_ALGORITHMS_HPP 47 #define ROUNDING_ALGORITHMS_HPP 48 49 #ifndef ROUNDING_EPSILON 50 #define ROUNDING_EPSILON 0.0000001 51 #endif 52 53 #include <cmath> 54 #include <cstdlib> 55 #include <ciso646> 56 57 namespace rounding 58 { 59 60 //-------------------------------------------------------------------------- 61 // round down 62 // Bias: -Infinity 63 using std::floor; 64 65 //-------------------------------------------------------------------------- 66 // round up 67 // Bias: +Infinity 68 using std::ceil; 69 70 //-------------------------------------------------------------------------- 71 // symmetric round down 72 // Bias: towards zero 73 template <typename FloatType> floor0(const FloatType & value)74 FloatType floor0( const FloatType& value ) 75 { 76 FloatType result = std::floor( std::fabs( value ) ); 77 return (value < 0.0) ? -result : result; 78 } 79 80 //-------------------------------------------------------------------------- 81 // A common alias for floor0() 82 // (notwithstanding hardware quirks) 83 template <typename FloatType> 84 inline trunc(const FloatType & value)85 FloatType trunc( const FloatType& value ) 86 { 87 return floor0( value ); 88 } 89 90 //-------------------------------------------------------------------------- 91 // symmetric round up 92 // Bias: away from zero 93 template <typename FloatType> ceil0(const FloatType & value)94 FloatType ceil0( const FloatType& value ) 95 { 96 FloatType result = std::ceil( std::fabs( value ) ); 97 return (value < 0.0) ? -result : result; 98 } 99 100 //-------------------------------------------------------------------------- 101 // Common rounding: round half up 102 // Bias: +Infinity 103 template <typename FloatType> roundhalfup(const FloatType & value)104 FloatType roundhalfup( const FloatType& value ) 105 { 106 return std::floor( value +0.5 ); 107 } 108 109 //-------------------------------------------------------------------------- 110 // Round half down 111 // Bias: -Infinity 112 template <typename FloatType> roundhalfdown(const FloatType & value)113 FloatType roundhalfdown( const FloatType& value ) 114 { 115 return std::ceil( value -0.5 ); 116 } 117 118 //-------------------------------------------------------------------------- 119 // symmetric round half down 120 // Bias: towards zero 121 template <typename FloatType> roundhalfdown0(const FloatType & value)122 FloatType roundhalfdown0( const FloatType& value ) 123 { 124 FloatType result = roundhalfdown( std::fabs( value ) ); 125 return (value < 0.0) ? -result : result; 126 } 127 128 //-------------------------------------------------------------------------- 129 // symmetric round half up 130 // Bias: away from zero 131 template <typename FloatType> roundhalfup0(const FloatType & value)132 FloatType roundhalfup0( const FloatType& value ) 133 { 134 FloatType result = roundhalfup( std::fabs( value ) ); 135 return (value < 0.0) ? -result : result; 136 } 137 138 //-------------------------------------------------------------------------- 139 // round half even (banker's rounding) 140 // Bias: none 141 template <typename FloatType> 142 FloatType roundhalfeven( 143 const FloatType& value, 144 const FloatType& epsilon = ROUNDING_EPSILON 145 ) { 146 if (value < 0.0) return -roundhalfeven <FloatType> ( -value, epsilon ); 147 148 FloatType ipart; 149 std::modf( value, &ipart ); 150 151 // If 'value' is exctly halfway between two integers 152 if ((value -(ipart +0.5)) < epsilon) 153 { 154 // If 'ipart' is even then return 'ipart' 155 if (std::fmod( ipart, 2.0 ) < epsilon) 156 return ipart; 157 158 // Else return the nearest even integer 159 return ceil0( ipart +0.5 ); 160 } 161 162 // Otherwise use the usual round to closest 163 // (Either symmetric half-up or half-down will do0 164 return roundhalfup0( value ); 165 } 166 167 //-------------------------------------------------------------------------- 168 // round random 169 // Bias: generator's bias 170 template <typename FloatType, typename RandValue, typename RandomGenerator> roundrandom(const FloatType & value,const RandValue & mid,RandomGenerator & g)171 FloatType roundrandom( 172 const FloatType& value, 173 const RandValue& mid, 174 RandomGenerator& g 175 ) { 176 if (g() < mid) 177 return roundhalfup0( value ); 178 return roundhalfdown0( value ); 179 } 180 181 //-------------------------------------------------------------------------- 182 // default round random 183 // Bias: rand() 184 template <typename FloatType> roundrandom(const FloatType & value)185 FloatType roundrandom( const FloatType& value ) 186 { 187 return roundrandom <FloatType, int, int(*)()> ( value, RAND_MAX /2, &rand ); 188 } 189 } 190 191 #endif 192