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