Skip to content

Commit

Permalink
feat: add rounding mode
Browse files Browse the repository at this point in the history
  • Loading branch information
tal7aouy committed Jan 4, 2025
1 parent 417d0e8 commit 4902b3a
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 8 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ aveta --help
| `space` | `boolean` | `false` | Insert a space between the number and unit abbreviation |
| `units` | `Array<string>` | `['', 'K', 'M', 'B', 'T', 'P', 'E']` | Units to use for thousand, million, billion, etc. |
| `base` | `number` | `1000` | Base to scale numbers (default is 1000 for K, M, etc.) |
| `roundingMode` | `'up' \| 'down' \| 'nearest'` | `'nearest'` | How numbers are rounded: nearest, always up, or always down(coming) |
| `roundingMode` | `'up' \| 'down' \| 'nearest'` | `'nearest'` | How numbers are rounded: nearest, always up, or always down |
| `threshold` | `number` | `0` | Minimum value before unit conversion is applied (coming) |

---
Expand Down
40 changes: 33 additions & 7 deletions src/aveta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,15 @@ function parseValue(value: number): number {
*/
function roundTo(
value: number,
{ precision, digits }: { precision: number; digits: number },
{
precision,
digits,
roundingMode = 'nearest',
}: {
precision: number;
digits: number;
roundingMode: 'up' | 'down' | 'nearest';
},
): number {
if (!Number.isFinite(value)) {
throw new Error('Input value is not an infinite number');
Expand All @@ -58,10 +66,24 @@ function roundTo(
if (Number.isInteger(value)) {
return value;
}
// check if digits is great than 0
return digits > 0
? parseFloat(value.toPrecision(digits))
: parseFloat(value.toFixed(precision));

const result =
digits > 0
? parseFloat(value.toPrecision(digits))
: parseFloat(value.toFixed(precision));

const multiplier = Math.pow(10, precision);
const shifted = result * multiplier;

switch (roundingMode) {
case 'up':
return Math.ceil(shifted) / multiplier;
case 'down':
return Math.floor(shifted) / multiplier;
default:
// 'nearest'
return Math.round(shifted) / multiplier;
}
}

/**
Expand Down Expand Up @@ -100,8 +122,12 @@ function aveta(value: number, options?: Partial<IOptions>): string {
}

// Round decimal up to desired precision.
let rounded = roundTo(val, opts);

const { precision, digits, roundingMode = 'nearest' } = opts;
let rounded = roundTo(val, {
precision,
digits,
roundingMode,
});
// The rounded value needs another iteration in the generator(divider) cycle.
for (const result of generator(rounded)) {
rounded = result;
Expand Down
6 changes: 6 additions & 0 deletions src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ export interface IOptions {
* Number of significant digits.
*/
precision: number;
/**
* How numbers are rounded: nearest, always up, or always down
* @default 'nearest'
*/
roundingMode?: 'up' | 'down' | 'nearest';
/**
* maximum number of significant digits
*/
Expand Down Expand Up @@ -48,6 +53,7 @@ export const Options: IOptions = {
separator: '.',
lowercase: false,
precision: 1,
roundingMode: 'nearest',
digits: 0,
space: false,
base: 1000,
Expand Down
39 changes: 39 additions & 0 deletions test/aveta.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,42 @@ describe('avetaReverse', () => {
expect(avetaReverse('1M', { base: 1024 })).toBe(1048576);
});
});

describe('aveta rounding modes', () => {
it('rounds up when specified', () => {
const map = new Map([
[1234, '1.2K'], // 1234 -> 1.234K -> 1.2K
[1567, '1.6K'], // 1567 -> 1.567K -> 1.6K
[9400, '9.4K'], // 9400 -> 9.4K -> 9.4K
]);
for (const [value, expected] of map) {
expect(aveta(value, { roundingMode: 'up' })).toEqual(expected);
}
});
it('rounds down when specified', () => {
const map = new Map([
[1240, '1.2K'], // 1.240K rounds down to 1.2K
[1340, '1.3K'], // 1.340K rounds down to 1.3K
[1440, '1.4K'], // 1.440K rounds down to 1.4K
[1540, '1.5K'], // 1.540K rounds down to 1.5K
]);

for (const [value, expected] of map) {
const result = aveta(value, {
roundingMode: 'down',
precision: 1,
});
expect(result).toEqual(expected);
}
});

it('respects precision with rounding modes', () => {
expect(aveta(1234, { precision: 2, roundingMode: 'up' })).toEqual('1.23K');
expect(aveta(1234, { precision: 2, roundingMode: 'down' })).toEqual(
'1.23K',
);
expect(aveta(1234, { precision: 2, roundingMode: 'nearest' })).toEqual(
'1.23K',
);
});
});

0 comments on commit 4902b3a

Please sign in to comment.