pure TS amount arithmetic

This commit is contained in:
Florian Dold 2016-02-22 20:55:01 +01:00
parent 180e122ee6
commit 81428771b8

View File

@ -126,6 +126,91 @@ export interface Reserve {
reserve_pub: string;
}
export namespace Amounts {
export interface Result {
amount: AmountJson;
// Was there an over-/underflow?
saturated: boolean;
}
function getMaxAmount(currency: string) {
return {
currency,
value: Number.MAX_SAFE_INTEGER,
fraction: 2**32,
}
}
export function add(first: AmountJson, ...rest: AmountJson[]): Result {
let currency = first.currency;
let value = first.value + Math.floor(first.fraction / 1e6);
if (value > Number.MAX_SAFE_INTEGER) {
return {amount: getMaxAmount(currency), saturated: true};
}
let fraction = first.fraction;
for (let x of rest) {
if (x.currency !== currency) {
throw Error(`Mismatched currency: ${x.currency} and ${currency}`);
}
fraction = (fraction + x.fraction) % 1e6;
value = value + x.value + (Math.floor(fraction + x.fraction) / 1e6);
if (value > Number.MAX_SAFE_INTEGER) {
return {amount: getMaxAmount(currency), saturated: true};
}
}
return {amount: {currency, value, fraction}, saturated: false};
}
export function sub(a: AmountJson, b: AmountJson): Result {
if (a.currency !== b.currency) {
throw Error(`Mismatched currency: ${a.currency} and ${b.currency}`);
}
let currency = a.currency;
let value = a.value;
let fraction = a.fraction;
if (fraction < b.fraction) {
if (value < 1) {
return {amount: {currency, value: 0, fraction: 0}, saturated: true};
}
value--;
fraction = +1e6;
}
console.assert(fraction >= b.fraction);
fraction -= b.fraction;
if (value < b.value) {
return {amount: {currency, value: 0, fraction: 0}, saturated: true};
}
value -= b.value;
return {amount: {currency, value, fraction}, saturated: false};
}
export function cmp(a: AmountJson, b: AmountJson): number {
if (a.currency !== b.currency) {
throw Error(`Mismatched currency: ${a.currency} and ${b.currency}`);
}
let av = a.value + Math.floor(a.fraction / 1e6);
let af = a.fraction % 1e6;
let bv = b.value + Math.floor(b.fraction / 1e6);
let bf = b.fraction % 1e6;
switch (true) {
case av < bv:
return -1;
case av > bv:
return 1;
case af < bf:
return -1;
case af > bf:
return 1;
case af == bf:
return 0;
default:
throw Error("assertion failed");
}
}
}
export interface Notifier {
notify();
}