Skip to content

Commit

Permalink
Implement utilities for obtaining the nth prime or a range of primes
Browse files Browse the repository at this point in the history
ref #32
  • Loading branch information
frostburn committed Apr 29, 2024
1 parent 99eaf2d commit 26db555
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 1 deletion.
64 changes: 63 additions & 1 deletion src/__tests__/primes.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {describe, it, expect} from 'vitest';
import {PRIMES, isPrime, primes} from '../primes';
import {PRIMES, isPrime, nthPrime, primeRange, primes} from '../primes';

describe('Array of prime numbers', () => {
it('has no gaps', () => {
Expand Down Expand Up @@ -84,3 +84,65 @@ describe('Lists of primes', () => {
expect(primes(7920, 8094)).toEqual(LARGER_PRIMES);
});
});

describe('Nth odd prime generator', () => {
it('knowns 3 is the 1st odd prime', () => {
expect(nthPrime(1)).toBe(3);
});

it('knowns 2 is the prime at index 0', () => {
expect(nthPrime(0)).toBe(2);
});

it('returns undefined for a negative index', () => {
expect(nthPrime(-1)).toBe(undefined);
});

it('returns undefined for a fractional index', () => {
expect(nthPrime(0.5)).toBe(undefined);
});

it('knows that 7919 is the 999th odd prime', () => {
expect(nthPrime(999)).toBe(7919);
});

it('knows that 7927 is the 1000th odd prime', () => {
expect(nthPrime(1000)).toBe(7927);
});

it('knows the about larger primes', () => {
for (let i = 0; i < LARGER_PRIMES.length; ++i) {
expect(nthPrime(1000 + i)).toBe(LARGER_PRIMES[i]);
}
});
});

describe('Prime range generator', () => {
it('produces an empty range for start > end', () => {
expect(primeRange(99999, 9999)).toEqual([]);
});

it('produces an empty range for start === end', () => {
expect(primeRange(9999, 9999)).toEqual([]);
});

it('produces the first 4 primes', () => {
expect(primeRange(0, 4)).toEqual([2, 3, 5, 7]);
});

it('produces 5 primes starting from the 999th odd prime', () => {
expect(primeRange(999, 999 + 5)).toEqual([7919, 7927, 7933, 7937, 7949]);
});

it('produces the larger primes', () => {
expect(primeRange(1000, 1000 + LARGER_PRIMES.length)).toEqual(
LARGER_PRIMES
);
});

it('produces the larger primes but one', () => {
expect(primeRange(1001, 1000 + LARGER_PRIMES.length)).toEqual(
LARGER_PRIMES.slice(1)
);
});
});
81 changes: 81 additions & 0 deletions src/primes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,30 @@ export function isPrime(n: number) {
return true;
}

/**
* Obtain the nth odd prime.
* @param n 1-based ordinal of the nth odd prime, or zero to obtain prime two.
* @returns The nth odd prime number or `2` if `n === 0`.
*/
export function nthPrime(n: number) {
if (n < PRIMES.length) {
return PRIMES[n];
}
n -= PRIMES.length;
let prime = 7927;
while (n) {
// Skip over known composites mod 6.
prime += 4;
n -= Number(isPrime(prime));
if (!n) {
return prime;
}
prime += 2;
n -= Number(isPrime(prime));
}
return prime;
}

/**
* Generate an array of prime numbers.
* @param start Smallest prime number to include (or the next smallest prime).
Expand Down Expand Up @@ -180,3 +204,60 @@ export function primes(start: number, end?: number) {
}
return result;
}

/**
* Obtain a range of odd primes starting at ordinal the given ordinal.
* @param start 1-based ordinal of the nth odd prime to start from, or zero to include prime two.
* @param end Range end. `end - start` elements are returned.
* @returns The primes in the range.
*/
export function primeRange(start: number, end: number) {
start = Math.round(Math.max(0, start));
end = Math.round(end);
if (end <= start) {
return [];
}
if (end <= PRIMES.length) {
return PRIMES.slice(start, end);
}
const result = PRIMES.slice(start);
start = Math.max(0, start - PRIMES.length);
end -= PRIMES.length;

// We skip over known composites mod 6.
let prime = 7927;
let delta: number;
let a = 4;
let b = 2;
while (start) {
prime += 4;
delta = Number(isPrime(prime));
start -= delta;
end -= delta;
if (!start) {
a = 2;
b = 4;
break;
}
prime += 2;
delta = Number(isPrime(prime));
start -= delta;
end -= delta;
}
while (end) {
if (isPrime(prime)) {
result.push(prime);
end--;
if (!end) {
return result;
}
}
prime += a;
if (isPrime(prime)) {
result.push(prime);
end--;
}
prime += b;
}
return result;
}

0 comments on commit 26db555

Please sign in to comment.