@@ -0,0 +1 @@ | |||
cprime |
@@ -0,0 +1,2 @@ | |||
build: | |||
gcc -o cprime $(shell find src -name '*.c') -lm -O3 |
@@ -0,0 +1,67 @@ | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<meta charset="utf-8"> | |||
<title>Factoring</title> | |||
<style> | |||
body { | |||
height: 100%; | |||
} | |||
* { | |||
box-sizing: border-box; | |||
} | |||
#form { | |||
width: 90%; | |||
max-width: 700px; | |||
margin: auto; | |||
margin-top: 10vh; | |||
} | |||
#num { | |||
width: 80%; | |||
} | |||
#form button { | |||
width: 19%; | |||
float: right; | |||
} | |||
#form * { | |||
height: 32px; | |||
} | |||
#output { | |||
width: 100%; | |||
} | |||
</style> | |||
</head> | |||
<body> | |||
<form id="form"> | |||
<input id="num" type="number" pattern="\d*"> | |||
<button>Factor</button> | |||
<input id="output" readonly> | |||
</form> | |||
<script> | |||
var num = document.getElementById("num"); | |||
var output = document.getElementById("output"); | |||
var form = document.getElementById("form"); | |||
form.addEventListener("submit", function(evt) { | |||
evt.preventDefault(); | |||
var xhr = new XMLHttpRequest(); | |||
xhr.onload = function() { | |||
output.value = xhr.responseText; | |||
} | |||
xhr.open("GET", "/factor/"+num.value); | |||
xhr.send(); | |||
}); | |||
</script> | |||
</body> | |||
</html> |
@@ -0,0 +1,55 @@ | |||
var spawn = require("child_process").spawn; | |||
function lineReader(stream, cb) { | |||
stream.on("data", function ondata(d) { | |||
d.toString().split("\n").forEach(str => { | |||
str = str.trim(); | |||
if (str === "") return; | |||
cb(str); | |||
}); | |||
}); | |||
} | |||
module.exports = class CPrime { | |||
constructor(maxnum) { | |||
this.maxqueue = 30; | |||
this.maxnum = maxnum; | |||
this.queue = []; | |||
this.child = spawn("./cprime", [ maxnum ]); | |||
this.ready = false; | |||
lineReader(this.child.stderr, str => { | |||
console.log("stderr: "+str); | |||
if (str === "done" && !this.ready) { | |||
this.ready = true; | |||
} | |||
}); | |||
lineReader(this.child.stdout, str => { | |||
if (this.queue.length === 0) | |||
return; | |||
var cb = this.queue.shift(); | |||
cb(str); | |||
}); | |||
} | |||
factor(num, cb) { | |||
num = num.replace(/\n/g, ""); | |||
if (num.length > 1000) | |||
return cb("Invalid input."); | |||
if (!this.ready) | |||
return cb("Not ready."); | |||
if (this.queue.length >= this.maxqueue) { | |||
console.log("Warning: over "+this.maxqueue+" concurrent requests"); | |||
return cb("Overloaded."); | |||
} | |||
this.queue.push(cb); | |||
this.child.stdin.write(num+"\n"); | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
#!/usr/bin/env node | |||
var http = require("http"); | |||
var fs = require("fs"); | |||
var CPrime = require("./js/cprime"); | |||
var maxnum = "9223372036854775806"; | |||
var cprime = new CPrime(maxnum); | |||
var port = parseInt(process.argv[2]); | |||
if (isNaN(port)) { | |||
console.log("Usage: "+process.argv[1]+" <port>"); | |||
process.exit(1); | |||
} | |||
var html = fs.readFileSync("index.html"); | |||
http.createServer((req, res) => { | |||
if (req.url.indexOf("/factor/") === 0) { | |||
var num = req.url.substr("/factor/".length); | |||
cprime.factor(num, str => res.end(str)); | |||
} else { | |||
res.end(html); | |||
} | |||
}).listen(port); |
@@ -0,0 +1,104 @@ | |||
#include "sieve.h" | |||
#include <stdio.h> | |||
#include <math.h> | |||
#include <stdlib.h> | |||
#include <signal.h> | |||
#include <unistd.h> | |||
#include <string.h> | |||
static void printfac(int64_t num, int64_t *buf) | |||
{ | |||
int64_t n; | |||
int i = 0; | |||
fprintf(stdout, "%ld = ", num); | |||
while ((n = buf[i++]) != 0) | |||
{ | |||
if (i == 1) | |||
fprintf(stdout, "%ld", n); | |||
else | |||
fprintf(stdout, " * %ld", n); | |||
} | |||
fprintf(stdout, "\n"); | |||
} | |||
static sieve s; | |||
void onTerm(int signal) | |||
{ | |||
sieve_free(&s); | |||
exit(1); | |||
} | |||
int main(int argc, char **argv) | |||
{ | |||
if (argc != 2) | |||
{ | |||
printf("Usage: %s <max-num>\n", argv[0]); | |||
exit(1); | |||
} | |||
int64_t maxnum = atol(argv[1]); | |||
sieve_init(&s, sqrt(maxnum) + 1); | |||
// Attach signal handler | |||
struct sigaction sa; | |||
memset(&sa, 0, sizeof(sa)); | |||
sa.sa_handler = onTerm; | |||
sigaction(SIGTERM, &sa, NULL); | |||
sigaction(SIGINT, &sa, NULL); | |||
// Generate sieve | |||
fprintf(stderr, "Generating sieve...\n"); | |||
sieve_generate(&s); | |||
fprintf(stderr, "done\n"); | |||
fflush(stderr); | |||
int64_t buf[1024]; | |||
// Main loop | |||
char line[1024]; | |||
while (1) | |||
{ | |||
// Read line | |||
int i = 0; | |||
int c; | |||
while ((c = getchar()) != EOF) | |||
{ | |||
if (c == '\n') | |||
break; | |||
if (i < sizeof(buf) - 3) | |||
line[i++] = c; | |||
} | |||
line[i++] = 0; | |||
int64_t num = atol(line); | |||
if (num > maxnum) | |||
{ | |||
printf("Number too big. Max size: %ld.\n", maxnum); | |||
} | |||
else if (num <= 0) | |||
{ | |||
printf("Can only factor numbers >= 0.\n"); | |||
} | |||
else | |||
{ | |||
// Factor | |||
sieve_factor(&s, num, buf); | |||
printfac(num, buf); | |||
} | |||
fflush(stdout); | |||
if (c == EOF) | |||
return 0; | |||
} | |||
sieve_free(&s); | |||
return 0; | |||
} |
@@ -0,0 +1,116 @@ | |||
#include "sieve.h" | |||
#include <stdlib.h> | |||
#include <math.h> | |||
static int isprime(sieve *s, int64_t num); | |||
static void setnotprime(sieve *s, int64_t num); | |||
static void setnotprimes(sieve *s, int64_t min, int64_t max); | |||
void sieve_init(sieve *s, int64_t max) | |||
{ | |||
s->nbytes = (max / 16) + 1; | |||
s->bytes = calloc(s->nbytes, 1); | |||
s->maxNum = max; | |||
s->primes = NULL; | |||
s->nprimes = 0; | |||
} | |||
void sieve_free(sieve *s) | |||
{ | |||
free(s->bytes); | |||
if (s->primes != NULL) | |||
free(s->primes); | |||
} | |||
void sieve_generate(sieve *s) | |||
{ | |||
// Generate primes | |||
int64_t max = s->maxNum; | |||
int64_t sqrtnum = sqrt(max); | |||
for (int64_t i = 3; i <= sqrtnum; i += 2) | |||
{ | |||
if (isprime(s, i)) { | |||
setnotprimes(s, i, max); | |||
} | |||
} | |||
// Generate primes array | |||
s->nprimes = max / ((int)log(max) - 1) + 1; | |||
s->primes = calloc(s->nprimes, sizeof(int64_t)); | |||
int i = 0; | |||
s->primes[i++] = 2; | |||
for (int64_t p = 3; p < max; p += 2) { | |||
if (isprime(s, p)) | |||
s->primes[i++] = p; | |||
} | |||
} | |||
void sieve_factor(sieve *s, int64_t num, int64_t *buf) | |||
{ | |||
int j = 0; | |||
int64_t sqrtnum = sqrt(num); | |||
for (int i = 0; i < s->nprimes; ++i) | |||
{ | |||
int64_t p = s->primes[i]; | |||
if (p == 0) | |||
break; | |||
if (p > sqrtnum) | |||
break; | |||
if (num % p == 0) | |||
{ | |||
do | |||
{ | |||
buf[j++] = p; | |||
num /= p; | |||
} while (num % p == 0); | |||
sqrtnum = sqrt(num); | |||
} | |||
} | |||
if (num != 1 || j == 0) | |||
buf[j++] = num; | |||
buf[j++] = 0; | |||
} | |||
/* | |||
* See whether a number is prime or not | |||
*/ | |||
static int isprime(sieve *s, int64_t num) | |||
{ | |||
if (num == 2) | |||
return 1; | |||
if ((num & 1) == 0) | |||
return 0; | |||
unsigned char c = s->bytes[num >> 4]; | |||
return (c & (1 << ((num % 16) >> 1))) == 0; | |||
} | |||
/* | |||
* Set number to be not prime (aka set its bit to 1) | |||
*/ | |||
static void setnotprime(sieve *s, int64_t num) | |||
{ | |||
if ((num & 1) == 0) | |||
return; | |||
int bi = num >> 4; | |||
s->bytes[bi] = s->bytes[bi] | (1 << ((num % 16) >> 1)); | |||
} | |||
static void setnotprimes(sieve *s, int64_t min, int64_t max) | |||
{ | |||
int64_t j = min; | |||
min *= 2; | |||
int64_t mul = 3; | |||
while (min <= max) { | |||
setnotprime(s, min); | |||
min = j * mul; | |||
mul += 2; | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
#ifndef SIEVE_H | |||
#define SIEVE_H | |||
#include <stdint.h> | |||
typedef struct sieve | |||
{ | |||
unsigned char *bytes; | |||
int nbytes; | |||
int64_t maxNum; | |||
int64_t *primes; | |||
int nprimes; | |||
} sieve; | |||
void sieve_init(sieve *s, int64_t max); | |||
void sieve_free(sieve *s); | |||
void sieve_generate(sieve *s); | |||
void sieve_factor(sieve *s, int64_t num, int64_t *buf); | |||
#endif |