Add Amount.MulF64.
ok @davecgh, @jcvernaleo
This commit is contained in:
parent
fb4c64910d
commit
2847c14f06
3 changed files with 133 additions and 11 deletions
30
amount.go
30
amount.go
|
@ -53,6 +53,17 @@ func (u AmountUnit) String() string {
|
|||
// to as a `Satoshi'). A single Amount is equal to 1e-8 of a bitcoin.
|
||||
type Amount int64
|
||||
|
||||
// round converts a floating point number, which may or may not be representable
|
||||
// as an integer, to the Amount integer type by rounding to the nearest integer.
|
||||
// This is performed by adding or subtracting 0.5 depending on the sign, and
|
||||
// relying on integer truncation to round the value to the nearest Amount.
|
||||
func round(f float64) Amount {
|
||||
if f < 0 {
|
||||
return Amount(f - 0.5)
|
||||
}
|
||||
return Amount(f + 0.5)
|
||||
}
|
||||
|
||||
// NewAmount creates an Amount from a floating point value representing
|
||||
// some value in bitcoin. NewAmount errors if f is NaN or +-Infinity, but
|
||||
// does not check that the amount is within the total amount of bitcoin
|
||||
|
@ -69,16 +80,7 @@ func NewAmount(f float64) (Amount, error) {
|
|||
return 0, errors.New("invalid bitcoin amount")
|
||||
}
|
||||
|
||||
a := f * float64(SatoshiPerBitcoin)
|
||||
|
||||
// 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
|
||||
return round(f * satoshiPerBitcoin), nil
|
||||
}
|
||||
|
||||
// ToUnit converts a monetary amount counted in bitcoin base units to a
|
||||
|
@ -100,3 +102,11 @@ func (a Amount) Format(u AmountUnit) string {
|
|||
func (a Amount) String() string {
|
||||
return a.Format(AmountBTC)
|
||||
}
|
||||
|
||||
// MulF64 multiplies an Amount by a floating point value. While this is not
|
||||
// an operation that must typically be done by a full node or wallet, it is
|
||||
// useful for services that build on top of bitcoin (for example, calculating
|
||||
// a fee by multiplying by a percentage).
|
||||
func (a Amount) MulF64(f float64) Amount {
|
||||
return round(float64(a) * f)
|
||||
}
|
||||
|
|
107
amount_test.go
107
amount_test.go
|
@ -192,3 +192,110 @@ func TestAmountUnitConversions(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAmountMulF64(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
amt Amount
|
||||
mul float64
|
||||
res Amount
|
||||
}{
|
||||
{
|
||||
name: "Multiply 0.1 BTC by 2",
|
||||
amt: 100e5, // 0.1 BTC
|
||||
mul: 2,
|
||||
res: 200e5, // 0.2 BTC
|
||||
},
|
||||
{
|
||||
name: "Multiply 0.2 BTC by 0.02",
|
||||
amt: 200e5, // 0.2 BTC
|
||||
mul: 1.02,
|
||||
res: 204e5, // 0.204 BTC
|
||||
},
|
||||
{
|
||||
name: "Multiply 0.1 BTC by -2",
|
||||
amt: 100e5, // 0.1 BTC
|
||||
mul: -2,
|
||||
res: -200e5, // -0.2 BTC
|
||||
},
|
||||
{
|
||||
name: "Multiply 0.2 BTC by -0.02",
|
||||
amt: 200e5, // 0.2 BTC
|
||||
mul: -1.02,
|
||||
res: -204e5, // -0.204 BTC
|
||||
},
|
||||
{
|
||||
name: "Multiply -0.1 BTC by 2",
|
||||
amt: -100e5, // -0.1 BTC
|
||||
mul: 2,
|
||||
res: -200e5, // -0.2 BTC
|
||||
},
|
||||
{
|
||||
name: "Multiply -0.2 BTC by 0.02",
|
||||
amt: -200e5, // -0.2 BTC
|
||||
mul: 1.02,
|
||||
res: -204e5, // -0.204 BTC
|
||||
},
|
||||
{
|
||||
name: "Multiply -0.1 BTC by -2",
|
||||
amt: -100e5, // -0.1 BTC
|
||||
mul: -2,
|
||||
res: 200e5, // 0.2 BTC
|
||||
},
|
||||
{
|
||||
name: "Multiply -0.2 BTC by -0.02",
|
||||
amt: -200e5, // -0.2 BTC
|
||||
mul: -1.02,
|
||||
res: 204e5, // 0.204 BTC
|
||||
},
|
||||
{
|
||||
name: "Round down",
|
||||
amt: 49, // 49 Satoshis
|
||||
mul: 0.01,
|
||||
res: 0,
|
||||
},
|
||||
{
|
||||
name: "Round up",
|
||||
amt: 50, // 50 Satoshis
|
||||
mul: 0.01,
|
||||
res: 1, // 1 Satoshi
|
||||
},
|
||||
{
|
||||
name: "Multiply by 0.",
|
||||
amt: 1e8, // 1 BTC
|
||||
mul: 0,
|
||||
res: 0, // 0 BTC
|
||||
},
|
||||
{
|
||||
name: "Multiply 1 by 0.5.",
|
||||
amt: 1, // 1 Satoshi
|
||||
mul: 0.5,
|
||||
res: 1, // 1 Satoshi
|
||||
},
|
||||
{
|
||||
name: "Multiply 100 by 66%.",
|
||||
amt: 100, // 100 Satoshis
|
||||
mul: 0.66,
|
||||
res: 66, // 66 Satoshis
|
||||
},
|
||||
{
|
||||
name: "Multiply 100 by 66.6%.",
|
||||
amt: 100, // 100 Satoshis
|
||||
mul: 0.666,
|
||||
res: 67, // 67 Satoshis
|
||||
},
|
||||
{
|
||||
name: "Multiply 100 by 2/3.",
|
||||
amt: 100, // 100 Satoshis
|
||||
mul: 2.0 / 3,
|
||||
res: 67, // 67 Satoshis
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
a := test.amt.MulF64(test.mul)
|
||||
if a != test.res {
|
||||
t.Errorf("%v: expected %v got %v", test.name, test.res, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
7
const.go
7
const.go
|
@ -5,11 +5,16 @@
|
|||
package btcutil
|
||||
|
||||
const (
|
||||
// satoshiPerBitcoin is the untyped version of SatoshiPerBitcoin.
|
||||
//
|
||||
// TODO(jrick): Switch the exported consts below to be untyped.
|
||||
satoshiPerBitcoin = 1e8
|
||||
|
||||
// SatoshiPerBitcent is the number of satoshi in one bitcoin cent.
|
||||
SatoshiPerBitcent int64 = 1e6
|
||||
|
||||
// SatoshiPerBitcoin is the number of satoshi in one bitcoin (1 BTC).
|
||||
SatoshiPerBitcoin int64 = 1e8
|
||||
SatoshiPerBitcoin int64 = satoshiPerBitcoin
|
||||
|
||||
// MaxSatoshi is the maximum transaction amount allowed in satoshi.
|
||||
MaxSatoshi int64 = 21e6 * SatoshiPerBitcoin
|
||||
|
|
Loading…
Reference in a new issue