File: num.go

package info (click to toggle)
fq 0.9.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 106,624 kB
  • sloc: xml: 2,835; makefile: 250; sh: 241; exp: 57; ansic: 21
file content (108 lines) | stat: -rw-r--r-- 2,488 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package mathex

import (
	"fmt"
	"math"
	"math/big"
	"strconv"
	"strings"

	"github.com/wader/fq/pkg/ranges"
	"golang.org/x/exp/constraints"
)

var BasePrefixMap = map[int]string{
	2:  "0b",
	8:  "0o",
	16: "0x",
}

func DigitsInBase[T constraints.Integer](n T, basePrefix bool, base int) int {
	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
}

func PadFormatInt[T constraints.Signed](i T, base int, basePrefix bool, width int) string {
	return padFormatNumber(strconv.FormatInt(int64(i), base), base, basePrefix, width)
}

func PadFormatUint[T constraints.Unsigned](i T, base int, basePrefix bool, width int) string {
	return padFormatNumber(strconv.FormatUint(uint64(i), base), base, basePrefix, width)
}

func PadFormatBigInt(i *big.Int, base int, basePrefix bool, width int) string {
	return padFormatNumber(i.Text(base), base, basePrefix, width)
}

func Max[T constraints.Ordered](v T, vs ...T) T {
	m := v
	for _, v := range vs {
		if v > m {
			m = v
		}
	}
	return m
}

func Min[T constraints.Ordered](v T, vs ...T) T {
	m := v
	for _, v := range vs {
		if v < m {
			m = v
		}
	}
	return m
}

func Clamp[T constraints.Ordered](min, max, v T) T {
	return Max(min, Min(max, v))
}

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 {
	return fmt.Sprintf("%s-%s", Bits(r.Start).StringByteBits(base), Bits(r.Start+r.Len).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
func ZigZag[U constraints.Unsigned, S constraints.Signed](n U) S {
	return S(n>>1 ^ -(n & 1))
}