github.com/PandaGoAdmin/utils@v0.0.0-20211208134815-d5461603a00f/number.go (about) 1 package kgo 2 3 import ( 4 "fmt" 5 "math" 6 "math/rand" 7 "reflect" 8 "strconv" 9 "time" 10 ) 11 12 // AbsFloat 浮点型取绝对值. 13 func (kn *LkkNumber) AbsFloat(number float64) float64 { 14 return math.Abs(number) 15 } 16 17 // AbsInt 整型取绝对值. 18 func (kn *LkkNumber) AbsInt(number int64) int64 { 19 r := number >> 63 20 return (number ^ r) - r 21 } 22 23 // Range 根据范围创建数组,包含指定的元素. 24 // start为起始元素值,end为末尾元素值.若start<end,返回升序的数组;若start>end,返回降序的数组. 25 func (kn *LkkNumber) Range(start, end int) []int { 26 res := make([]int, kn.AbsInt(int64(end-start))+1) 27 for i := range res { 28 if end > start { 29 res[i] = start + i 30 } else { 31 res[i] = start - i 32 } 33 } 34 return res 35 } 36 37 // NumberFormat 以千位分隔符方式格式化一个数字. 38 // decimal为要保留的小数位数,point为小数点显示的字符,thousand为千位分隔符显示的字符. 39 // 有效数值是长度(包括小数点)为17位之内的数值,最后一位会四舍五入. 40 func (kn *LkkNumber) NumberFormat(number float64, decimal uint8, point, thousand string) string { 41 neg := false 42 if number < 0 { 43 number = -number 44 neg = true 45 } 46 dec := int(decimal) 47 // Will round off 48 str := fmt.Sprintf("%."+strconv.Itoa(dec)+"F", number) 49 prefix, suffix := "", "" 50 if dec > 0 { 51 prefix = str[:len(str)-(dec+1)] 52 suffix = str[len(str)-dec:] 53 } else { 54 prefix = str 55 } 56 sep := []byte(thousand) 57 n, l1, l2 := 0, len(prefix), len(sep) 58 // thousands sep num 59 c := (l1 - 1) / 3 60 tmp := make([]byte, l2*c+l1) 61 pos := len(tmp) - 1 62 for i := l1 - 1; i >= 0; i, n, pos = i-1, n+1, pos-1 { 63 if l2 > 0 && n > 0 && n%3 == 0 { 64 for j := range sep { 65 tmp[pos] = sep[l2-j-1] 66 pos-- 67 } 68 } 69 tmp[pos] = prefix[i] 70 } 71 s := string(tmp) 72 if dec > 0 { 73 s += point + suffix 74 } 75 if neg { 76 s = "-" + s 77 } 78 79 return s 80 } 81 82 // FloatEqual 比较两个浮点数是否相等.decimal为小数精确位数,默认为 FLOAT_DECIMAL . 83 // 有效数值是长度(包括小数点)为17位之内的数值,最后一位会四舍五入. 84 func (kn *LkkNumber) FloatEqual(f1 float64, f2 float64, decimal ...uint8) (res bool) { 85 var threshold float64 86 var dec uint8 87 if len(decimal) == 0 { 88 dec = FLOAT_DECIMAL 89 } else { 90 dec = decimal[0] 91 } 92 93 //比较精度 94 threshold = math.Pow10(-int(dec)) 95 var diff float64 96 if f1 > f2 { 97 diff = f1 - f2 98 } else { 99 diff = f2 - f1 100 } 101 102 //diff := math.Abs(f1 - f2) 103 res = diff <= threshold 104 105 return 106 } 107 108 // RandInt64 生成一个min~max范围内的随机int64整数. 109 func (kn *LkkNumber) RandInt64(min, max int64) int64 { 110 if min > max { 111 min, max = max, min 112 } else if min == max { 113 return min 114 } 115 116 //范围是否在边界内 117 mMax := int64(math.MaxInt32) 118 mMin := int64(math.MinInt32) 119 inrang := (mMin <= min && max <= mMax) || (INT64_MIN <= min && max <= 0) || (0 <= min && max <= INT64_MAX) 120 if !inrang { 121 min, max = mMin, mMax 122 } 123 124 r := rand.New(rand.NewSource(time.Now().UnixNano())) 125 return r.Int63n(max-min) + min 126 } 127 128 // RandInt 生成一个min~max范围内的随机int整数. 129 func (kn *LkkNumber) RandInt(min, max int) int { 130 if min > max { 131 min, max = max, min 132 } else if min == max { 133 return min 134 } 135 136 //范围是否在边界内 137 mMax := int(math.MaxInt32) 138 mMin := int(math.MinInt32) 139 inrang := (mMin <= min && max <= mMax) || (INT_MIN <= min && max <= 0) || (0 <= min && max <= INT_MAX) 140 if !inrang { 141 min, max = mMin, mMax 142 } 143 144 r := rand.New(rand.NewSource(time.Now().UnixNano())) 145 return r.Intn(max-min) + min 146 } 147 148 // Rand RandInt的别名. 149 func (kn *LkkNumber) Rand(min, max int) int { 150 return kn.RandInt(min, max) 151 } 152 153 // RandFloat64 生成一个min~max范围内的随机float64浮点数. 154 func (kn *LkkNumber) RandFloat64(min, max float64) float64 { 155 if min > max { 156 min, max = max, min 157 } 158 159 //范围是否在边界内 160 mMax := float64(math.MaxFloat32) 161 mMin := -mMax 162 inrang := (mMin <= min && max <= mMax) || (-math.MaxFloat64 <= min && max <= 0) || (0 <= min && max <= math.MaxFloat64) 163 if !inrang { 164 min, max = mMin, mMax 165 } 166 167 r := rand.New(rand.NewSource(time.Now().UnixNano())) 168 num := r.Float64() 169 170 res := min + num*(max-min) 171 return res 172 } 173 174 // Round 对浮点数(的整数)进行四舍五入. 175 func (kn *LkkNumber) Round(value float64) float64 { 176 return math.Floor(value + 0.5) 177 } 178 179 // RoundPlus 对指定的小数位进行四舍五入. 180 // precision为小数位数. 181 func (kn *LkkNumber) RoundPlus(value float64, precision uint8) float64 { 182 shift := math.Pow(10, float64(precision)) 183 return kn.Round(value*shift) / shift 184 } 185 186 // Floor 向下取整. 187 func (kn *LkkNumber) Floor(value float64) float64 { 188 return math.Floor(value) 189 } 190 191 // Ceil 向上取整. 192 func (kn *LkkNumber) Ceil(value float64) float64 { 193 return math.Ceil(value) 194 } 195 196 // MaxInt 整数序列求最大值. 197 func (kn *LkkNumber) MaxInt(nums ...int) (res int) { 198 if len(nums) < 1 { 199 panic("[MaxInt]` nums length is less than 1") 200 } 201 202 res = nums[0] 203 for _, v := range nums { 204 if v > res { 205 res = v 206 } 207 } 208 209 return 210 } 211 212 // MaxFloat64 64位浮点数序列求最大值. 213 func (kn *LkkNumber) MaxFloat64(nums ...float64) (res float64) { 214 if len(nums) < 1 { 215 panic("[MaxFloat64]` nums length is less than 1") 216 } 217 218 res = nums[0] 219 for _, v := range nums { 220 res = math.Max(res, v) 221 } 222 223 return 224 } 225 226 // Max 取出任意类型中数值类型的最大值,无数值类型则为0. 227 func (kn *LkkNumber) Max(nums ...interface{}) (res float64) { 228 if len(nums) < 1 { 229 panic("[Max]` nums length is less than 1") 230 } 231 232 var err error 233 var val float64 234 res, _ = numeric2Float(nums[0]) 235 for _, v := range nums { 236 val, err = numeric2Float(v) 237 if err == nil { 238 res = math.Max(res, val) 239 } 240 } 241 242 return 243 } 244 245 // MinInt 整数序列求最小值. 246 func (kn *LkkNumber) MinInt(nums ...int) (res int) { 247 if len(nums) < 1 { 248 panic("[MinInt]` nums length is less than 1") 249 } 250 res = nums[0] 251 for _, v := range nums { 252 if v < res { 253 res = v 254 } 255 } 256 257 return 258 } 259 260 // MinFloat64 64位浮点数序列求最小值. 261 func (kn *LkkNumber) MinFloat64(nums ...float64) (res float64) { 262 if len(nums) < 1 { 263 panic("[MinFloat64]` nums length is less than 1") 264 } 265 res = nums[0] 266 for _, v := range nums { 267 res = math.Min(res, v) 268 } 269 270 return 271 } 272 273 // Min 取出任意类型中数值类型的最小值,无数值类型则为0. 274 func (kn *LkkNumber) Min(nums ...interface{}) (res float64) { 275 if len(nums) < 1 { 276 panic("[Min]` nums length is less than 1") 277 } 278 279 var err error 280 var val float64 281 res, _ = numeric2Float(nums[0]) 282 for _, v := range nums { 283 val, err = numeric2Float(v) 284 if err == nil { 285 res = math.Min(res, val) 286 } 287 } 288 289 return 290 } 291 292 // Exp 计算 e 的指数. 293 func (kn *LkkNumber) Exp(x float64) float64 { 294 return math.Exp(x) 295 } 296 297 // Expm1 返回 exp(x) - 1. 298 func (kn *LkkNumber) Expm1(x float64) float64 { 299 return math.Exp(x) - 1 300 } 301 302 // Pow 指数表达式,求x的y次方. 303 func (kn *LkkNumber) Pow(x, y float64) float64 { 304 return math.Pow(x, y) 305 } 306 307 // Log 对数表达式,求以y为底x的对数. 308 func (kn *LkkNumber) Log(x, y float64) float64 { 309 return math.Log(x) / math.Log(y) 310 } 311 312 // ByteFormat 格式化文件比特大小. 313 // size为文件大小,decimal为要保留的小数位数,delimiter为数字和单位间的分隔符. 314 func (kn *LkkNumber) ByteFormat(size float64, decimal uint8, delimiter string) string { 315 var arr = []string{"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", Unknown} 316 var pos int = 0 317 var j float64 = float64(size) 318 for { 319 if size >= 1024 { 320 size = size / 1024 321 j = j / 1024 322 pos++ 323 } else { 324 break 325 } 326 } 327 if pos >= len(arr) { // fixed out index bug 328 pos = len(arr) - 1 329 } 330 331 return fmt.Sprintf("%."+strconv.Itoa(int(decimal))+"f%s%s", j, delimiter, arr[pos]) 332 } 333 334 // IsOdd 变量是否奇数. 335 func (kn *LkkNumber) IsOdd(val int) bool { 336 return val%2 != 0 337 } 338 339 // IsEven 变量是否偶数. 340 func (kn *LkkNumber) IsEven(val int) bool { 341 return val%2 == 0 342 } 343 344 // NumSign 返回数值的符号.值>0为1,<0为-1,其他为0. 345 func (kn *LkkNumber) NumSign(value float64) (res int8) { 346 if value > 0 { 347 res = 1 348 } else if value < 0 { 349 res = -1 350 } else { 351 res = 0 352 } 353 354 return 355 } 356 357 // IsNegative 数值是否为负数. 358 func (kn *LkkNumber) IsNegative(value float64) bool { 359 return value < 0 360 } 361 362 // IsPositive 数值是否为正数. 363 func (kn *LkkNumber) IsPositive(value float64) bool { 364 return value > 0 365 } 366 367 // IsNonNegative 数值是否为非负数. 368 func (kn *LkkNumber) IsNonNegative(value float64) bool { 369 return value >= 0 370 } 371 372 // IsNonPositive 数值是否为非正数. 373 func (kn *LkkNumber) IsNonPositive(value float64) bool { 374 return value <= 0 375 } 376 377 // IsWhole 数值是否为整数. 378 func (kn *LkkNumber) IsWhole(value float64) bool { 379 return math.Remainder(value, 1) == 0 380 } 381 382 // IsNatural 数值是否为自然数(包括0). 383 func (kn *LkkNumber) IsNatural(value float64) bool { 384 return kn.IsNonNegative(value) && kn.IsWhole(value) 385 } 386 387 // InRangeInt 数值是否在2个整数范围内. 388 func (kn *LkkNumber) InRangeInt(value, left, right int) bool { 389 if left > right { 390 left, right = right, left 391 } 392 return value >= left && value <= right 393 } 394 395 // InRangeFloat64 数值是否在2个64位浮点数范围内. 396 func (kn *LkkNumber) InRangeFloat64(value, left, right float64) bool { 397 if left > right { 398 left, right = right, left 399 } 400 return value >= left && value <= right 401 } 402 403 // InRangeFloat32 数值是否在2个32位浮点数范围内. 404 func (kn *LkkNumber) InRangeFloat32(value, left, right float32) bool { 405 if left > right { 406 left, right = right, left 407 } 408 return value >= left && value <= right 409 } 410 411 // InRange 数值是否在某个范围内,将自动转换类型再比较. 412 func (kn *LkkNumber) InRange(value interface{}, left interface{}, right interface{}) bool { 413 reflectValue := reflect.TypeOf(value).Kind() 414 reflectLeft := reflect.TypeOf(left).Kind() 415 reflectRight := reflect.TypeOf(right).Kind() 416 417 if reflectValue == reflect.Int && reflectLeft == reflect.Int && reflectRight == reflect.Int { 418 return kn.InRangeInt(value.(int), left.(int), right.(int)) 419 } else if reflectValue == reflect.Float32 && reflectLeft == reflect.Float32 && reflectRight == reflect.Float32 { 420 return kn.InRangeFloat32(value.(float32), left.(float32), right.(float32)) 421 } else if reflectValue == reflect.Float64 && reflectLeft == reflect.Float64 && reflectRight == reflect.Float64 { 422 return kn.InRangeFloat64(value.(float64), left.(float64), right.(float64)) 423 } else if KConv.IsInt(value) && KConv.IsInt(left) && KConv.IsInt(right) { 424 return kn.InRangeInt(KConv.ToInt(value), KConv.ToInt(left), KConv.ToInt(right)) 425 } else if KConv.IsNumeric(value) && KConv.IsNumeric(left) && KConv.IsNumeric(right) { 426 return kn.InRangeFloat64(KConv.ToFloat(value), KConv.ToFloat(left), KConv.ToFloat(right)) 427 } 428 429 return false 430 } 431 432 // SumInt 整数求和. 433 func (kn *LkkNumber) SumInt(nums ...int) int { 434 var sum int 435 for _, v := range nums { 436 sum += v 437 } 438 return sum 439 } 440 441 // SumFloat64 浮点数求和. 442 func (kn *LkkNumber) SumFloat64(nums ...float64) float64 { 443 var sum float64 444 for _, v := range nums { 445 sum += v 446 } 447 return sum 448 } 449 450 // Sum 对任意类型序列中的数值类型求和,忽略非数值的. 451 func (kn *LkkNumber) Sum(nums ...interface{}) (res float64) { 452 var err error 453 var val float64 454 for _, v := range nums { 455 val, err = numeric2Float(v) 456 if err == nil { 457 res += val 458 } 459 } 460 461 return 462 } 463 464 // AverageInt 对整数序列求平均值. 465 func (kn *LkkNumber) AverageInt(nums ...int) (res float64) { 466 length := len(nums) 467 if length == 0 { 468 return 469 } else if length == 1 { 470 res = float64(nums[0]) 471 } else { 472 total := kn.SumInt(nums...) 473 res = float64(total) / float64(length) 474 } 475 476 return 477 } 478 479 // AverageFloat64 对浮点数序列求平均值. 480 func (kn *LkkNumber) AverageFloat64(nums ...float64) (res float64) { 481 length := len(nums) 482 if length == 0 { 483 return 484 } else if length == 1 { 485 res = nums[0] 486 } else { 487 total := kn.SumFloat64(nums...) 488 res = total / float64(length) 489 } 490 491 return 492 } 493 494 // Average 对任意类型序列中的数值类型求平均值,忽略非数值的. 495 func (kn *LkkNumber) Average(nums ...interface{}) (res float64) { 496 length := len(nums) 497 if length == 0 { 498 return 499 } else if length == 1 { 500 res, _ = numeric2Float(nums[0]) 501 } else { 502 var count int 503 var err error 504 var val, total float64 505 for _, v := range nums { 506 val, err = numeric2Float(v) 507 if err == nil { 508 count++ 509 total += val 510 } 511 } 512 513 res = total / float64(count) 514 } 515 516 return 517 } 518 519 // Percent 返回百分比((val/total) *100). 520 func (kn *LkkNumber) Percent(val, total interface{}) float64 { 521 t := toFloat(total) 522 if t == 0 { 523 return float64(0) 524 } 525 526 v := toFloat(val) 527 528 return (v / t) * 100 529 } 530 531 // IsNan 是否为“非数值”.注意,这里复数也算“非数值”. 532 func (kn *LkkNumber) IsNan(val interface{}) bool { 533 if isFloat(val) { 534 return math.IsNaN(KConv.ToFloat(val)) 535 } 536 537 return !isNumeric(val) 538 } 539 540 // IsNaturalRange 是否连续的自然数数组/切片,如[0,1,2,3...],其中不能有间断. 541 // strict为是否严格检查元素的顺序. 542 func (kn *LkkNumber) IsNaturalRange(arr []int, strict bool) (res bool) { 543 n := len(arr) 544 if n == 0 { 545 return 546 } 547 548 orig := kn.Range(0, n-1) 549 ctyp := COMPARE_ONLY_VALUE 550 551 if strict { 552 ctyp = COMPARE_BOTH_KEYVALUE 553 } 554 555 diff := KArr.ArrayDiff(orig, arr, ctyp) 556 557 res = len(diff) == 0 558 return 559 } 560 561 // GeoDistance 获取地理距离/米. 562 // 参数分别为两点的经度和纬度:lat:-90~90,lng:-180~180. 563 func (kn *LkkNumber) GeoDistance(lng1, lat1, lng2, lat2 float64) float64 { 564 //地球半径 565 radius := 6371000.0 566 rad := math.Pi / 180.0 567 568 lng1 = lng1 * rad 569 lat1 = lat1 * rad 570 lng2 = lng2 * rad 571 lat2 = lat2 * rad 572 theta := lng2 - lng1 573 574 dist := math.Acos(math.Sin(lat1)*math.Sin(lat2) + math.Cos(lat1)*math.Cos(lat2)*math.Cos(theta)) 575 return dist * radius 576 } 577 578 // NearLogarithm 求以 base 为底 num 的对数临近值. 579 // num为自然数,base为正整数,left是否向左取整. 580 func (kn *LkkNumber) NearLogarithm(num, base int, left bool) int { 581 if num < 0 { 582 panic("[nearLogarithm]` num must be non-negative") 583 } else if base <= 0 { 584 panic("[nearLogarithm]` base must be a positive integer") 585 } 586 587 res := kn.Log(float64(num), float64(base)) 588 if left { 589 return int(kn.Floor(res)) 590 } 591 592 return int(kn.Ceil(res)) 593 } 594 595 // SplitNaturalNum 将自然数 num 按底数 base 进行拆解. 596 func (kn *LkkNumber) SplitNaturalNum(num, base int) []int { 597 var res []int 598 599 if !kn.IsNatural(toFloat(num)) { 600 panic("[splitNaturalNum]` num must be a natural number") 601 } else if base <= 0 { 602 panic("[splitNaturalNum]` base must be a positive integer") 603 } 604 605 var n, child int 606 for num > base { 607 n = kn.NearLogarithm(num, base, true) 608 child = int(math.Pow(float64(base), float64(n))) 609 num -= child 610 res = append(res, child) 611 } 612 613 if (num > 0) || (num == 0 && len(res) == 0) { 614 res = append(res, num) 615 } 616 617 return res 618 }