-
Notifications
You must be signed in to change notification settings - Fork 0
/
normalize.go
55 lines (48 loc) · 1.17 KB
/
normalize.go
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
package ucum
import (
"github.com/iimos/play/ucum/internal/data"
"github.com/iimos/play/ucum/internal/types"
"math/big"
)
func Normalize(unit Unit) Unit {
return Unit{u: normalize(unit.u)}
}
func normalize(unit types.Unit) types.Unit {
ret := types.Unit{
Coeff: (&big.Rat{}).Set(unit.Coeff),
Components: make(map[types.ComponentKey]int, len(unit.Components)),
}
for key, exponent := range unit.Components {
if key.AtomCode == "" {
k := types.ComponentKey{AtomCode: "1"}
ret.Components[k] += exponent
continue
}
normed, ok := data.Conv[key.AtomCode]
if !ok {
k := types.ComponentKey{AtomCode: key.AtomCode} // strip annotation
ret.Components[k] += exponent
continue
}
coeff := pow(normed.Coeff, exponent)
ret.Coeff = ret.Coeff.Mul(ret.Coeff, coeff)
for key2, exponent2 := range normed.Components {
ret.Components[key2] += exponent * exponent2
}
}
return ret
}
func pow(num *big.Rat, exp int) *big.Rat {
cpy := new(big.Rat).Set(num)
if exp < 0 {
cpy = cpy.Inv(cpy)
exp = -exp
} else if exp == 0 {
cpy.SetFrac64(0, 1)
}
multiplier := new(big.Rat).Set(cpy)
for i := exp; i > 1; i-- {
cpy.Mul(cpy, multiplier)
}
return cpy
}