Skip to content

Commit

Permalink
fix(up, down, halfUp): fix handling of numbers close to 0 and roundin…
Browse files Browse the repository at this point in the history
…g of integer results (#711)

fixes #710
fixes #713
  • Loading branch information
shasderias committed Feb 19, 2023
1 parent 274714b commit 6b30aa0
Show file tree
Hide file tree
Showing 20 changed files with 675 additions and 149 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-promise": "6.1.1",
"eslint-plugin-sonarjs": "0.16.0",
"fast-check": "3.6.3",
"husky": "8.0.1",
"jest": "28.1.3",
"jest-watch-typeahead": "1.1.0",
Expand Down
16 changes: 8 additions & 8 deletions packages/core/etc/core.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export type DineroSnapshot<TAmount> = {
// @public (undocumented)
export type DivideOperation = <TAmount>(amount: TAmount, factor: TAmount, calculator: Calculator<TAmount>) => TAmount;

// @public (undocumented)
// @public
export const down: DivideOperation;

// @public (undocumented)
Expand Down Expand Up @@ -132,22 +132,22 @@ dineroObject: Dinero<TAmount>,
comparator: Dinero<TAmount>
];

// @public (undocumented)
// @public
export const halfAwayFromZero: DivideOperation;

// @public (undocumented)
// @public
export const halfDown: DivideOperation;

// @public (undocumented)
// @public
export const halfEven: DivideOperation;

// @public (undocumented)
// @public
export const halfOdd: DivideOperation;

// @public (undocumented)
// @public
export const halfTowardsZero: DivideOperation;

// @public (undocumented)
// @public
export const halfUp: DivideOperation;

// @public (undocumented)
Expand Down Expand Up @@ -346,7 +346,7 @@ export const UNEQUAL_CURRENCIES_MESSAGE = "Objects must have the same currency."
// @public (undocumented)
export const UNEQUAL_SCALES_MESSAGE = "Objects must have the same scale.";

// @public (undocumented)
// @public
export const up: DivideOperation;

// (No @packageDocumentation comment for this package)
Expand Down
55 changes: 39 additions & 16 deletions packages/core/src/divide/__tests__/down.test.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,69 @@
import { calculator } from '@dinero.js/calculator-number';
import * as fc from 'fast-check';

import { down } from '../down';

describe('down', () => {
describe('decimal factors', () => {
it('rounds down with a positive quotient below half', () => {
expect(down(14, 10, calculator)).toBe(1);
it('does not round with a positive integer quotient', () => {
expect(down(20, 10, calculator)).toBe(2);
});
it('rounds down with a negative quotient below half', () => {
expect(down(-14, 10, calculator)).toBe(-2);
it('does not round with a negative integer quotient', () => {
expect(down(-20, 10, calculator)).toBe(-2);
});
it('does not round with a zero quotient', () => {
expect(down(0, 10, calculator)).toBe(0);
});
it('rounds down with a positive half quotient', () => {
expect(down(15, 10, calculator)).toBe(1);
});
it('rounds down with a negative half quotient', () => {
expect(down(-15, 10, calculator)).toBe(-2);
});
it('rounds down with a positive quotient above half', () => {
expect(down(16, 10, calculator)).toBe(1);
it('rounds down with any positive float quotient', () => {
fc.assert(
fc.property(fc.integer({ min: 1, max: 9 }), (a) => {
expect(down(a, 10, calculator)).toBe(0);
})
);
});
it('rounds down with a negative quotient above half', () => {
expect(down(-16, 10, calculator)).toBe(-2);
it('rounds down with any negative float quotient', () => {
fc.assert(
fc.property(fc.integer({ min: -9, max: -1 }), (a) => {
expect(down(a, 10, calculator)).toBe(-1);
})
);
});
});
describe('non-decimal factors', () => {
it('rounds down with a positive quotient below half', () => {
expect(down(22, 5, calculator)).toBe(4);
it('does not round with a positive integer quotient', () => {
expect(down(20, 5, calculator)).toBe(4);
});
it('does not round with a negative integer quotient', () => {
expect(down(-20, 5, calculator)).toBe(-4);
});
it('rounds down with a negative quotient below half', () => {
expect(down(-22, 5, calculator)).toBe(-5);
it('does not round with a zero quotient', () => {
expect(down(0, 5, calculator)).toBe(0);
});
it('rounds down with a positive half quotient', () => {
expect(down(3, 2, calculator)).toBe(1);
});
it('rounds down with a negative half quotient', () => {
expect(down(-3, 2, calculator)).toBe(-2);
});
it('rounds down with a positive quotient above half', () => {
expect(down(24, 5, calculator)).toBe(4);
it('rounds down with any positive float', () => {
fc.assert(
fc.property(fc.integer({ min: 1, max: 4 }), (a) => {
expect(down(a, 5, calculator)).toBe(0);
})
);
});
it('rounds down with a negative quotient above half', () => {
expect(down(-24, 5, calculator)).toBe(-5);
it('rounds down with any negative float', () => {
fc.assert(
fc.property(fc.integer({ min: -4, max: -1 }), (a) => {
expect(down(a, 5, calculator)).toBe(-1);
})
);
});
});
});
83 changes: 67 additions & 16 deletions packages/core/src/divide/__tests__/halfAwayFromZero.test.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,97 @@
import { calculator } from '@dinero.js/calculator-number';
import * as fc from 'fast-check';

import { halfAwayFromZero } from '../halfAwayFromZero';

describe('halfAwayFromZero', () => {
describe('decimal factors', () => {
it('rounds down with a positive quotient below half', () => {
expect(halfAwayFromZero(14, 10, calculator)).toBe(1);
it('does not round with a positive integer quotient', () => {
expect(halfAwayFromZero(20, 10, calculator)).toBe(2);
});
it('rounds up with a negative quotient below half', () => {
expect(halfAwayFromZero(-14, 10, calculator)).toBe(-1);
it('does not round with a negative integer quotient', () => {
expect(halfAwayFromZero(-20, 10, calculator)).toBe(-2);
});
it('does not round with a zero quotient', () => {
expect(halfAwayFromZero(0, 10, calculator)).toBe(0);
});
it('rounds to the nearest integer away from zero with a positive half quotient', () => {
expect(halfAwayFromZero(15, 10, calculator)).toBe(2);
});
it('rounds to the nearest integer away from zero with a negative half quotient', () => {
expect(halfAwayFromZero(-25, 10, calculator)).toBe(-3);
});
it('rounds up with a positive quotient above half', () => {
expect(halfAwayFromZero(16, 10, calculator)).toBe(2);
it('rounds up with any positive float quotient above half', () => {
fc.assert(
fc.property(fc.integer({ min: 6, max: 9 }), (a) => {
expect(halfAwayFromZero(a, 10, calculator)).toBe(1);
})
);
});
it('rounds down with any negative quotient above half', () => {
fc.assert(
fc.property(fc.integer({ min: -9, max: -6 }), (a) => {
expect(halfAwayFromZero(a, 10, calculator)).toBe(-1);
})
);
});
it('rounds down with any positive float quotient below half', () => {
fc.assert(
fc.property(fc.integer({ min: 1, max: 4 }), (a) => {
expect(halfAwayFromZero(a, 10, calculator)).toBe(0);
})
);
});
it('rounds down with a negative quotient above half', () => {
expect(halfAwayFromZero(-16, 10, calculator)).toBe(-2);
it('rounds up with any negative quotient below half', () => {
fc.assert(
fc.property(fc.integer({ min: -4, max: -1 }), (a) => {
expect(halfAwayFromZero(a, 10, calculator)).toBe(-0);
})
);
});
});
describe('non-decimal factors', () => {
it('rounds down with a positive quotient below half', () => {
expect(halfAwayFromZero(22, 5, calculator)).toBe(4);
it('does not round with a positive integer quotient', () => {
expect(halfAwayFromZero(20, 5, calculator)).toBe(4);
});
it('rounds up with a negative quotient below half', () => {
expect(halfAwayFromZero(-22, 5, calculator)).toBe(-4);
it('does not round with a negative integer quotient', () => {
expect(halfAwayFromZero(-20, 5, calculator)).toBe(-4);
});
it('does not round with a zero quotient', () => {
expect(halfAwayFromZero(0, 5, calculator)).toBe(0);
});
it('rounds to the nearest integer away from zero with a positive half quotient', () => {
expect(halfAwayFromZero(3, 2, calculator)).toBe(2);
});
it('rounds to the nearest integer away from zero with a negative half quotient', () => {
expect(halfAwayFromZero(-5, 2, calculator)).toBe(-3);
});
it('rounds up with a positive quotient above half', () => {
expect(halfAwayFromZero(24, 5, calculator)).toBe(5);
it('rounds up with any positive float quotient above half', () => {
fc.assert(
fc.property(fc.integer({ min: 3, max: 4 }), (a) => {
expect(halfAwayFromZero(a, 5, calculator)).toBe(1);
})
);
});
it('rounds down with any negative quotient above half', () => {
fc.assert(
fc.property(fc.integer({ min: -4, max: -3 }), (a) => {
expect(halfAwayFromZero(a, 5, calculator)).toBe(-1);
})
);
});
it('rounds down with any positive float quotient below half', () => {
fc.assert(
fc.property(fc.integer({ min: 1, max: 2 }), (a) => {
expect(halfAwayFromZero(a, 5, calculator)).toBe(0);
})
);
});
it('rounds down with a negative quotient above half', () => {
expect(halfAwayFromZero(-24, 5, calculator)).toBe(-5);
it('rounds up with any negative quotient below half', () => {
fc.assert(
fc.property(fc.integer({ min: -2, max: -1 }), (a) => {
expect(halfAwayFromZero(a, 5, calculator)).toBe(-0);
})
);
});
});
});
79 changes: 71 additions & 8 deletions packages/core/src/divide/__tests__/halfDown.test.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,64 @@
import { calculator } from '@dinero.js/calculator-number';
import * as fc from 'fast-check';

import { halfDown } from '../halfDown';

describe('halfDown', () => {
describe('decimal factors', () => {
it('rounds down with a positive quotient below half', () => {
expect(halfDown(14, 10, calculator)).toBe(1);
it('does not round with a positive integer quotient', () => {
expect(halfDown(20, 10, calculator)).toBe(2);
});
it('rounds up with a negative quotient below half', () => {
expect(halfDown(-14, 10, calculator)).toBe(-1);
it('does not round with a negative integer quotient', () => {
expect(halfDown(-20, 10, calculator)).toBe(-2);
});
it('does not round with a zero quotient', () => {
expect(halfDown(0, 10, calculator)).toBe(0);
});
it('rounds down with a positive half quotient', () => {
expect(halfDown(15, 10, calculator)).toBe(1);
});
it('rounds down with a negative half quotient', () => {
expect(halfDown(-15, 10, calculator)).toBe(-2);
});
it('rounds up with a positive quotient above half', () => {
expect(halfDown(16, 10, calculator)).toBe(2);
it('rounds up with any positive float quotient above half', () => {
fc.assert(
fc.property(fc.integer({ min: 6, max: 9 }), (a) => {
expect(halfDown(a, 10, calculator)).toBe(1);
})
);
});
it('rounds down with a negative quotient above half', () => {
expect(halfDown(-16, 10, calculator)).toBe(-2);
it('rounds down with any negative quotient above half', () => {
fc.assert(
fc.property(fc.integer({ min: -9, max: -6 }), (a) => {
expect(halfDown(a, 10, calculator)).toBe(-1);
})
);
});
it('rounds down with any positive float quotient below half', () => {
fc.assert(
fc.property(fc.integer({ min: 1, max: 4 }), (a) => {
expect(halfDown(a, 10, calculator)).toBe(0);
})
);
});
it('rounds up with any negative quotient below half', () => {
fc.assert(
fc.property(fc.integer({ min: -4, max: -1 }), (a) => {
expect(halfDown(a, 10, calculator)).toBe(-0);
})
);
});
});
describe('non-decimal factors', () => {
it('does not round with a positive integer quotient', () => {
expect(halfDown(20, 5, calculator)).toBe(4);
});
it('does not round with a negative integer quotient', () => {
expect(halfDown(-20, 5, calculator)).toBe(-4);
});
it('does not round with a zero quotient', () => {
expect(halfDown(0, 5, calculator)).toBe(0);
});
it('rounds down with a positive quotient below half', () => {
expect(halfDown(22, 5, calculator)).toBe(4);
});
Expand All @@ -42,5 +77,33 @@ describe('halfDown', () => {
it('rounds down with a negative quotient above half', () => {
expect(halfDown(-24, 5, calculator)).toBe(-5);
});
it('rounds up with any positive float quotient above half', () => {
fc.assert(
fc.property(fc.integer({ min: 3, max: 4 }), (a) => {
expect(halfDown(a, 5, calculator)).toBe(1);
})
);
});
it('rounds down with any negative quotient above half', () => {
fc.assert(
fc.property(fc.integer({ min: -4, max: -3 }), (a) => {
expect(halfDown(a, 5, calculator)).toBe(-1);
})
);
});
it('rounds down with any positive float quotient below half', () => {
fc.assert(
fc.property(fc.integer({ min: 1, max: 2 }), (a) => {
expect(halfDown(a, 5, calculator)).toBe(0);
})
);
});
it('rounds up with any negative quotient below half', () => {
fc.assert(
fc.property(fc.integer({ min: -2, max: -1 }), (a) => {
expect(halfDown(a, 5, calculator)).toBe(-0);
})
);
});
});
});

1 comment on commit 6b30aa0

@vercel
Copy link

@vercel vercel bot commented on 6b30aa0 Feb 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

dinerojs – ./

dinerojs-git-main-dinerojs.vercel.app
v2.dinerojs.com
dinerojs-dinerojs.vercel.app

Please sign in to comment.