2022-08-12 16:27:51 +03:00
|
|
|
package mathex
|
2020-06-08 03:29:51 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math"
|
2022-01-14 03:58:42 +03:00
|
|
|
"math/big"
|
2020-06-08 03:29:51 +03:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2021-08-17 13:06:32 +03:00
|
|
|
|
2022-08-12 16:27:51 +03:00
|
|
|
"golang.org/x/exp/constraints"
|
|
|
|
|
2021-08-17 13:06:32 +03:00
|
|
|
"github.com/wader/fq/pkg/ranges"
|
2020-06-08 03:29:51 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
var BasePrefixMap = map[int]string{
|
|
|
|
2: "0b",
|
|
|
|
8: "0o",
|
|
|
|
16: "0x",
|
|
|
|
}
|
|
|
|
|
2022-08-12 16:27:51 +03:00
|
|
|
func DigitsInBase[T constraints.Integer](n T, basePrefix bool, base int) int {
|
2020-06-08 03:29:51 +03:00
|
|
|
prefixLen := 0
|
|
|
|
if basePrefix {
|
|
|
|
prefixLen = len(BasePrefixMap[base])
|
|
|
|
}
|
|
|
|
if n == 0 {
|
|
|
|
return prefixLen + 1
|
|
|
|
}
|
|
|
|
return prefixLen + int(1+math.Floor(math.Log(float64(n))/math.Log(float64(base))))
|
|
|
|
}
|
|
|
|
|
|
|
|
func padFormatNumber(s string, base int, basePrefix bool, width int) string {
|
|
|
|
prefixStr := ""
|
|
|
|
if basePrefix {
|
|
|
|
prefixStr = BasePrefixMap[base]
|
|
|
|
}
|
|
|
|
padStr := ""
|
|
|
|
padN := width - len(s) - len(prefixStr)
|
|
|
|
if padN > 0 {
|
|
|
|
// TODO: something faster?
|
|
|
|
padStr = strings.Repeat("0", padN)
|
|
|
|
}
|
|
|
|
return prefixStr + padStr + s
|
|
|
|
}
|
|
|
|
|
2022-08-12 16:27:51 +03:00
|
|
|
func PadFormatInt[T constraints.Signed](i T, base int, basePrefix bool, width int) string {
|
|
|
|
return padFormatNumber(strconv.FormatInt(int64(i), base), base, basePrefix, width)
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
|
|
|
|
2022-08-12 16:27:51 +03:00
|
|
|
func PadFormatUint[T constraints.Unsigned](i T, base int, basePrefix bool, width int) string {
|
|
|
|
return padFormatNumber(strconv.FormatUint(uint64(i), base), base, basePrefix, width)
|
2022-01-14 03:58:42 +03:00
|
|
|
}
|
2020-06-08 03:29:51 +03:00
|
|
|
|
2022-01-14 03:58:42 +03:00
|
|
|
func PadFormatBigInt(i *big.Int, base int, basePrefix bool, width int) string {
|
|
|
|
return padFormatNumber(i.Text(base), base, basePrefix, width)
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
2022-01-14 03:58:42 +03:00
|
|
|
|
2022-08-31 11:34:32 +03:00
|
|
|
func Max[T constraints.Ordered](v T, vs ...T) T {
|
2022-08-12 16:27:51 +03:00
|
|
|
m := v
|
|
|
|
for _, v := range vs {
|
|
|
|
if v > m {
|
|
|
|
m = v
|
|
|
|
}
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
2022-08-12 16:27:51 +03:00
|
|
|
return m
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
|
|
|
|
2022-08-31 11:34:32 +03:00
|
|
|
func Min[T constraints.Ordered](v T, vs ...T) T {
|
2022-08-12 16:27:51 +03:00
|
|
|
m := v
|
|
|
|
for _, v := range vs {
|
|
|
|
if v < m {
|
|
|
|
m = v
|
|
|
|
}
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
2022-08-12 16:27:51 +03:00
|
|
|
return m
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
|
|
|
|
2022-08-31 11:34:32 +03:00
|
|
|
func Clamp[T constraints.Ordered](min, max, v T) T {
|
2022-08-12 16:27:51 +03:00
|
|
|
return Max(min, Min(max, v))
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type Bits uint64
|
|
|
|
|
|
|
|
func (b Bits) StringByteBits(base int) string {
|
|
|
|
if b&0x7 != 0 {
|
|
|
|
return BasePrefixMap[base] + strconv.FormatUint(uint64(b)>>3, base) + "." + strconv.FormatUint(uint64(b)&0x7, base)
|
|
|
|
}
|
|
|
|
return BasePrefixMap[base] + strconv.FormatUint(uint64(b>>3), base)
|
|
|
|
}
|
|
|
|
|
|
|
|
type BitRange ranges.Range
|
|
|
|
|
|
|
|
func (r BitRange) StringByteBits(base int) string {
|
|
|
|
if r.Len == 0 {
|
|
|
|
return fmt.Sprintf("%s-NA", Bits(r.Start).StringByteBits(base))
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("%s-%s", Bits(r.Start).StringByteBits(base), Bits(r.Start+r.Len-1).StringByteBits(base))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TwosComplement(nBits int, n uint64) int64 {
|
|
|
|
if n&(1<<(nBits-1)) > 0 {
|
|
|
|
// two's complement
|
|
|
|
return -int64((^n & ((1 << nBits) - 1)) + 1)
|
|
|
|
}
|
|
|
|
return int64(n)
|
|
|
|
}
|
|
|
|
|
|
|
|
// decode zigzag encoded integer
|
|
|
|
// https://developers.google.com/protocol-buffers/docs/encoding
|
2022-08-31 11:34:32 +03:00
|
|
|
func ZigZag[U constraints.Unsigned, S constraints.Signed](n U) S {
|
|
|
|
return S(n>>1 ^ -(n & 1))
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|