From 1fc1ace9ab3edb7df114cc3d697252ea85f07c90 Mon Sep 17 00:00:00 2001 From: sarthakgupta1907-cell Date: Sat, 7 Nov 2026 18:22:46 +0530 Subject: [PATCH] feat: add geometric mean algorithm --- Maths/GeometricMean.js | 24 +++++++++++++++ Maths/test/GeometricMean.test.js | 53 ++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 Maths/GeometricMean.js create mode 100644 Maths/test/GeometricMean.test.js diff --git a/Maths/GeometricMean.js b/Maths/GeometricMean.js new file mode 100644 index 0000000000..42141c4a75 --- /dev/null +++ b/Maths/GeometricMean.js @@ -0,0 +1,24 @@ +/** + * @function geometricMean + * @description Calculates the geometric mean of an array of positive numbers. + * The geometric mean is the nth root of the product of n numbers. + * Formula: (x1 * x2 * ... * xn)^(1/n) + * @param {number[]} arr - An array of positive numbers + * @returns {number} - The geometric mean + * @see https://en.wikipedia.org/wiki/Geometric_mean + * @example geometricMean([1, 2, 3, 4]) => 2.213 + * @example geometricMean([2, 8]) => 4 + * @example geometricMean([4, 4, 4]) => 4 + */ +const geometricMean = (arr) => { + if (!Array.isArray(arr) || arr.length === 0) { + throw new TypeError('Input must be a non-empty array') + } + if (!arr.every((n) => typeof n === 'number' && !isNaN(n) && n > 0)) { + throw new TypeError('All elements must be positive numbers') + } + const product = arr.reduce((acc, n) => acc * n, 1) + return Math.pow(product, 1 / arr.length) +} + +export { geometricMean } diff --git a/Maths/test/GeometricMean.test.js b/Maths/test/GeometricMean.test.js new file mode 100644 index 0000000000..a0f5556ee3 --- /dev/null +++ b/Maths/test/GeometricMean.test.js @@ -0,0 +1,53 @@ +import { geometricMean } from '../GeometricMean.js' + +describe('geometricMean', () => { + test('geometricMean([2, 8]) returns 4', () => { + expect(geometricMean([2, 8])).toBeCloseTo(4) + }) + + test('geometricMean([4, 4, 4]) returns 4', () => { + expect(geometricMean([4, 4, 4])).toBeCloseTo(4) + }) + + test('geometricMean([1, 2, 3, 4]) returns ~2.213', () => { + expect(geometricMean([1, 2, 3, 4])).toBeCloseTo(2.213, 2) + }) + + test('geometricMean single element returns that element', () => { + expect(geometricMean([5])).toBeCloseTo(5) + }) + + test('geometricMean([1, 1, 1]) returns 1', () => { + expect(geometricMean([1, 1, 1])).toBeCloseTo(1) + }) + + test('geometricMean([2, 2]) returns 2', () => { + expect(geometricMean([2, 2])).toBeCloseTo(2) + }) + + test('geometricMean([3, 27]) returns 9', () => { + expect(geometricMean([3, 27])).toBeCloseTo(9) + }) + + test('geometricMean does not mutate original array', () => { + const arr = [1, 2, 3, 4] + geometricMean(arr) + expect(arr).toEqual([1, 2, 3, 4]) + }) + + test('throws TypeError for empty array', () => { + expect(() => geometricMean([])).toThrow(TypeError) + }) + + test('throws TypeError for non-array input', () => { + expect(() => geometricMean('123')).toThrow(TypeError) + }) + + test('throws TypeError for zero values', () => { + expect(() => geometricMean([1, 0, 3])).toThrow(TypeError) + }) + + test('throws TypeError for negative values', () => { + expect(() => geometricMean([1, -2, 3])).toThrow(TypeError) + }) +})