mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-05-03 05:33:30 -04:00
The goutil that OpenCloud currently uses is one version from the release that adds FreeBSD support, this now compiles successfully on FreeBSD.
141 lines
3.2 KiB
Go
141 lines
3.2 KiB
Go
// Package mathutil provide math(int, number) util functions. eg: convert, math calc, random
|
|
package mathutil
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gookit/goutil/comdef"
|
|
"github.com/gookit/goutil/internal/checkfn"
|
|
)
|
|
|
|
// Mul computes the `a*b` value, rounding the result.
|
|
func Mul[T1, T2 comdef.Number](a T1, b T2) float64 {
|
|
return math.Round(SafeFloat(a) * SafeFloat(b))
|
|
}
|
|
|
|
// MulF2i computes the float64 type a * b value, rounding the result to an integer.
|
|
func MulF2i(a, b float64) int {
|
|
return int(math.Round(a * b))
|
|
}
|
|
|
|
// Div computes the `a/b` value, result uses a round handle.
|
|
func Div[T1, T2 comdef.Number](a T1, b T2) float64 {
|
|
return math.Round(SafeFloat(a) / SafeFloat(b))
|
|
}
|
|
|
|
// DivInt computes the int type a / b value, rounding the result to an integer.
|
|
func DivInt[T comdef.Integer](a, b T) int {
|
|
fv := math.Round(float64(a) / float64(b))
|
|
return int(fv)
|
|
}
|
|
|
|
// DivF2i computes the float64 type a / b value, rounding the result to an integer.
|
|
func DivF2i(a, b float64) int {
|
|
return int(math.Round(a / b))
|
|
}
|
|
|
|
// Percent returns a value percentage of the total. eg: 1/100 = 1.0%
|
|
func Percent(val, total int) float64 {
|
|
if total == 0 {
|
|
return float64(0)
|
|
}
|
|
return (float64(val) / float64(total)) * 100
|
|
}
|
|
|
|
// Range a number range expression, and handle each value. eg: "1-100,123,124"
|
|
func Range(expr string, handle func(val int)) error {
|
|
for _, item := range strings.Split(expr, ",") {
|
|
item = strings.TrimSpace(item)
|
|
if item == "" {
|
|
continue
|
|
}
|
|
|
|
// is range, eg: "1-100", "-20-2"
|
|
if idx := checkfn.IndexByteAfter(item, '-', 1); idx > 0 {
|
|
start, end, err := parseIntRange(item, idx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// range number
|
|
for i := start; i <= end; i++ {
|
|
handle(i)
|
|
}
|
|
} else {
|
|
iVal, err := strconv.Atoi(item)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid integer value: %q", item)
|
|
}
|
|
handle(iVal)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Expand a number range expression to int[]. eg: "1-100,123,124"
|
|
func Expand(expr string) ([]int, error) {
|
|
var nums []int
|
|
for _, item := range strings.Split(expr, ",") {
|
|
if item == "" {
|
|
continue
|
|
}
|
|
|
|
// is range, eg: "1-100", "-20-2"
|
|
if idx := checkfn.IndexByteAfter(item, '-', 1); idx > 0 {
|
|
ints, err := expandIntRange(item, idx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
nums = append(nums, ints...)
|
|
} else {
|
|
iVal, err := strconv.Atoi(item)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid integer value: %q", item)
|
|
}
|
|
nums = append(nums, iVal)
|
|
}
|
|
}
|
|
return nums, nil
|
|
}
|
|
|
|
// 处理范围格式
|
|
// eg: "1-30" -> [1, 30], "-20-2" -> [-20, 2]
|
|
func parseIntRange(value string, sepIdx int) (min int, max int, err error) {
|
|
start, end := value[:sepIdx], value[sepIdx+1:]
|
|
|
|
min, err = strconv.Atoi(start)
|
|
if err != nil {
|
|
err = fmt.Errorf("invalid range start value: %q", start)
|
|
return
|
|
}
|
|
|
|
max, err = strconv.Atoi(end)
|
|
if err != nil {
|
|
err = fmt.Errorf("invalid range end value: %q", end)
|
|
return
|
|
}
|
|
|
|
// swap min and max
|
|
if min > max {
|
|
min, max = max, min
|
|
}
|
|
return
|
|
}
|
|
|
|
// 将 "1-30" 转换为 int 列表
|
|
func expandIntRange(value string, sepIdx int) ([]int, error) {
|
|
var ints []int
|
|
start, end, err := parseIntRange(value, sepIdx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for i := start; i <= end; i++ {
|
|
ints = append(ints, i)
|
|
}
|
|
return ints, nil
|
|
}
|