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  }