github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/api/resource/math.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package resource 18 19 import ( 20 "math/big" 21 22 inf "gopkg.in/inf.v0" 23 ) 24 25 const ( 26 // maxInt64Factors is the highest value that will be checked when removing factors of 10 from an int64. 27 // It is also the maximum decimal digits that can be represented with an int64. 28 maxInt64Factors = 18 29 ) 30 31 var ( 32 // Commonly needed big.Int values-- treat as read only! 33 bigTen = big.NewInt(10) 34 bigZero = big.NewInt(0) 35 bigOne = big.NewInt(1) 36 bigThousand = big.NewInt(1000) 37 big1024 = big.NewInt(1024) 38 39 // Commonly needed inf.Dec values-- treat as read only! 40 decZero = inf.NewDec(0, 0) 41 decOne = inf.NewDec(1, 0) 42 43 // Largest (in magnitude) number allowed. 44 maxAllowed = infDecAmount{inf.NewDec((1<<63)-1, 0)} // == max int64 45 46 // The maximum value we can represent milli-units for. 47 // Compare with the return value of Quantity.Value() to 48 // see if it's safe to use Quantity.MilliValue(). 49 MaxMilliValue = int64(((1 << 63) - 1) / 1000) 50 ) 51 52 const mostNegative = -(mostPositive + 1) 53 const mostPositive = 1<<63 - 1 54 55 // int64Add returns a+b, or false if that would overflow int64. 56 func int64Add(a, b int64) (int64, bool) { 57 c := a + b 58 switch { 59 case a > 0 && b > 0: 60 if c < 0 { 61 return 0, false 62 } 63 case a < 0 && b < 0: 64 if c > 0 { 65 return 0, false 66 } 67 if a == mostNegative && b == mostNegative { 68 return 0, false 69 } 70 } 71 return c, true 72 } 73 74 // int64Multiply returns a*b, or false if that would overflow or underflow int64. 75 func int64Multiply(a, b int64) (int64, bool) { 76 if a == 0 || b == 0 || a == 1 || b == 1 { 77 return a * b, true 78 } 79 if a == mostNegative || b == mostNegative { 80 return 0, false 81 } 82 c := a * b 83 return c, c/b == a 84 } 85 86 // int64MultiplyScale returns a*b, assuming b is greater than one, or false if that would overflow or underflow int64. 87 // Use when b is known to be greater than one. 88 func int64MultiplyScale(a int64, b int64) (int64, bool) { 89 if a == 0 || a == 1 { 90 return a * b, true 91 } 92 if a == mostNegative && b != 1 { 93 return 0, false 94 } 95 c := a * b 96 return c, c/b == a 97 } 98 99 // int64MultiplyScale10 multiplies a by 10, or returns false if that would overflow. This method is faster than 100 // int64Multiply(a, 10) because the compiler can optimize constant factor multiplication. 101 func int64MultiplyScale10(a int64) (int64, bool) { 102 if a == 0 || a == 1 { 103 return a * 10, true 104 } 105 if a == mostNegative { 106 return 0, false 107 } 108 c := a * 10 109 return c, c/10 == a 110 } 111 112 // int64MultiplyScale100 multiplies a by 100, or returns false if that would overflow. This method is faster than 113 // int64Multiply(a, 100) because the compiler can optimize constant factor multiplication. 114 func int64MultiplyScale100(a int64) (int64, bool) { 115 if a == 0 || a == 1 { 116 return a * 100, true 117 } 118 if a == mostNegative { 119 return 0, false 120 } 121 c := a * 100 122 return c, c/100 == a 123 } 124 125 // int64MultiplyScale1000 multiplies a by 1000, or returns false if that would overflow. This method is faster than 126 // int64Multiply(a, 1000) because the compiler can optimize constant factor multiplication. 127 func int64MultiplyScale1000(a int64) (int64, bool) { 128 if a == 0 || a == 1 { 129 return a * 1000, true 130 } 131 if a == mostNegative { 132 return 0, false 133 } 134 c := a * 1000 135 return c, c/1000 == a 136 } 137 138 // positiveScaleInt64 multiplies base by 10^scale, returning false if the 139 // value overflows. Passing a negative scale is undefined. 140 func positiveScaleInt64(base int64, scale Scale) (int64, bool) { 141 switch scale { 142 case 0: 143 return base, true 144 case 1: 145 return int64MultiplyScale10(base) 146 case 2: 147 return int64MultiplyScale100(base) 148 case 3: 149 return int64MultiplyScale1000(base) 150 case 6: 151 return int64MultiplyScale(base, 1000000) 152 case 9: 153 return int64MultiplyScale(base, 1000000000) 154 default: 155 value := base 156 var ok bool 157 for i := Scale(0); i < scale; i++ { 158 if value, ok = int64MultiplyScale(value, 10); !ok { 159 return 0, false 160 } 161 } 162 return value, true 163 } 164 } 165 166 // negativeScaleInt64 reduces base by the provided scale, rounding up, until the 167 // value is zero or the scale is reached. Passing a negative scale is undefined. 168 // The value returned, if not exact, is rounded away from zero. 169 func negativeScaleInt64(base int64, scale Scale) (result int64, exact bool) { 170 if scale == 0 { 171 return base, true 172 } 173 174 value := base 175 var fraction bool 176 for i := Scale(0); i < scale; i++ { 177 if !fraction && value%10 != 0 { 178 fraction = true 179 } 180 value = value / 10 181 if value == 0 { 182 if fraction { 183 if base > 0 { 184 return 1, false 185 } 186 return -1, false 187 } 188 return 0, true 189 } 190 } 191 if fraction { 192 if base > 0 { 193 value++ 194 } else { 195 value-- 196 } 197 } 198 return value, !fraction 199 } 200 201 func pow10Int64(b int64) int64 { 202 switch b { 203 case 0: 204 return 1 205 case 1: 206 return 10 207 case 2: 208 return 100 209 case 3: 210 return 1000 211 case 4: 212 return 10000 213 case 5: 214 return 100000 215 case 6: 216 return 1000000 217 case 7: 218 return 10000000 219 case 8: 220 return 100000000 221 case 9: 222 return 1000000000 223 case 10: 224 return 10000000000 225 case 11: 226 return 100000000000 227 case 12: 228 return 1000000000000 229 case 13: 230 return 10000000000000 231 case 14: 232 return 100000000000000 233 case 15: 234 return 1000000000000000 235 case 16: 236 return 10000000000000000 237 case 17: 238 return 100000000000000000 239 case 18: 240 return 1000000000000000000 241 default: 242 return 0 243 } 244 } 245 246 // negativeScaleInt64 returns the result of dividing base by scale * 10 and the remainder, or 247 // false if no such division is possible. Dividing by negative scales is undefined. 248 func divideByScaleInt64(base int64, scale Scale) (result, remainder int64, exact bool) { 249 if scale == 0 { 250 return base, 0, true 251 } 252 // the max scale representable in base 10 in an int64 is 18 decimal places 253 if scale >= 18 { 254 return 0, base, false 255 } 256 divisor := pow10Int64(int64(scale)) 257 return base / divisor, base % divisor, true 258 } 259 260 // removeInt64Factors divides in a loop; the return values have the property that 261 // value == result * base ^ scale 262 func removeInt64Factors(value int64, base int64) (result int64, times int32) { 263 times = 0 264 result = value 265 negative := result < 0 266 if negative { 267 result = -result 268 } 269 switch base { 270 // allow the compiler to optimize the common cases 271 case 10: 272 for result >= 10 && result%10 == 0 { 273 times++ 274 result = result / 10 275 } 276 // allow the compiler to optimize the common cases 277 case 1024: 278 for result >= 1024 && result%1024 == 0 { 279 times++ 280 result = result / 1024 281 } 282 default: 283 for result >= base && result%base == 0 { 284 times++ 285 result = result / base 286 } 287 } 288 if negative { 289 result = -result 290 } 291 return result, times 292 } 293 294 // removeBigIntFactors divides in a loop; the return values have the property that 295 // d == result * factor ^ times 296 // d may be modified in place. 297 // If d == 0, then the return values will be (0, 0) 298 func removeBigIntFactors(d, factor *big.Int) (result *big.Int, times int32) { 299 q := big.NewInt(0) 300 m := big.NewInt(0) 301 for d.Cmp(bigZero) != 0 { 302 q.DivMod(d, factor, m) 303 if m.Cmp(bigZero) != 0 { 304 break 305 } 306 times++ 307 d, q = q, d 308 } 309 return d, times 310 }