github.com/m3db/m3@v1.5.0/src/dbnode/encoding/m3tsz/m3tsz.go (about) 1 // Copyright (c) 2016 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package m3tsz 22 23 import ( 24 "errors" 25 "math" 26 ) 27 28 const ( 29 // DefaultIntOptimizationEnabled is the default switch for m3tsz int optimization 30 DefaultIntOptimizationEnabled = true 31 32 // OpcodeZeroSig indicates that there were zero significant digits. 33 OpcodeZeroSig = 0x0 34 // OpcodeNonZeroSig indicates that there were a non-zero number of significant digits. 35 OpcodeNonZeroSig = 0x1 36 37 // NumSigBits is the number of bits required to encode the maximum possible value 38 // of significant digits. 39 NumSigBits = 6 40 41 opcodeZeroValueXOR = 0x0 42 opcodeContainedValueXOR = 0x2 43 opcodeUncontainedValueXOR = 0x3 44 opcodeNoUpdateSig = 0x0 45 opcodeUpdateSig = 0x1 46 opcodeUpdate = 0x0 47 opcodeNoUpdate = 0x1 48 opcodeUpdateMult = 0x1 49 opcodeNoUpdateMult = 0x0 50 opcodePositive = 0x0 51 opcodeNegative = 0x1 52 opcodeRepeat = 0x1 53 opcodeNoRepeat = 0x0 54 opcodeFloatMode = 0x1 55 opcodeIntMode = 0x0 56 57 sigDiffThreshold = uint8(3) 58 sigRepeatThreshold = uint8(5) 59 60 maxMult = uint8(6) 61 numMultBits = 3 62 ) 63 64 var ( 65 maxInt = float64(math.MaxInt64) 66 minInt = float64(math.MinInt64) 67 maxOptInt = math.Pow(10.0, 13) // Max int for int optimization 68 multipliers = createMultipliers() 69 errInvalidMultiplier = errors.New("supplied multiplier is invalid") 70 ) 71 72 // convertToIntFloat takes a float64 val and the current max multiplier 73 // and attempts to transform the float into an int with multiplier. There 74 // is potential for a small accuracy loss for float values that are very 75 // close to ints eg. 46.000000000000001 would be returned as 46. This only 76 // applies to values where the next possible smaller or larger float changes 77 // the integer component of the float 78 func convertToIntFloat(v float64, curMaxMult uint8) (float64, uint8, bool, error) { 79 if curMaxMult == 0 && v < maxInt { 80 // Quick check for vals that are already ints 81 i, r := math.Modf(v) 82 if r == 0 { 83 return i, 0, false, nil 84 } 85 } 86 87 if curMaxMult > maxMult { 88 return 0.0, 0, false, errInvalidMultiplier 89 } 90 91 sign := 1.0 92 if v < 0 { 93 sign = -1.0 94 } 95 96 for mult := curMaxMult; mult <= maxMult; mult++ { 97 val := v * multipliers[int(mult)] * sign 98 if val >= maxOptInt { 99 break 100 } 101 i, r := math.Modf(val) 102 if r == 0 { 103 return sign * i, mult, false, nil 104 } else if r < 0.1 { 105 // Round down and check 106 if math.Nextafter(val, 0) <= i { 107 return sign * i, mult, false, nil 108 } 109 } else if r > 0.9 { 110 // Round up and check 111 next := i + 1 112 if math.Nextafter(val, next) >= next { 113 return sign * next, mult, false, nil 114 } 115 } 116 } 117 118 return v, 0, true, nil 119 } 120 121 func convertFromIntFloat(val float64, mult uint8) float64 { 122 if mult == 0 { 123 return val 124 } 125 126 return val / multipliers[int(mult)] 127 } 128 129 // createMultipliers creates all the multipliers up to maxMult 130 // and places them into a slice 131 func createMultipliers() []float64 { 132 multipliers := make([]float64, maxMult+1) 133 base := 1.0 134 for i := 0; i <= int(maxMult); i++ { 135 multipliers[i] = base 136 base = base * 10.0 137 } 138 139 return multipliers 140 }