lbcutil/amount.go
2014-04-11 22:43:47 -05:00

95 lines
2.9 KiB
Go

// Copyright (c) 2013, 2014 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil
import (
"errors"
"math"
"strconv"
)
// AmountUnit describes a method of converting an Amount to something
// other than the base unit of a bitcoin. The value of the AmountUnit
// is the exponent component of the decadic multiple to convert from
// an amount in bitcoin to an amount counted in units.
type AmountUnit int
// These constants define the various standard units used when describing
// a bitcoin monetary amount.
const (
AmountMegaBitcoin AmountUnit = 6
AmountKiloBitcoin AmountUnit = 3
AmountBitcoin AmountUnit = 0
AmountMilliBitcoin AmountUnit = -3
AmountMicroBitcoin AmountUnit = -6
AmountBaseBitcoin AmountUnit = -8
)
// String returns the unit as a string. For recognized units, the SI
// prefix is used, or "Satoshi" for the base unit. For all unrecognized
// units, "1eN BTC" is returned, where N is the AmountUnit.
func (u AmountUnit) String() string {
switch u {
case AmountMegaBitcoin:
return "MBTC"
case AmountKiloBitcoin:
return "kBTC"
case AmountBitcoin:
return "BTC"
case AmountMilliBitcoin:
return "mBTC"
case AmountMicroBitcoin:
return "μBTC"
case AmountBaseBitcoin:
return "Satoshi"
default:
return "1e" + strconv.FormatInt(int64(u), 10) + " BTC"
}
}
// Amount represents the base bitcoin monetary unit (colloquially referred
// to as a `Satoshi'). A single Amount is equal to 1e-8 of a bitcoin.
type Amount int64
// NewAmount creates an Amount from a floating point value representing
// some value in bitcoin.
func NewAmount(f float64) (Amount, error) {
a := f * float64(SatoshiPerBitcoin)
// The amount is only valid if it does not exceed the total amount
// of bitcoin producable, and is not a floating point number that
// would otherwise fail that check such as NaN or +-Inf.
switch abs := math.Abs(a); {
case abs > float64(MaxSatoshi):
fallthrough
case math.IsNaN(abs) || math.IsInf(abs, 1):
return 0, errors.New("invalid bitcoin amount")
}
// Depending on the sign, add or subtract 0.5 and rely on integer
// truncation to correctly round the value up or down.
if a < 0 {
a = a - 0.5
} else {
a = a + 0.5
}
return Amount(a), nil
}
// ToUnit converts a monetary amount counted in bitcoin base units to a
// floating point value representing an amount of bitcoin.
func (a Amount) ToUnit(u AmountUnit) float64 {
return float64(a) / math.Pow10(int(u+8))
}
// Format formats a monetary amount counted in bitcoin base units as a
// string for a given unit. The conversion will succeed for any unit,
// however, known units will be formated with an appended label describing
// the units with SI notation.
func (a Amount) Format(u AmountUnit) string {
units := " " + u.String()
return strconv.FormatFloat(a.ToUnit(u), 'f', -int(u+8), 64) + units
}