github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/api/resource/scale_int.go (about)

     1  /*
     2  Copyright 2015 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"
    21  	"math/big"
    22  	"sync"
    23  )
    24  
    25  var (
    26  	// A sync pool to reduce allocation.
    27  	intPool  sync.Pool
    28  	maxInt64 = big.NewInt(math.MaxInt64)
    29  )
    30  
    31  func init() {
    32  	intPool.New = func() interface{} {
    33  		return &big.Int{}
    34  	}
    35  }
    36  
    37  // scaledValue scales given unscaled value from scale to new Scale and returns
    38  // an int64. It ALWAYS rounds up the result when scale down. The final result might
    39  // overflow.
    40  //
    41  // scale, newScale represents the scale of the unscaled decimal.
    42  // The mathematical value of the decimal is unscaled * 10**(-scale).
    43  func scaledValue(unscaled *big.Int, scale, newScale int) int64 {
    44  	dif := scale - newScale
    45  	if dif == 0 {
    46  		return unscaled.Int64()
    47  	}
    48  
    49  	// Handle scale up
    50  	// This is an easy case, we do not need to care about rounding and overflow.
    51  	// If any intermediate operation causes overflow, the result will overflow.
    52  	if dif < 0 {
    53  		return unscaled.Int64() * int64(math.Pow10(-dif))
    54  	}
    55  
    56  	// Handle scale down
    57  	// We have to be careful about the intermediate operations.
    58  
    59  	// fast path when unscaled < max.Int64 and exp(10,dif) < max.Int64
    60  	const log10MaxInt64 = 19
    61  	if unscaled.Cmp(maxInt64) < 0 && dif < log10MaxInt64 {
    62  		divide := int64(math.Pow10(dif))
    63  		result := unscaled.Int64() / divide
    64  		mod := unscaled.Int64() % divide
    65  		if mod != 0 {
    66  			return result + 1
    67  		}
    68  		return result
    69  	}
    70  
    71  	// We should only convert back to int64 when getting the result.
    72  	divisor := intPool.Get().(*big.Int)
    73  	exp := intPool.Get().(*big.Int)
    74  	result := intPool.Get().(*big.Int)
    75  	defer func() {
    76  		intPool.Put(divisor)
    77  		intPool.Put(exp)
    78  		intPool.Put(result)
    79  	}()
    80  
    81  	// divisor = 10^(dif)
    82  	// TODO: create loop up table if exp costs too much.
    83  	divisor.Exp(bigTen, exp.SetInt64(int64(dif)), nil)
    84  	// reuse exp
    85  	remainder := exp
    86  
    87  	// result = unscaled / divisor
    88  	// remainder = unscaled % divisor
    89  	result.DivMod(unscaled, divisor, remainder)
    90  	if remainder.Sign() != 0 {
    91  		return result.Int64() + 1
    92  	}
    93  
    94  	return result.Int64()
    95  }