Skip to content

Commit

Permalink
Merge pull request #98 from skgndi12/feature/issue-88/introduce-utili…
Browse files Browse the repository at this point in the history
…ty-function-for-calculation

[#79] Introduce utility function and a class for calculations
  • Loading branch information
skgndi12 authored Dec 29, 2023
2 parents c3369bb + bea1372 commit e886169
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 0 deletions.
70 changes: 70 additions & 0 deletions api/src/util/calculator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { createHash } from 'crypto';

export function generateMd5Hash(data: string): string {
return createHash('md5').update(data).digest('hex');
}

export class HexaModCalculator {
private static hexadecimalDigits: Map<string, number>;
private static isInitialized = false;

private static initialize = () => {
HexaModCalculator.hexadecimalDigits = new Map();

for (let i = 0; i <= 9; i++) {
HexaModCalculator.hexadecimalDigits.set(
String.fromCharCode(i + '0'.charCodeAt(0)),
i
);
}

HexaModCalculator.hexadecimalDigits.set('a', 10);
HexaModCalculator.hexadecimalDigits.set('b', 11);
HexaModCalculator.hexadecimalDigits.set('c', 12);
HexaModCalculator.hexadecimalDigits.set('d', 13);
HexaModCalculator.hexadecimalDigits.set('e', 14);
HexaModCalculator.hexadecimalDigits.set('f', 15);
};

private static ensureInitialize = () => {
if (!HexaModCalculator.isInitialized) {
HexaModCalculator.initialize();
HexaModCalculator.isInitialized = true;
}
};

// NOTE: This code is adapted from https://www.geeksforgeeks.org/modulus-of-two-hexadecimal-numbers/
public static hexaMod = (hexDividend: string, hexDivisor: string): number => {
HexaModCalculator.ensureInitialize();

const decimalDivisor = parseInt(hexDivisor, 16);
if (decimalDivisor <= 0) {
throw Error('division by zero is not allowed');
}

let decimalBase = 1;
let decimalResult = 0;

for (let i = hexDividend.length - 1; i >= 0; i--) {
const decimalValue = HexaModCalculator.hexadecimalDigits.get(
hexDividend[i]
);
if (decimalValue === undefined) {
throw Error('invalid hexadecimal value');
}

const decimalRemainder = decimalValue % decimalDivisor;
decimalResult =
(decimalResult +
((((decimalBase % decimalDivisor) * decimalRemainder) %
decimalDivisor) %
decimalDivisor)) %
decimalDivisor;
decimalBase =
(((decimalBase % decimalDivisor) * 16) % decimalDivisor) %
decimalDivisor;
}

return decimalResult;
};
}
38 changes: 38 additions & 0 deletions api/test/util/calculator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { HexaModCalculator } from '@src/util/calculator';

describe('Test hexaMod calculator', () => {
it('should return correct result', () => {
const testSet: Array<[number, number]> = [];

for (
let i = Number.MAX_SAFE_INTEGER - 50;
i <= Number.MAX_SAFE_INTEGER;
i++
) {
testSet.push([i, Math.floor(i / 1000)]);
}

for (const [dividend, divisor] of testSet) {
expect(
HexaModCalculator.hexaMod(dividend.toString(16), divisor.toString(16))
).toEqual(dividend % divisor);
}
});

it('should work correctly even if given dividend is very large', () => {
expect(
HexaModCalculator.hexaMod(
'9ff4599228e14263b7076e2fa7a6477c998fabf315129eee77549ff238bfe26aa9b976f0db9e68f5',
'469cbad3'
)
).toEqual(114047340);
});

it('should throw Error when given divisor is zero', () => {
expect(() => HexaModCalculator.hexaMod('111', '0')).toThrow();
});

it('should throw Error when given dividend is not valid hex', () => {
expect(() => HexaModCalculator.hexaMod('xyz', 'ab')).toThrow();
});
});

0 comments on commit e886169

Please sign in to comment.