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  }