Skip to content

Commit

Permalink
Implement primality check and prime array generation
Browse files Browse the repository at this point in the history
  • Loading branch information
frostburn committed Dec 19, 2023
1 parent 84d68e8 commit de21aa7
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 4 deletions.
66 changes: 62 additions & 4 deletions src/__tests__/primes.spec.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,80 @@
import {describe, it, expect} from 'vitest';
import {PRIMES} from '../primes';
import {PRIMES, isPrime, primes} from '../primes';

describe('Array of prime numbers', () => {
it('has no gaps', () => {
expect(PRIMES[0]).toBe(2);
let index = 1;
for (let n = 3; n <= 7919; n += 2) {
let isPrime = true;
let isPrime_ = true;
for (let i = 3; i * i <= n; ++i) {
if (n % i === 0) {
isPrime = false;
isPrime_ = false;
break;
}
}
if (isPrime) {
if (isPrime_) {
expect(PRIMES[index]).toBe(n);
index++;
}
}
});
});

const LARGER_PRIMES = [
7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059,
8069, 8081, 8087, 8089, 8093,
];

describe('Primeness detector', () => {
it('works for small primes', () => {
for (let n = -1.5; n < 7920.5; n += 0.5) {
if (isPrime(n)) {
expect(PRIMES).includes(n);
} else {
expect(PRIMES).not.includes(n);
}
}
});
it.each(LARGER_PRIMES)('works for %s', (prime: number) => {
expect(isPrime(prime)).toBe(true);
});
it('works for larger composites', () => {
for (let n = 7919.25; n < 8095; n += 0.25) {
if (LARGER_PRIMES.includes(n)) {
continue;
}
expect(isPrime(n)).toBe(false);
}
});
});

describe('Lists of primes', () => {
it('works from implicit 2 to 7', () => {
expect(primes(7)).toEqual([2, 3, 5, 7]);
});

it('works from implicit 2 to below 16', () => {
expect(primes(16)).toEqual([2, 3, 5, 7, 11, 13]);
});

it('produces an empty array with negative bounds', () => {
expect(primes(-100, -50)).toHaveLength(0);
});

it('produces an empty array when end < start', () => {
expect(primes(10, 1)).toHaveLength(0);
});

it('supports start and end parameters', () => {
expect(primes(12, 31)).toEqual([13, 17, 19, 23, 29, 31]);
});

it('works with medium-sized values', () => {
expect(primes(7907, 7933)).toEqual([7907, 7919, 7927, 7933]);
});

it('works with larger values', () => {
expect(primes(7920, 8094)).toEqual(LARGER_PRIMES);
});
});
76 changes: 76 additions & 0 deletions src/primes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,79 @@ PRIME_CENTS[0] = 1200; // Ensure that octaves are exact.
* BigInt representation of the primes.
*/
export const BIG_INT_PRIMES = PRIMES.map(BigInt);

/**
* Check a number for primality.
* @param n Number to check.
* @returns True if the number is prime, false otherwise.
*/
export function isPrime(n: number) {
if (!Number.isInteger(n) || n < 2) {
return false;
}
if (n < 7927) {
return PRIMES.includes(n);
}
if (n > 62837328) {
throw new Error('Prime check only implemented up to 62837328');
}
for (const prime of PRIMES) {
if (n % prime === 0) {
return false;
}
}
return true;
}

/**
* Generate an array of prime numbers.
* @param start Smallest prime number to include (or the next smallest prime).
* @param end Largest prime number to include (or the previous largest prime).
* @returns An array of primes p in ascending order such that start <= p <= end.
*/
export function primes(start: number, end?: number) {
if (end === undefined) {
end = start;
start = 2;
}
if (start > end || end < 2) {
return [];
}
if (start <= 2) {
if (end < 3) {
return [2];
}
start = 2;
} else {
start = Math.ceil((start + 1) * 0.5) * 2 - 1;
while (!isPrime(start)) {
start += 2;
}
}
end = Math.floor((end + 1) * 0.5) * 2 - 1;
while (!isPrime(end)) {
end -= 2;
}

const startIndex = PRIMES.indexOf(start);
const endIndex = PRIMES.indexOf(end);

let result: number[];
if (endIndex < 0) {
if (startIndex >= 0) {
result = PRIMES.slice(startIndex);
start = 7927;
} else {
result = [];
}
} else {
return PRIMES.slice(startIndex, endIndex + 1);
}

for (let n = start; n <= end; n += 2) {
if (isPrime(n)) {
result.push(n);
}
}
return result;
}

0 comments on commit de21aa7

Please sign in to comment.