From 7497a6228c82b5fc5b052b2424c0362793f874c8 Mon Sep 17 00:00:00 2001 From: sarthakgupta1907-cell Date: Mon, 2 Nov 2026 18:40:02 +0530 Subject: [PATCH] feat: add Roman numeral to number conversion --- Conversions/RomanToNumber.js | 37 ++++++++++++++++++++ Conversions/test/RomanToNumber.test.js | 47 ++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 Conversions/RomanToNumber.js create mode 100644 Conversions/test/RomanToNumber.test.js diff --git a/Conversions/RomanToNumber.js b/Conversions/RomanToNumber.js new file mode 100644 index 0000000000..d5aa453e01 --- /dev/null +++ b/Conversions/RomanToNumber.js @@ -0,0 +1,37 @@ +/** + * @function romanToNumber + * @description Converts a Roman numeral string to its decimal number. + * @param {string} roman - A valid Roman numeral string + * @returns {number} - The decimal representation of the Roman numeral + * @see https://en.wikipedia.org/wiki/Roman_numerals + * @example romanToNumber("III") => 3 + * @example romanToNumber("IX") => 9 + * @example romanToNumber("MCMXCIV") => 1994 + */ +const romanToNumber = (roman) => { + if (typeof roman !== 'string' || !/^[IVXLCDM]+$/.test(roman)) { + throw new TypeError('Input must be a valid Roman numeral string') + } + const romanValues = { + I: 1, + V: 5, + X: 10, + L: 50, + C: 100, + D: 500, + M: 1000 + } + let result = 0 + for (let i = 0; i < roman.length; i++) { + const current = romanValues[roman[i]] + const next = romanValues[roman[i + 1]] + if (next && current < next) { + result -= current + } else { + result += current + } + } + return result +} + +export { romanToNumber } diff --git a/Conversions/test/RomanToNumber.test.js b/Conversions/test/RomanToNumber.test.js new file mode 100644 index 0000000000..b18e720082 --- /dev/null +++ b/Conversions/test/RomanToNumber.test.js @@ -0,0 +1,47 @@ +import { romanToNumber } from '../RomanToNumber.js' + +describe('romanToNumber', () => { + test("romanToNumber('I') returns 1", () => { + expect(romanToNumber('I')).toBe(1) + }) + + test("romanToNumber('III') returns 3", () => { + expect(romanToNumber('III')).toBe(3) + }) + + test("romanToNumber('IV') returns 4", () => { + expect(romanToNumber('IV')).toBe(4) + }) + + test("romanToNumber('IX') returns 9", () => { + expect(romanToNumber('IX')).toBe(9) + }) + + test("romanToNumber('LVIII') returns 58", () => { + expect(romanToNumber('LVIII')).toBe(58) + }) + + test("romanToNumber('MCMXCIV') returns 1994", () => { + expect(romanToNumber('MCMXCIV')).toBe(1994) + }) + + test("romanToNumber('MMMCMXCIX') returns 3999", () => { + expect(romanToNumber('MMMCMXCIX')).toBe(3999) + }) + + test("romanToNumber('XL') returns 40", () => { + expect(romanToNumber('XL')).toBe(40) + }) + + test('throws TypeError for empty string', () => { + expect(() => romanToNumber('')).toThrow(TypeError) + }) + + test('throws TypeError for invalid characters', () => { + expect(() => romanToNumber('ABC')).toThrow(TypeError) + }) + + test('throws TypeError for non-string input', () => { + expect(() => romanToNumber(10)).toThrow(TypeError) + }) +})