cprime |
build: | |||||
gcc -o cprime $(shell find src -name '*.c') -lm -O3 |
<!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> |
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"); | |||||
} | |||||
} |
#!/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); |
#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; | |||||
} |
#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; | |||||
} | |||||
} |
#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 |