Add clamping functions to FixedNumber (#1037).
This commit is contained in:
parent
6e10675adf
commit
042b74e6ee
@ -240,29 +240,56 @@ export class FixedNumber {
|
||||
return FixedNumber.fromValue(a.mul(this.format._multiplier).div(b), this.format.decimals, this.format);
|
||||
}
|
||||
|
||||
floor(): FixedNumber {
|
||||
let comps = this.toString().split(".");
|
||||
|
||||
let result = FixedNumber.from(comps[0], this.format);
|
||||
|
||||
const hasFraction = !comps[1].match(/^(0*)$/);
|
||||
if (this.isNegative() && hasFraction) {
|
||||
result = result.subUnsafe(ONE);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ceiling(): FixedNumber {
|
||||
let comps = this.toString().split(".");
|
||||
|
||||
let result = FixedNumber.from(comps[0], this.format);
|
||||
|
||||
const hasFraction = !comps[1].match(/^(0*)$/);
|
||||
if (!this.isNegative() && hasFraction) {
|
||||
result = result.addUnsafe(ONE);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// @TODO: Support other rounding algorithms
|
||||
round(decimals?: number): FixedNumber {
|
||||
if (decimals == null) { decimals = 0; }
|
||||
|
||||
// If we are already in range, we're done
|
||||
let comps = this.toString().split(".");
|
||||
|
||||
if (decimals < 0 || decimals > 80 || (decimals % 1)) {
|
||||
logger.throwArgumentError("invalid decimal count", "decimals", decimals);
|
||||
}
|
||||
|
||||
// If we are already in range, we're done
|
||||
let comps = this.toString().split(".");
|
||||
if (comps[1].length <= decimals) { return this; }
|
||||
|
||||
// Bump the value up by the 0.00...0005
|
||||
const bump = "0." + zeros.substring(0, decimals) + "5";
|
||||
comps = this.addUnsafe(FixedNumber.fromString(bump, this.format))._value.split(".");
|
||||
|
||||
// Now it is safe to truncate
|
||||
return FixedNumber.fromString(comps[0] + "." + comps[1].substring(0, decimals));
|
||||
const factor = FixedNumber.from("1" + zeros.substring(0, decimals));
|
||||
return this.mulUnsafe(factor).addUnsafe(BUMP).floor().divUnsafe(factor);
|
||||
}
|
||||
|
||||
isZero(): boolean {
|
||||
return (this._value === "0.0");
|
||||
}
|
||||
|
||||
isNegative(): boolean {
|
||||
return (this._value[0] === "-");
|
||||
}
|
||||
|
||||
toString(): string { return this._value; }
|
||||
|
||||
@ -361,3 +388,6 @@ export class FixedNumber {
|
||||
return !!(value && value._isFixedNumber);
|
||||
}
|
||||
}
|
||||
|
||||
const ONE = FixedNumber.from(1);
|
||||
const BUMP = FixedNumber.from("0.5");
|
||||
|
@ -623,6 +623,80 @@ describe("BigNumber", function() {
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe("FixedNumber", function() {
|
||||
{
|
||||
const Tests = [
|
||||
{ value: "0.0", expected: "0.0" },
|
||||
{ value: "-0.0", expected: "0.0" },
|
||||
|
||||
{ value: "1.0", expected: "1.0" },
|
||||
{ value: "1.00", expected: "1.0" },
|
||||
{ value: "01.00", expected: "1.0" },
|
||||
{ value: 1, expected: "1.0" },
|
||||
|
||||
{ value: "-1.0", expected: "-1.0" },
|
||||
{ value: "-1.00", expected: "-1.0" },
|
||||
{ value: "-01.00", expected: "-1.0" },
|
||||
{ value: -1, expected: "-1.0" },
|
||||
];
|
||||
|
||||
Tests.forEach((test) => {
|
||||
it (`Create from=${ test.value }`, function() {
|
||||
const value = ethers.FixedNumber.from(test.value);
|
||||
assert.equal(value.toString(), test.expected);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
const Tests = [
|
||||
{ value: "1.0", round: 1, expected: "1.0" },
|
||||
{ value: "1.4", round: 1, expected: "1.4" },
|
||||
{ value: "1.4", round: 2, expected: "1.4" },
|
||||
{ value: "1.4", round: 0, expected: "1.0" },
|
||||
{ value: "1.5", round: 0, expected: "2.0" },
|
||||
{ value: "1.6", round: 0, expected: "2.0" },
|
||||
|
||||
{ value: "-1.0", round: 1, expected: "-1.0" },
|
||||
{ value: "-1.4", round: 1, expected: "-1.4" },
|
||||
{ value: "-1.4", round: 2, expected: "-1.4" },
|
||||
{ value: "-1.4", round: 0, expected: "-1.0" },
|
||||
{ value: "-1.5", round: 0, expected: "-1.0" },
|
||||
{ value: "-1.6", round: 0, expected: "-2.0" },
|
||||
|
||||
{ value: "1.51", round: 1, expected: "1.5" },
|
||||
{ value: "1.55", round: 1, expected: "1.6" },
|
||||
];
|
||||
|
||||
Tests.forEach((test) => {
|
||||
it (`Rounding value=${ test.value }, decimals=${ test.round }`, function() {
|
||||
const value = ethers.FixedNumber.from(test.value).round(test.round);
|
||||
assert.equal(value.toString(), test.expected);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
const Tests = [
|
||||
{ value: "1.0", ceiling: "1.0", floor: "1.0" },
|
||||
{ value: "1.1", ceiling: "2.0", floor: "1.0" },
|
||||
{ value: "1.9", ceiling: "2.0", floor: "1.0" },
|
||||
{ value: "-1.0", ceiling: "-1.0", floor: "-1.0" },
|
||||
{ value: "-1.1", ceiling: "-1.0", floor: "-2.0" },
|
||||
{ value: "-1.9", ceiling: "-1.0", floor: "-2.0" },
|
||||
];
|
||||
|
||||
Tests.forEach((test) => {
|
||||
it (`Clamping value=${ test.value }`, function() {
|
||||
const value = ethers.FixedNumber.from(test.value);
|
||||
assert.equal(value.floor().toString(), test.floor);
|
||||
assert.equal(value.ceiling().toString(), test.ceiling);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("Logger", function() {
|
||||
const logger = new ethers.utils.Logger("testing/0.0");
|
||||
|
||||
@ -658,7 +732,6 @@ describe("Logger", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
describe("Base58 Coder", function() {
|
||||
it("decodes", function() {
|
||||
|
Loading…
Reference in New Issue
Block a user