func (a Amount) IsNegative() bool {
	zero := apd.New(0, 0)
	return a.number.Cmp(zero) == -1
}
IsNegative returns whether a is negative.
package currency
import (
	"bytes"
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"math/big"
	"strings"
	"github.com/cockroachdb/apd/v2"
)
type RoundingMode uint8
const (
	RoundHalfUp RoundingMode = iota
	RoundHalfDown
	RoundUp
	RoundDown
)
type InvalidNumberError struct {
	Number string
}
func (e InvalidNumberError) Error() string {
	return fmt.Sprintf("invalid number %q", e.Number)
}
type InvalidCurrencyCodeError struct {
	CurrencyCode string
}
func (e InvalidCurrencyCodeError) Error() string {
	return fmt.Sprintf("invalid currency code %q", e.CurrencyCode)
}
type MismatchError struct {
	A Amount
	B Amount
}
func (e MismatchError) Error() string {
	return fmt.Sprintf("amounts %q and %q have mismatched currency codes", e.A, e.B)
}
type Amount struct {
	number       *apd.Decimal
	currencyCode string
}
func NewAmount(n, currencyCode string) (Amount, error) {
	number, _, err := apd.NewFromString(n)
	if err != nil {
		return Amount{}, InvalidNumberError{n}
	}
	if currencyCode == "" || !IsValid(currencyCode) {
		return Amount{}, InvalidCurrencyCodeError{currencyCode}
	}
	return Amount{number, currencyCode}, nil
}
func NewAmountFromBigInt(n *big.Int, currencyCode string) (Amount, error) {
	if n == nil {
		return Amount{}, InvalidNumberError{"nil"}
	}
	d, ok := GetDigits(currencyCode)
	if !ok {
		return Amount{}, InvalidCurrencyCodeError{currencyCode}
	}
	number := apd.NewWithBigInt(n, -int32(d))
	return Amount{number, currencyCode}, nil
}
func NewAmountFromInt64(n int64, currencyCode string) (Amount, error) {
	d, ok := GetDigits(currencyCode)
	if !ok {
		return Amount{}, InvalidCurrencyCodeError{currencyCode}
	}
	number := apd.New(n, -int32(d))
	return Amount{number, currencyCode}, nil
}
func (a Amount) Number() string {
	if a.number == nil {
		return "0"
	}
	return a.number.String()
}
func (a Amount) CurrencyCode() string {
	return a.currencyCode
}
func (a Amount) String() string {
	return a.Number() + " " + a.CurrencyCode()
}
func (a Amount) BigInt() *big.Int {
	return &a.Round().number.Coeff
}
func (a Amount) Int64() (int64, error) {
	n := *a.Round().number
	n.Exponent = 0
	return n.Int64()
}
func (a Amount) Convert(currencyCode, rate string) (Amount, error) {
	if currencyCode == "" || !IsValid(currencyCode) {
		return Amount{}, InvalidCurrencyCodeError{currencyCode}
	}
	result, _, err := apd.NewFromString(rate)
	if err != nil {
		return Amount{}, InvalidNumberError{rate}
	}
	ctx := decimalContext(a.number, result)
	ctx.Mul(result, a.number, result)
	return Amount{result, currencyCode}, nil
}
func (a Amount) Add(b Amount) (Amount, error) {
	if a.currencyCode != b.currencyCode {
		return Amount{}, MismatchError{a, b}
	}
	result := apd.New(0, 0)
	ctx := decimalContext(a.number, b.number)
	ctx.Add(result, a.number, b.number)
	return Amount{result, a.currencyCode}, nil
}
func (a Amount) Sub(b Amount) (Amount, error) {
	if a.currencyCode != b.currencyCode {
		return Amount{}, MismatchError{a, b}
	}
	result := apd.New(0, 0)
	ctx := decimalContext(a.number, b.number)
	ctx.Sub(result, a.number, b.number)
	return Amount{result, a.currencyCode}, nil
}
func (a Amount) Mul(n string) (Amount, error) {
	result, _, err := apd.NewFromString(n)
	if err != nil {
		return Amount{}, InvalidNumberError{n}
	}
	ctx := decimalContext(a.number, result)
	ctx.Mul(result, a.number, result)
	return Amount{result, a.currencyCode}, err
}
func (a Amount) Div(n string) (Amount, error) {
	result, _, err := apd.NewFromString(n)
	if err != nil || result.IsZero() {
		return Amount{}, InvalidNumberError{n}
	}
	ctx := decimalContext(a.number, result)
	ctx.Quo(result, a.number, result)
	return Amount{result, a.currencyCode}, err
}
func (a Amount) Round() Amount {
	return a.RoundTo(DefaultDigits, RoundHalfUp)
}
func (a Amount) RoundTo(digits uint8, mode RoundingMode) Amount {
	if digits == DefaultDigits {
		digits, _ = GetDigits(a.currencyCode)
	}
	extModes := map[RoundingMode]string{
		RoundHalfUp:   apd.RoundHalfUp,
		RoundHalfDown: apd.RoundHalfDown,
		RoundUp:       apd.RoundUp,
		RoundDown:     apd.RoundDown,
	}
	result := apd.New(0, 0)
	ctx := decimalContext(a.number)
	ctx.Rounding = extModes[mode]
	ctx.Quantize(result, a.number, -int32(digits))
	return Amount{result, a.currencyCode}
}
func (a Amount) Cmp(b Amount) (int, error) {
	if a.currencyCode != b.currencyCode {
		return -1, MismatchError{a, b}
	}
	return a.number.Cmp(b.number), nil
}
func (a Amount) Equal(b Amount) bool {
	if a.currencyCode != b.currencyCode {
		return false
	}
	return a.number.Cmp(b.number) == 0
}
func (a Amount) IsPositive() bool {
	zero := apd.New(0, 0)
	return a.number.Cmp(zero) == 1
}