func ParseCurrency(s string) (Currency, error) {
	i, ok := new(big.Int).SetString(s, 10)
	if !ok {
		return ZeroCurrency, errors.New("not an integer")
	} else if i.Sign() < 0 {
		return ZeroCurrency, errors.New("value cannot be negative")
	} else if i.BitLen() > 128 {
		return ZeroCurrency, errors.New("value overflows Currency representation")
	}
	return NewCurrency(i.Uint64(), new(big.Int).Rsh(i, 64).Uint64()), nil
}
ParseCurrency parses s as a Currency value. The format of s should match the
return value of the ExactString method, i.e. an unsigned base-10 integer.
package sunyata
import (
	"encoding/binary"
	"errors"
	"math/big"
	"math/bits"
	"strings"
)
var BaseUnitsPerCoin = NewCurrency64(1e9)
var ZeroCurrency Currency
type Currency struct {
	Lo, Hi uint64
}
func (c Currency) IsZero() bool {
	return c == ZeroCurrency
}
func (c Currency) Equals(v Currency) bool {
	return c == v
}
func (c Currency) Cmp(v Currency) int {
	if c == v {
		return 0
	} else if c.Hi < v.Hi || (c.Hi == v.Hi && c.Lo < v.Lo) {
		return -1
	} else {
		return 1
	}
}
func (c Currency) Add(v Currency) Currency {
	s, overflow := c.AddWithOverflow(v)
	if overflow {
		panic("overflow")
	}
	return s
}
func (c Currency) AddWithOverflow(v Currency) (Currency, bool) {
	lo, carry := bits.Add64(c.Lo, v.Lo, 0)
	hi, carry := bits.Add64(c.Hi, v.Hi, carry)
	return Currency{lo, hi}, carry != 0
}
func (c Currency) Sub(v Currency) Currency {
	lo, borrow := bits.Sub64(c.Lo, v.Lo, 0)
	hi, borrow := bits.Sub64(c.Hi, v.Hi, borrow)
	if borrow != 0 {
		panic("underflow")
	}
	return Currency{lo, hi}
}
func (c Currency) Mul64(v uint64) Currency {
	hi0, lo0 := bits.Mul64(c.Lo, v)
	hi1, lo1 := bits.Mul64(c.Hi, v)
	hi2, c0 := bits.Add64(hi0, lo1, 0)
	if hi1 != 0 || c0 != 0 {
		panic("overflow")
	}
	return Currency{lo0, hi2}
}
func (c Currency) Div(v Currency) Currency {
	q, _ := c.quoRem(v)
	return q
}
func (c Currency) Div64(v uint64) Currency {
	q, _ := c.quoRem64(v)
	return q
}
func (c Currency) quoRem(v Currency) (q, r Currency) {
	if v.Hi == 0 {
		var r64 uint64
		q, r64 = c.quoRem64(v.Lo)
		r = NewCurrency64(r64)
	} else {
		n := bits.LeadingZeros64(v.Hi)
		v1 := NewCurrency(v.Lo<<n, v.Hi<<n|v.Lo>>(64-n))  
		u1 := NewCurrency(c.Lo>>1|c.Hi<<63, c.Hi>>1)      
		tq, _ := bits.Div64(u1.Hi, u1.Lo, v1.Hi)
		tq >>= 63 - n
		if tq != 0 {
			tq--
		}
		q = NewCurrency64(tq)
		r = c.Sub(v.Mul64(tq))
		if r.Cmp(v) >= 0 {
			if q.Lo++; q.Lo == 0 {
				q.Hi++
			}
			r = r.Sub(v)
		}
	}
	return
}
func (c Currency) quoRem64(v uint64) (q Currency, r uint64) {
	if c.Hi < v {
		q.Lo, r = bits.Div64(c.Hi, c.Lo, v)
	} else {
		q.Hi, r = bits.Div64(0, c.Hi, v)
		q.Lo, r = bits.Div64(r, c.Lo, v)
	}
	return
}
func (c Currency) ExactString() string {
	if c.IsZero() {
		return "0"
	}
	buf := []byte("0000000000000000000000000000000000000000")  
	for i := len(buf); ; i -= 19 {
		q, r := c.quoRem64(1e19)  
		var n int
		for ; r != 0; r /= 10 {
			n++
			buf[i-n] += byte(r % 10)
		}
		if q.IsZero() {
			return string(buf[i-n:])
		}
		c = q
	}
}
func (c Currency) String() string {
	fs := new(big.Rat).SetFrac(c.Big(), BaseUnitsPerCoin.Big()).FloatString(3)
	return strings.TrimSuffix(strings.TrimRight(fs, "0"), ".")
}
func (c Currency) MarshalJSON() ([]byte, error) {
	return []byte(`"` + c.ExactString() + `"`), nil
}
func (c *Currency) UnmarshalJSON(b []byte) (err error) {
	*c, err = ParseCurrency(strings.Trim(string(b), `"`))
	return
}
func (c Currency) Big() *big.Int {
	b := make([]byte, 16)
	binary.BigEndian.PutUint64(b[:8], c.Hi)
	binary.BigEndian.PutUint64(b[8:], c.Lo)
	return new(big.Int).SetBytes(b)
}
func NewCurrency(lo, hi uint64) Currency {
	return Currency{lo, hi}
}
func NewCurrency64(c uint64) Currency {
	return Currency{c, 0}
}