ready-primes-extended
Version:
Get Primes in milliseconds. Pre-calculated collections of prime numbers, natural numbers with distinguished primes and methods to retrieve them.
156 lines (136 loc) • 5.41 kB
text/typescript
import * as fs from 'fs-extra';
import { JsonHelper } from './helpers/JsonHelper';
import * as _chunk from 'lodash/chunk';
import * as _each from 'lodash/each';
import * as _fill from 'lodash/fill';
import * as _last from 'lodash/last';
export type IntegersCollection = number[];
export type PrimeCollection = number[];
export type Collections = { primes: PrimeCollection, integers: IntegersCollection };
export type ReferenceObj = { first: number, last: number };
export type ReferenceCategory = { [ chunk: number ]: ReferenceObj };
export type ReferenceMetric = { prime: number, integer: number };
export type Reference = {
integers: ReferenceCategory,
primes: ReferenceCategory,
last: ReferenceMetric,
length: ReferenceMetric,
chunkSize: number
};
function sieve( limit: number ): Collections {
const startTimer: number = new Date().getTime();
const limitSqrt: number = Math.sqrt( limit );
let sieve: boolean[] = [];
let n: number;
sieve[ 2 ] = true;
sieve[ 3 ] = true;
for ( let x: number = 1; x <= limitSqrt; x++ ) {
let xx: number = x * x;
for ( let y: number = 1; y <= limitSqrt; y++ ) {
let yy: number = y * y;
if ( xx + yy >= limit ) {
break;
}
// first quadratic using m = 12 and r in R1 = {r : 1, 5}
n = ( 4 * xx ) + ( yy );
if ( n <= limit && ( n % 12 === 1 || n % 12 === 5 ) ) {
sieve[ n ] = !sieve[ n ];
}
// second quadratic using m = 12 and r in R2 = {r : 7}
n = ( 3 * xx ) + ( yy );
if ( n <= limit && ( n % 12 === 7 ) ) {
sieve[ n ] = !sieve[ n ];
}
// third quadratic using m = 12 and r in R3 = {r : 11}
n = ( 3 * xx ) - ( yy );
if ( x > y && n <= limit && ( n % 12 === 11 ) ) {
sieve[ n ] = !sieve[ n ];
}
}
}
let x: number;
let i: number;
// false each prime's multiples
for ( n = 5; n <= limitSqrt; n++ ) {
if ( sieve[ n ] ) {
x = n * n;
for ( i = x; i <= limit; i += x ) {
sieve[ i ] = false;
}
}
}
let integers: number[] = _fill( Array( limit ), 0 );
let primes: number[] = [];
sieve.forEach(( value: boolean, index: number ) => {
if ( value ) {
primes.push( index );
integers[ index ] = 1;
}
});
console.log( 'Run time:', ( ( new Date().getTime() ) - startTimer ) / 1000, 'seconds' );
return { primes: primes, integers: integers };
}
function hasArg( needle: string ): boolean {
return process.argv.indexOf( needle ) > -1;
}
function getArgValue( needle: string ): string {
let result: string = undefined;
_each( process.argv, ( arg: string ) => {
if ( arg.substr( 0, needle.length + 1 ) === needle + '=' ) {
let split: string[] = arg.split( '=' );
result = split[ 1 ];
}
});
return result;
}
let hasRead: boolean = hasArg( '-r' );
let hasWrite: boolean = hasArg( '-w' );
let size: number = Number( getArgValue( '-size' ) ) || 1e6;
let chunkSize: number = Number( getArgValue( '-chunk' ) ) || 1e4;
if ( hasRead && !hasWrite ) {
JsonHelper.readPrimeFile( 10000 ).then(( response ) => {
console.log( '10000th Prime: ', response[ response.length - 1 ] );
});
}
if ( hasWrite && !hasRead ) {
console.log( 'Generating primes. Limited to', size );
console.log( 'Approximate ETA:', Math.floor( Math.floor( 3e5 / 7e7 * size ) / 10 ) / 1000, 'seconds' );
fs.emptyDir( './data', ( err: any ) => {
if ( !err ) {
let all: Collections = sieve( size + 1 );
let referenceData: Reference = {
integers: {},
primes: {},
last: {
prime: all.primes[ all.primes.length - 1 ],
integer: size
},
length: {
prime: all.primes.length,
integer: size
},
chunkSize: chunkSize
};
console.log( 'Primes found:', all.primes.length );
console.log( 'Last prime:', all.primes[ all.primes.length - 1 ] );
_each( _chunk( all.primes, chunkSize ), ( chunk: PrimeCollection, index: number ) => {
const chunkName: number = ( index + 1 ) * chunkSize;
referenceData.primes[ chunkName ] = <ReferenceObj>{ first: chunk[ 0 ], last: _last( chunk ) };
JsonHelper.writePrimeFile( chunkName, chunk );
});
all.integers.shift();
_each( _chunk( all.integers, chunkSize ), ( chunk: IntegersCollection, index: number ) => {
if ( index === 0 ) {
chunk.reverse();
chunk.push( 0 );
chunk.reverse();
}
const chunkName: number = ( index + 1 ) * chunkSize;
let first: number = chunkName - chunkSize;
referenceData.integers[ chunkName ] = <ReferenceObj>{ first: first === 0 ? first : first + 1, last: chunkName };
JsonHelper.writeIntegerFile( chunkName, chunk );
});
JsonHelper.writeReference( referenceData );
}
});
}