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