| @@ -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 | |||