Merge pull request #217 from CosmWasm/214-decimal-comparisons
Add comparison methods to Decimal class
This commit is contained in:
commit
bb3cd1352a
@ -54,9 +54,7 @@ export class TokenManager {
|
||||
const thresholdAmount = this.refillThreshold(tickerSymbol);
|
||||
const threshold = Decimal.fromAtomics(thresholdAmount.amount, meta.fractionalDigits);
|
||||
|
||||
// TODO: perform < operation on Decimal type directly
|
||||
// https://github.com/iov-one/iov-core/issues/1375
|
||||
return balance.toFloatApproximation() < threshold.toFloatApproximation();
|
||||
return balance.isLessThan(threshold);
|
||||
}
|
||||
|
||||
private getTokenMeta(tickerSymbol: string): BankTokenMeta {
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
"scripts": {
|
||||
"docs": "shx rm -rf docs && typedoc --options typedoc.js",
|
||||
"lint": "eslint --max-warnings 0 \"**/*.{js,ts}\"",
|
||||
"lint-fix": "eslint --max-warnings 0 \"**/*.{js,ts}\" --fix",
|
||||
"format": "prettier --write --loglevel warn \"./src/**/*.ts\"",
|
||||
"format-text": "prettier --write --prose-wrap always --print-width 80 \"./*.md\"",
|
||||
"test-node": "node jasmine-testrunner.js",
|
||||
|
||||
@ -210,4 +210,214 @@ describe("Decimal", () => {
|
||||
expect(() => zero.plus(Decimal.fromUserInput("1", 7))).toThrowError(/do not match/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("equals", () => {
|
||||
it("returns correct values", () => {
|
||||
const zero = Decimal.fromUserInput("0", 5);
|
||||
expect(zero.equals(Decimal.fromUserInput("0", 5))).toEqual(true);
|
||||
expect(zero.equals(Decimal.fromUserInput("1", 5))).toEqual(false);
|
||||
expect(zero.equals(Decimal.fromUserInput("2", 5))).toEqual(false);
|
||||
expect(zero.equals(Decimal.fromUserInput("2.8", 5))).toEqual(false);
|
||||
expect(zero.equals(Decimal.fromUserInput("0.12345", 5))).toEqual(false);
|
||||
|
||||
const one = Decimal.fromUserInput("1", 5);
|
||||
expect(one.equals(Decimal.fromUserInput("0", 5))).toEqual(false);
|
||||
expect(one.equals(Decimal.fromUserInput("1", 5))).toEqual(true);
|
||||
expect(one.equals(Decimal.fromUserInput("2", 5))).toEqual(false);
|
||||
expect(one.equals(Decimal.fromUserInput("2.8", 5))).toEqual(false);
|
||||
expect(one.equals(Decimal.fromUserInput("0.12345", 5))).toEqual(false);
|
||||
|
||||
const oneDotFive = Decimal.fromUserInput("1.5", 5);
|
||||
expect(oneDotFive.equals(Decimal.fromUserInput("0", 5))).toEqual(false);
|
||||
expect(oneDotFive.equals(Decimal.fromUserInput("1", 5))).toEqual(false);
|
||||
expect(oneDotFive.equals(Decimal.fromUserInput("1.5", 5))).toEqual(true);
|
||||
expect(oneDotFive.equals(Decimal.fromUserInput("2", 5))).toEqual(false);
|
||||
expect(oneDotFive.equals(Decimal.fromUserInput("2.8", 5))).toEqual(false);
|
||||
expect(oneDotFive.equals(Decimal.fromUserInput("0.12345", 5))).toEqual(false);
|
||||
|
||||
// original value remain unchanged
|
||||
expect(zero.toString()).toEqual("0");
|
||||
expect(one.toString()).toEqual("1");
|
||||
expect(oneDotFive.toString()).toEqual("1.5");
|
||||
});
|
||||
|
||||
it("throws for different fractional digits", () => {
|
||||
const zero = Decimal.fromUserInput("0", 5);
|
||||
expect(() => zero.equals(Decimal.fromUserInput("1", 1))).toThrowError(/do not match/i);
|
||||
expect(() => zero.equals(Decimal.fromUserInput("1", 2))).toThrowError(/do not match/i);
|
||||
expect(() => zero.equals(Decimal.fromUserInput("1", 3))).toThrowError(/do not match/i);
|
||||
expect(() => zero.equals(Decimal.fromUserInput("1", 4))).toThrowError(/do not match/i);
|
||||
|
||||
expect(() => zero.equals(Decimal.fromUserInput("1", 6))).toThrowError(/do not match/i);
|
||||
expect(() => zero.equals(Decimal.fromUserInput("1", 7))).toThrowError(/do not match/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isLessThan", () => {
|
||||
it("returns correct values", () => {
|
||||
const zero = Decimal.fromUserInput("0", 5);
|
||||
expect(zero.isLessThan(Decimal.fromUserInput("0", 5))).toEqual(false);
|
||||
expect(zero.isLessThan(Decimal.fromUserInput("1", 5))).toEqual(true);
|
||||
expect(zero.isLessThan(Decimal.fromUserInput("2", 5))).toEqual(true);
|
||||
expect(zero.isLessThan(Decimal.fromUserInput("2.8", 5))).toEqual(true);
|
||||
expect(zero.isLessThan(Decimal.fromUserInput("0.12345", 5))).toEqual(true);
|
||||
|
||||
const one = Decimal.fromUserInput("1", 5);
|
||||
expect(one.isLessThan(Decimal.fromUserInput("0", 5))).toEqual(false);
|
||||
expect(one.isLessThan(Decimal.fromUserInput("1", 5))).toEqual(false);
|
||||
expect(one.isLessThan(Decimal.fromUserInput("2", 5))).toEqual(true);
|
||||
expect(one.isLessThan(Decimal.fromUserInput("2.8", 5))).toEqual(true);
|
||||
expect(one.isLessThan(Decimal.fromUserInput("0.12345", 5))).toEqual(false);
|
||||
|
||||
const oneDotFive = Decimal.fromUserInput("1.5", 5);
|
||||
expect(oneDotFive.isLessThan(Decimal.fromUserInput("0", 5))).toEqual(false);
|
||||
expect(oneDotFive.isLessThan(Decimal.fromUserInput("1", 5))).toEqual(false);
|
||||
expect(oneDotFive.isLessThan(Decimal.fromUserInput("1.5", 5))).toEqual(false);
|
||||
expect(oneDotFive.isLessThan(Decimal.fromUserInput("2", 5))).toEqual(true);
|
||||
expect(oneDotFive.isLessThan(Decimal.fromUserInput("2.8", 5))).toEqual(true);
|
||||
expect(oneDotFive.isLessThan(Decimal.fromUserInput("0.12345", 5))).toEqual(false);
|
||||
|
||||
// original value remain unchanged
|
||||
expect(zero.toString()).toEqual("0");
|
||||
expect(one.toString()).toEqual("1");
|
||||
expect(oneDotFive.toString()).toEqual("1.5");
|
||||
});
|
||||
|
||||
it("throws for different fractional digits", () => {
|
||||
const zero = Decimal.fromUserInput("0", 5);
|
||||
expect(() => zero.isLessThan(Decimal.fromUserInput("1", 1))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isLessThan(Decimal.fromUserInput("1", 2))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isLessThan(Decimal.fromUserInput("1", 3))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isLessThan(Decimal.fromUserInput("1", 4))).toThrowError(/do not match/i);
|
||||
|
||||
expect(() => zero.isLessThan(Decimal.fromUserInput("1", 6))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isLessThan(Decimal.fromUserInput("1", 7))).toThrowError(/do not match/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isLessThanOrEqual", () => {
|
||||
it("returns correct values", () => {
|
||||
const zero = Decimal.fromUserInput("0", 5);
|
||||
expect(zero.isLessThanOrEqual(Decimal.fromUserInput("0", 5))).toEqual(true);
|
||||
expect(zero.isLessThanOrEqual(Decimal.fromUserInput("1", 5))).toEqual(true);
|
||||
expect(zero.isLessThanOrEqual(Decimal.fromUserInput("2", 5))).toEqual(true);
|
||||
expect(zero.isLessThanOrEqual(Decimal.fromUserInput("2.8", 5))).toEqual(true);
|
||||
expect(zero.isLessThanOrEqual(Decimal.fromUserInput("0.12345", 5))).toEqual(true);
|
||||
|
||||
const one = Decimal.fromUserInput("1", 5);
|
||||
expect(one.isLessThanOrEqual(Decimal.fromUserInput("0", 5))).toEqual(false);
|
||||
expect(one.isLessThanOrEqual(Decimal.fromUserInput("1", 5))).toEqual(true);
|
||||
expect(one.isLessThanOrEqual(Decimal.fromUserInput("2", 5))).toEqual(true);
|
||||
expect(one.isLessThanOrEqual(Decimal.fromUserInput("2.8", 5))).toEqual(true);
|
||||
expect(one.isLessThanOrEqual(Decimal.fromUserInput("0.12345", 5))).toEqual(false);
|
||||
|
||||
const oneDotFive = Decimal.fromUserInput("1.5", 5);
|
||||
expect(oneDotFive.isLessThanOrEqual(Decimal.fromUserInput("0", 5))).toEqual(false);
|
||||
expect(oneDotFive.isLessThanOrEqual(Decimal.fromUserInput("1", 5))).toEqual(false);
|
||||
expect(oneDotFive.isLessThanOrEqual(Decimal.fromUserInput("1.5", 5))).toEqual(true);
|
||||
expect(oneDotFive.isLessThanOrEqual(Decimal.fromUserInput("2", 5))).toEqual(true);
|
||||
expect(oneDotFive.isLessThanOrEqual(Decimal.fromUserInput("2.8", 5))).toEqual(true);
|
||||
expect(oneDotFive.isLessThanOrEqual(Decimal.fromUserInput("0.12345", 5))).toEqual(false);
|
||||
|
||||
// original value remain unchanged
|
||||
expect(zero.toString()).toEqual("0");
|
||||
expect(one.toString()).toEqual("1");
|
||||
expect(oneDotFive.toString()).toEqual("1.5");
|
||||
});
|
||||
|
||||
it("throws for different fractional digits", () => {
|
||||
const zero = Decimal.fromUserInput("0", 5);
|
||||
expect(() => zero.isLessThanOrEqual(Decimal.fromUserInput("1", 1))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isLessThanOrEqual(Decimal.fromUserInput("1", 2))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isLessThanOrEqual(Decimal.fromUserInput("1", 3))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isLessThanOrEqual(Decimal.fromUserInput("1", 4))).toThrowError(/do not match/i);
|
||||
|
||||
expect(() => zero.isLessThanOrEqual(Decimal.fromUserInput("1", 6))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isLessThanOrEqual(Decimal.fromUserInput("1", 7))).toThrowError(/do not match/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isGreaterThan", () => {
|
||||
it("returns correct values", () => {
|
||||
const zero = Decimal.fromUserInput("0", 5);
|
||||
expect(zero.isGreaterThan(Decimal.fromUserInput("0", 5))).toEqual(false);
|
||||
expect(zero.isGreaterThan(Decimal.fromUserInput("1", 5))).toEqual(false);
|
||||
expect(zero.isGreaterThan(Decimal.fromUserInput("2", 5))).toEqual(false);
|
||||
expect(zero.isGreaterThan(Decimal.fromUserInput("2.8", 5))).toEqual(false);
|
||||
expect(zero.isGreaterThan(Decimal.fromUserInput("0.12345", 5))).toEqual(false);
|
||||
|
||||
const one = Decimal.fromUserInput("1", 5);
|
||||
expect(one.isGreaterThan(Decimal.fromUserInput("0", 5))).toEqual(true);
|
||||
expect(one.isGreaterThan(Decimal.fromUserInput("1", 5))).toEqual(false);
|
||||
expect(one.isGreaterThan(Decimal.fromUserInput("2", 5))).toEqual(false);
|
||||
expect(one.isGreaterThan(Decimal.fromUserInput("2.8", 5))).toEqual(false);
|
||||
expect(one.isGreaterThan(Decimal.fromUserInput("0.12345", 5))).toEqual(true);
|
||||
|
||||
const oneDotFive = Decimal.fromUserInput("1.5", 5);
|
||||
expect(oneDotFive.isGreaterThan(Decimal.fromUserInput("0", 5))).toEqual(true);
|
||||
expect(oneDotFive.isGreaterThan(Decimal.fromUserInput("1", 5))).toEqual(true);
|
||||
expect(oneDotFive.isGreaterThan(Decimal.fromUserInput("1.5", 5))).toEqual(false);
|
||||
expect(oneDotFive.isGreaterThan(Decimal.fromUserInput("2", 5))).toEqual(false);
|
||||
expect(oneDotFive.isGreaterThan(Decimal.fromUserInput("2.8", 5))).toEqual(false);
|
||||
expect(oneDotFive.isGreaterThan(Decimal.fromUserInput("0.12345", 5))).toEqual(true);
|
||||
|
||||
// original value remain unchanged
|
||||
expect(zero.toString()).toEqual("0");
|
||||
expect(one.toString()).toEqual("1");
|
||||
expect(oneDotFive.toString()).toEqual("1.5");
|
||||
});
|
||||
|
||||
it("throws for different fractional digits", () => {
|
||||
const zero = Decimal.fromUserInput("0", 5);
|
||||
expect(() => zero.isGreaterThan(Decimal.fromUserInput("1", 1))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isGreaterThan(Decimal.fromUserInput("1", 2))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isGreaterThan(Decimal.fromUserInput("1", 3))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isGreaterThan(Decimal.fromUserInput("1", 4))).toThrowError(/do not match/i);
|
||||
|
||||
expect(() => zero.isGreaterThan(Decimal.fromUserInput("1", 6))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isGreaterThan(Decimal.fromUserInput("1", 7))).toThrowError(/do not match/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isGreaterThanOrEqual", () => {
|
||||
it("returns correct values", () => {
|
||||
const zero = Decimal.fromUserInput("0", 5);
|
||||
expect(zero.isGreaterThanOrEqual(Decimal.fromUserInput("0", 5))).toEqual(true);
|
||||
expect(zero.isGreaterThanOrEqual(Decimal.fromUserInput("1", 5))).toEqual(false);
|
||||
expect(zero.isGreaterThanOrEqual(Decimal.fromUserInput("2", 5))).toEqual(false);
|
||||
expect(zero.isGreaterThanOrEqual(Decimal.fromUserInput("2.8", 5))).toEqual(false);
|
||||
expect(zero.isGreaterThanOrEqual(Decimal.fromUserInput("0.12345", 5))).toEqual(false);
|
||||
|
||||
const one = Decimal.fromUserInput("1", 5);
|
||||
expect(one.isGreaterThanOrEqual(Decimal.fromUserInput("0", 5))).toEqual(true);
|
||||
expect(one.isGreaterThanOrEqual(Decimal.fromUserInput("1", 5))).toEqual(true);
|
||||
expect(one.isGreaterThanOrEqual(Decimal.fromUserInput("2", 5))).toEqual(false);
|
||||
expect(one.isGreaterThanOrEqual(Decimal.fromUserInput("2.8", 5))).toEqual(false);
|
||||
expect(one.isGreaterThanOrEqual(Decimal.fromUserInput("0.12345", 5))).toEqual(true);
|
||||
|
||||
const oneDotFive = Decimal.fromUserInput("1.5", 5);
|
||||
expect(oneDotFive.isGreaterThanOrEqual(Decimal.fromUserInput("0", 5))).toEqual(true);
|
||||
expect(oneDotFive.isGreaterThanOrEqual(Decimal.fromUserInput("1", 5))).toEqual(true);
|
||||
expect(oneDotFive.isGreaterThanOrEqual(Decimal.fromUserInput("1.5", 5))).toEqual(true);
|
||||
expect(oneDotFive.isGreaterThanOrEqual(Decimal.fromUserInput("2", 5))).toEqual(false);
|
||||
expect(oneDotFive.isGreaterThanOrEqual(Decimal.fromUserInput("2.8", 5))).toEqual(false);
|
||||
expect(oneDotFive.isGreaterThanOrEqual(Decimal.fromUserInput("0.12345", 5))).toEqual(true);
|
||||
|
||||
// original value remain unchanged
|
||||
expect(zero.toString()).toEqual("0");
|
||||
expect(one.toString()).toEqual("1");
|
||||
expect(oneDotFive.toString()).toEqual("1.5");
|
||||
});
|
||||
|
||||
it("throws for different fractional digits", () => {
|
||||
const zero = Decimal.fromUserInput("0", 5);
|
||||
expect(() => zero.isGreaterThanOrEqual(Decimal.fromUserInput("1", 1))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isGreaterThanOrEqual(Decimal.fromUserInput("1", 2))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isGreaterThanOrEqual(Decimal.fromUserInput("1", 3))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isGreaterThanOrEqual(Decimal.fromUserInput("1", 4))).toThrowError(/do not match/i);
|
||||
|
||||
expect(() => zero.isGreaterThanOrEqual(Decimal.fromUserInput("1", 6))).toThrowError(/do not match/i);
|
||||
expect(() => zero.isGreaterThanOrEqual(Decimal.fromUserInput("1", 7))).toThrowError(/do not match/i);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -64,6 +64,11 @@ export class Decimal {
|
||||
}
|
||||
}
|
||||
|
||||
public static compare(a: Decimal, b: Decimal): number {
|
||||
if (a.fractionalDigits !== b.fractionalDigits) throw new Error("Fractional digits do not match");
|
||||
return a.data.atomics.cmp(new BN(b.atomics));
|
||||
}
|
||||
|
||||
public get atomics(): string {
|
||||
return this.data.atomics.toString();
|
||||
}
|
||||
@ -118,4 +123,24 @@ export class Decimal {
|
||||
const sum = this.data.atomics.add(new BN(b.atomics));
|
||||
return new Decimal(sum.toString(), this.fractionalDigits);
|
||||
}
|
||||
|
||||
public equals(b: Decimal): boolean {
|
||||
return Decimal.compare(this, b) === 0;
|
||||
}
|
||||
|
||||
public isLessThan(b: Decimal): boolean {
|
||||
return Decimal.compare(this, b) < 0;
|
||||
}
|
||||
|
||||
public isLessThanOrEqual(b: Decimal): boolean {
|
||||
return Decimal.compare(this, b) <= 0;
|
||||
}
|
||||
|
||||
public isGreaterThan(b: Decimal): boolean {
|
||||
return Decimal.compare(this, b) > 0;
|
||||
}
|
||||
|
||||
public isGreaterThanOrEqual(b: Decimal): boolean {
|
||||
return Decimal.compare(this, b) >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
6
packages/math/types/decimal.d.ts
vendored
6
packages/math/types/decimal.d.ts
vendored
@ -7,6 +7,7 @@ export declare class Decimal {
|
||||
static fromUserInput(input: string, fractionalDigits: number): Decimal;
|
||||
static fromAtomics(atomics: string, fractionalDigits: number): Decimal;
|
||||
private static verifyFractionalDigits;
|
||||
static compare(a: Decimal, b: Decimal): number;
|
||||
get atomics(): string;
|
||||
get fractionalDigits(): number;
|
||||
private readonly data;
|
||||
@ -23,4 +24,9 @@ export declare class Decimal {
|
||||
* Both values need to have the same fractional digits.
|
||||
*/
|
||||
plus(b: Decimal): Decimal;
|
||||
equals(b: Decimal): boolean;
|
||||
isLessThan(b: Decimal): boolean;
|
||||
isLessThanOrEqual(b: Decimal): boolean;
|
||||
isGreaterThan(b: Decimal): boolean;
|
||||
isGreaterThanOrEqual(b: Decimal): boolean;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user