Skip to content

Commit e34d1f0

Browse files
authored
Merge pull request #114 from Exabyte-io/feature/SOF-7597
feature/SOF 7597
2 parents dde887c + 2ab6e24 commit e34d1f0

File tree

4 files changed

+115
-1
lines changed

4 files changed

+115
-1
lines changed

dist/js/math.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ export type FormatOptions = mathjs.FormatOptions;
2626
export type Help = mathjs.Help;
2727
export type MathJsChain = mathjs.MathJsChain;
2828
export type MathJsJson = mathjs.MathJsJson;
29+
export declare enum RoundingMethod {
30+
Bankers = "bankers",
31+
HalfAwayFromZero = "halfAwayFromZero"
32+
}
33+
export declare const roundCustom: (value: number, decimals?: number, method?: RoundingMethod) => number;
2934
/**
3035
* @summary Wrapper for native [Number.toPrecision](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Number/toPrecision) method.
3136
* Returns a string representing the Number object to the specified precision.
@@ -58,6 +63,8 @@ export declare const math: {
5863
calculateSegmentsBetweenPoints3D: (point1: (string | number)[], point2: (string | number)[], n: number | string) => number[][];
5964
roundValueToNDecimals: (value: number, decimals?: number) => number;
6065
numberToPrecision: typeof numberToPrecision;
66+
roundCustom: (value: number, decimals?: number, method?: RoundingMethod) => number;
67+
RoundingMethod: typeof RoundingMethod;
6168
e: number;
6269
pi: number;
6370
i: number;

dist/js/math.js

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
33
return (mod && mod.__esModule) ? mod : { "default": mod };
44
};
55
Object.defineProperty(exports, "__esModule", { value: true });
6-
exports.math = void 0;
6+
exports.math = exports.roundCustom = exports.RoundingMethod = void 0;
77
exports.numberToPrecision = numberToPrecision;
88
/* eslint-disable */
99
const mathjs_1 = __importDefault(require("mathjs"));
@@ -170,6 +170,39 @@ const combinationsFromIntervals = (arrA, arrB, arrC) => {
170170
const roundValueToNDecimals = (value, decimals = 3) => {
171171
return parseFloat(value.toFixed(decimals));
172172
};
173+
// See: https://en.wikipedia.org/wiki/Rounding
174+
var RoundingMethod;
175+
(function (RoundingMethod) {
176+
RoundingMethod["Bankers"] = "bankers";
177+
RoundingMethod["HalfAwayFromZero"] = "halfAwayFromZero";
178+
})(RoundingMethod || (exports.RoundingMethod = RoundingMethod = {}));
179+
const roundCustom = (value, decimals = 0, method = RoundingMethod.HalfAwayFromZero) => {
180+
const factor = Math.pow(10, decimals);
181+
const scaledValue = value * factor;
182+
const absValue = Math.abs(scaledValue);
183+
const sign = scaledValue < 0 ? -1 : 1;
184+
let roundedAbs;
185+
switch (method) {
186+
case RoundingMethod.HalfAwayFromZero:
187+
roundedAbs = Math.round(absValue);
188+
break;
189+
case RoundingMethod.Bankers:
190+
const floorValue = Math.floor(absValue);
191+
const fractional = absValue - floorValue;
192+
if (Math.abs(fractional - 0.5) < Number.EPSILON) {
193+
// Round to even
194+
roundedAbs = floorValue % 2 === 0 ? floorValue : floorValue + 1;
195+
}
196+
else {
197+
roundedAbs = Math.round(absValue);
198+
}
199+
break;
200+
default:
201+
throw new Error(`Unsupported rounding method: ${method}`);
202+
}
203+
return (roundedAbs * sign) / factor;
204+
};
205+
exports.roundCustom = roundCustom;
173206
/**
174207
* @summary Returns n splits of the passed segment.
175208
*/
@@ -227,4 +260,6 @@ exports.math = {
227260
calculateSegmentsBetweenPoints3D,
228261
roundValueToNDecimals,
229262
numberToPrecision,
263+
roundCustom: exports.roundCustom,
264+
RoundingMethod,
230265
};

src/js/math.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,46 @@ const roundValueToNDecimals = (value: number, decimals = 3) => {
216216
return parseFloat(value.toFixed(decimals));
217217
};
218218

219+
// See: https://en.wikipedia.org/wiki/Rounding
220+
export enum RoundingMethod {
221+
Bankers = "bankers",
222+
HalfAwayFromZero = "halfAwayFromZero",
223+
}
224+
225+
export const roundCustom = (
226+
value: number,
227+
decimals = 0,
228+
method = RoundingMethod.HalfAwayFromZero,
229+
) => {
230+
const factor = Math.pow(10, decimals);
231+
const scaledValue = value * factor;
232+
const absValue = Math.abs(scaledValue);
233+
const sign = scaledValue < 0 ? -1 : 1;
234+
235+
let roundedAbs: number;
236+
237+
switch (method) {
238+
case RoundingMethod.HalfAwayFromZero:
239+
roundedAbs = Math.round(absValue);
240+
break;
241+
case RoundingMethod.Bankers:
242+
const floorValue = Math.floor(absValue);
243+
const fractional = absValue - floorValue;
244+
245+
if (Math.abs(fractional - 0.5) < Number.EPSILON) {
246+
// Round to even
247+
roundedAbs = floorValue % 2 === 0 ? floorValue : floorValue + 1;
248+
} else {
249+
roundedAbs = Math.round(absValue);
250+
}
251+
break;
252+
default:
253+
throw new Error(`Unsupported rounding method: ${method}`);
254+
}
255+
256+
return (roundedAbs * sign) / factor;
257+
};
258+
219259
/**
220260
* @summary Returns n splits of the passed segment.
221261
*/
@@ -280,4 +320,6 @@ export const math = {
280320
calculateSegmentsBetweenPoints3D,
281321
roundValueToNDecimals,
282322
numberToPrecision,
323+
roundCustom,
324+
RoundingMethod,
283325
};

tests/js/math.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { expect } from "chai";
2+
3+
import { math } from "../../src/js/math";
4+
5+
describe("Math Tests", () => {
6+
it("should round according to specified method", () => {
7+
const [value1, value2, value3, value4] = [0.5, 1.5, -0.5, -1.5];
8+
const [expectedBankers1, expectedBankers2, expectedBankers3, expectedBankers4] = [
9+
0, 2, 0, -2,
10+
];
11+
const [expectedAway1, expectedAway2, expectedAway3, expectedAway4] = [1, 2, -1, -2];
12+
const n = 0;
13+
expect(math.roundCustom(value1, n, math.RoundingMethod.Bankers)).to.equal(expectedBankers1);
14+
expect(math.roundCustom(value2, n, math.RoundingMethod.Bankers)).to.equal(expectedBankers2);
15+
expect(math.roundCustom(value3, n, math.RoundingMethod.Bankers)).to.equal(expectedBankers3);
16+
expect(math.roundCustom(value4, n, math.RoundingMethod.Bankers)).to.equal(expectedBankers4);
17+
expect(math.roundCustom(value1, n, math.RoundingMethod.HalfAwayFromZero)).to.equal(
18+
expectedAway1,
19+
);
20+
expect(math.roundCustom(value2, n, math.RoundingMethod.HalfAwayFromZero)).to.equal(
21+
expectedAway2,
22+
);
23+
expect(math.roundCustom(value3, n, math.RoundingMethod.HalfAwayFromZero)).to.equal(
24+
expectedAway3,
25+
);
26+
expect(math.roundCustom(value4, n, math.RoundingMethod.HalfAwayFromZero)).to.equal(
27+
expectedAway4,
28+
);
29+
});
30+
});

0 commit comments

Comments
 (0)