From fe5019808617292d12328ee656606b92b866c014 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 26 Apr 2022 17:05:27 +0200 Subject: [PATCH] Add Decimal.floor/.ceil --- CHANGELOG.md | 4 ++++ packages/math/src/decimal.spec.ts | 36 +++++++++++++++++++++++++++++++ packages/math/src/decimal.ts | 31 ++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 857340fe8e..9dc2be2b4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to ## [Unreleased] +### Added + +- @cosmjs/math: Add `Decimal.floor` and `Decimal.ceil`. + ## [0.28.4] - 2022-04-15 ### Added diff --git a/packages/math/src/decimal.spec.ts b/packages/math/src/decimal.spec.ts index 1526c9260e..52b876f7d5 100644 --- a/packages/math/src/decimal.spec.ts +++ b/packages/math/src/decimal.spec.ts @@ -177,6 +177,42 @@ describe("Decimal", () => { }); }); + describe("floor", () => { + it("works", () => { + // whole numbers + expect(Decimal.fromUserInput("0", 0).floor().toString()).toEqual("0"); + expect(Decimal.fromUserInput("1", 0).floor().toString()).toEqual("1"); + expect(Decimal.fromUserInput("44", 0).floor().toString()).toEqual("44"); + expect(Decimal.fromUserInput("0", 3).floor().toString()).toEqual("0"); + expect(Decimal.fromUserInput("1", 3).floor().toString()).toEqual("1"); + expect(Decimal.fromUserInput("44", 3).floor().toString()).toEqual("44"); + + // with fractional part + expect(Decimal.fromUserInput("0.001", 3).floor().toString()).toEqual("0"); + expect(Decimal.fromUserInput("1.999", 3).floor().toString()).toEqual("1"); + expect(Decimal.fromUserInput("0.000000000000000001", 18).floor().toString()).toEqual("0"); + expect(Decimal.fromUserInput("1.999999999999999999", 18).floor().toString()).toEqual("1"); + }); + }); + + describe("ceil", () => { + it("works", () => { + // whole numbers + expect(Decimal.fromUserInput("0", 0).ceil().toString()).toEqual("0"); + expect(Decimal.fromUserInput("1", 0).ceil().toString()).toEqual("1"); + expect(Decimal.fromUserInput("44", 0).ceil().toString()).toEqual("44"); + expect(Decimal.fromUserInput("0", 3).ceil().toString()).toEqual("0"); + expect(Decimal.fromUserInput("1", 3).ceil().toString()).toEqual("1"); + expect(Decimal.fromUserInput("44", 3).ceil().toString()).toEqual("44"); + + // with fractional part + expect(Decimal.fromUserInput("0.001", 3).ceil().toString()).toEqual("1"); + expect(Decimal.fromUserInput("1.999", 3).ceil().toString()).toEqual("2"); + expect(Decimal.fromUserInput("0.000000000000000001", 18).ceil().toString()).toEqual("1"); + expect(Decimal.fromUserInput("1.999999999999999999", 18).ceil().toString()).toEqual("2"); + }); + }); + describe("toString", () => { it("displays no decimal point for full numbers", () => { expect(Decimal.fromUserInput("44", 0).toString()).toEqual("44"); diff --git a/packages/math/src/decimal.ts b/packages/math/src/decimal.ts index 6bb8a1f69a..91ec2cc181 100644 --- a/packages/math/src/decimal.ts +++ b/packages/math/src/decimal.ts @@ -113,6 +113,37 @@ export class Decimal { }; } + /** Creates a new instance with the same value */ + private clone(): Decimal { + return new Decimal(this.atomics, this.fractionalDigits); + } + + /** Returns the greatest decimal <= this which has no fractional part (rounding down) */ + public floor(): Decimal { + const factor = new BN(10).pow(new BN(this.data.fractionalDigits)); + const whole = this.data.atomics.div(factor); + const fractional = this.data.atomics.mod(factor); + + if (fractional.isZero()) { + return this.clone(); + } else { + return Decimal.fromAtomics(whole.mul(factor).toString(), this.fractionalDigits); + } + } + + /** Returns the smallest decimal >= this which has no fractional part (rounding up) */ + public ceil(): Decimal { + const factor = new BN(10).pow(new BN(this.data.fractionalDigits)); + const whole = this.data.atomics.div(factor); + const fractional = this.data.atomics.mod(factor); + + if (fractional.isZero()) { + return this.clone(); + } else { + return Decimal.fromAtomics(whole.addn(1).mul(factor).toString(), this.fractionalDigits); + } + } + public toString(): string { const factor = new BN(10).pow(new BN(this.data.fractionalDigits)); const whole = this.data.atomics.div(factor);