github.com/XiaoMi/Gaea@v1.2.5/parser/tidb-types/helper.go (about) 1 // Copyright 2015 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package types 15 16 import ( 17 "math" 18 "strings" 19 "unicode" 20 21 "github.com/pingcap/errors" 22 ) 23 24 // RoundFloat rounds float val to the nearest integer value with float64 format, like MySQL Round function. 25 // RoundFloat uses default rounding mode, see https://dev.mysql.com/doc/refman/5.7/en/precision-math-rounding.html 26 // so rounding use "round half away from zero". 27 // e.g, 1.5 -> 2, -1.5 -> -2. 28 func RoundFloat(f float64) float64 { 29 if math.Abs(f) < 0.5 { 30 return 0 31 } 32 33 return math.Trunc(f + math.Copysign(0.5, f)) 34 } 35 36 // Round rounds the argument f to dec decimal places. 37 // dec defaults to 0 if not specified. dec can be negative 38 // to cause dec digits left of the decimal point of the 39 // value f to become zero. 40 func Round(f float64, dec int) float64 { 41 shift := math.Pow10(dec) 42 tmp := f * shift 43 if math.IsInf(tmp, 0) { 44 return f 45 } 46 return RoundFloat(tmp) / shift 47 } 48 49 // Truncate truncates the argument f to dec decimal places. 50 // dec defaults to 0 if not specified. dec can be negative 51 // to cause dec digits left of the decimal point of the 52 // value f to become zero. 53 func Truncate(f float64, dec int) float64 { 54 shift := math.Pow10(dec) 55 tmp := f * shift 56 if math.IsInf(tmp, 0) { 57 return f 58 } 59 return math.Trunc(tmp) / shift 60 } 61 62 // GetMaxFloat gets the max float for given flen and decimal. 63 func GetMaxFloat(flen int, decimal int) float64 { 64 intPartLen := flen - decimal 65 f := math.Pow10(intPartLen) 66 f -= math.Pow10(-decimal) 67 return f 68 } 69 70 // TruncateFloat tries to truncate f. 71 // If the result exceeds the max/min float that flen/decimal allowed, returns the max/min float allowed. 72 func TruncateFloat(f float64, flen int, decimal int) (float64, error) { 73 if math.IsNaN(f) { 74 // nan returns 0 75 return 0, ErrOverflow.GenWithStackByArgs("DOUBLE", "") 76 } 77 78 maxF := GetMaxFloat(flen, decimal) 79 80 if !math.IsInf(f, 0) { 81 f = Round(f, decimal) 82 } 83 84 var err error 85 if f > maxF { 86 f = maxF 87 err = ErrOverflow.GenWithStackByArgs("DOUBLE", "") 88 } else if f < -maxF { 89 f = -maxF 90 err = ErrOverflow.GenWithStackByArgs("DOUBLE", "") 91 } 92 93 return f, errors.Trace(err) 94 } 95 96 func isSpace(c byte) bool { 97 return c == ' ' || c == '\t' 98 } 99 100 func isDigit(c byte) bool { 101 return c >= '0' && c <= '9' 102 } 103 104 func myMax(a, b int) int { 105 if a > b { 106 return a 107 } 108 return b 109 } 110 111 func myMaxInt8(a, b int8) int8 { 112 if a > b { 113 return a 114 } 115 return b 116 } 117 118 func myMin(a, b int) int { 119 if a < b { 120 return a 121 } 122 return b 123 } 124 125 func myMinInt8(a, b int8) int8 { 126 if a < b { 127 return a 128 } 129 return b 130 } 131 132 const ( 133 maxUint = uint64(math.MaxUint64) 134 uintCutOff = maxUint/uint64(10) + 1 135 intCutOff = uint64(math.MaxInt64) + 1 136 ) 137 138 // strToInt converts a string to an integer in best effort. 139 func strToInt(str string) (int64, error) { 140 str = strings.TrimSpace(str) 141 if len(str) == 0 { 142 return 0, ErrTruncated 143 } 144 negative := false 145 i := 0 146 if str[i] == '-' { 147 negative = true 148 i++ 149 } else if str[i] == '+' { 150 i++ 151 } 152 153 var ( 154 err error 155 hasNum = false 156 ) 157 r := uint64(0) 158 for ; i < len(str); i++ { 159 if !unicode.IsDigit(rune(str[i])) { 160 err = ErrTruncated 161 break 162 } 163 hasNum = true 164 if r >= uintCutOff { 165 r = 0 166 err = errors.Trace(ErrBadNumber) 167 break 168 } 169 r = r * uint64(10) 170 171 r1 := r + uint64(str[i]-'0') 172 if r1 < r || r1 > maxUint { 173 r = 0 174 err = errors.Trace(ErrBadNumber) 175 break 176 } 177 r = r1 178 } 179 if !hasNum { 180 err = ErrTruncated 181 } 182 183 if !negative && r >= intCutOff { 184 return math.MaxInt64, errors.Trace(ErrBadNumber) 185 } 186 187 if negative && r > intCutOff { 188 return math.MinInt64, errors.Trace(ErrBadNumber) 189 } 190 191 if negative { 192 r = -r 193 } 194 return int64(r), err 195 }