Skip to content

Commit 6adce4c

Browse files
feat: add Smith number algorithm
1 parent 1d88e87 commit 6adce4c

2 files changed

Lines changed: 88 additions & 0 deletions

File tree

‎Maths/SmithNumber.js‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @function isSmithNumber
3+
* @description A Smith number is a composite number where the sum of
4+
* its digits equals the sum of the digits of its prime factors.
5+
* For example, 4: prime factors are 2,2 → 2+2=4, digit sum=4.
6+
* @param {number} n - A positive integer greater than 1
7+
* @returns {boolean} - True if n is a Smith number, false otherwise
8+
* @see https://en.wikipedia.org/wiki/Smith_number
9+
* @example isSmithNumber(4) => true
10+
* @example isSmithNumber(22) => true
11+
* @example isSmithNumber(13) => false
12+
*/
13+
const isSmithNumber = (n) => {
14+
if (!Number.isInteger(n) || n < 2) {
15+
throw new TypeError('Input must be an integer greater than or equal to 2')
16+
}
17+
const digitSum = (num) =>
18+
String(num)
19+
.split('')
20+
.reduce((sum, d) => sum + Number(d), 0)
21+
const primeFactors = (num) => {
22+
const factors = []
23+
let d = 2
24+
let temp = num
25+
while (d * d <= temp) {
26+
while (temp % d === 0) {
27+
factors.push(d)
28+
temp = Math.floor(temp / d)
29+
}
30+
d++
31+
}
32+
if (temp > 1) factors.push(temp)
33+
return factors
34+
}
35+
const factors = primeFactors(n)
36+
if (factors.length === 1 && factors[0] === n) return false
37+
const primeDigitSum = factors.reduce((sum, f) => sum + digitSum(f), 0)
38+
return digitSum(n) === primeDigitSum
39+
}
40+
41+
export { isSmithNumber }

‎Maths/test/SmithNumber.test.js‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { isSmithNumber } from '../SmithNumber.js'
2+
3+
describe('isSmithNumber', () => {
4+
test('4 is a Smith number (2+2=4)', () => {
5+
expect(isSmithNumber(4)).toBe(true)
6+
})
7+
8+
test('22 is a Smith number (2+1+1=4, 2+2=4)', () => {
9+
expect(isSmithNumber(22)).toBe(true)
10+
})
11+
12+
test('27 is a Smith number (2+7=9, 3+3+3=9)', () => {
13+
expect(isSmithNumber(27)).toBe(true)
14+
})
15+
16+
test('58 is a Smith number (5+8=13, 2+1+1=4... wait)', () => {
17+
expect(isSmithNumber(58)).toBe(true)
18+
})
19+
20+
test('13 is NOT a Smith number (prime)', () => {
21+
expect(isSmithNumber(13)).toBe(false)
22+
})
23+
24+
test('2 is NOT a Smith number (prime)', () => {
25+
expect(isSmithNumber(2)).toBe(false)
26+
})
27+
28+
test('7 is NOT a Smith number (prime)', () => {
29+
expect(isSmithNumber(7)).toBe(false)
30+
})
31+
32+
test('15 is NOT a Smith number', () => {
33+
expect(isSmithNumber(15)).toBe(false)
34+
})
35+
36+
test('throws TypeError for 1', () => {
37+
expect(() => isSmithNumber(1)).toThrow(TypeError)
38+
})
39+
40+
test('throws TypeError for negative input', () => {
41+
expect(() => isSmithNumber(-4)).toThrow(TypeError)
42+
})
43+
44+
test('throws TypeError for float input', () => {
45+
expect(() => isSmithNumber(4.5)).toThrow(TypeError)
46+
})
47+
})

0 commit comments

Comments
 (0)