Browse Source

initial commit

master
mortie 7 years ago
commit
68c7bfaeb5
8 changed files with 392 additions and 0 deletions
  1. 1
    0
      .gitignore
  2. 2
    0
      Makefile
  3. 67
    0
      index.html
  4. 55
    0
      js/cprime.js
  5. 25
    0
      server.js
  6. 104
    0
      src/main.c
  7. 116
    0
      src/sieve.c
  8. 22
    0
      src/sieve.h

+ 1
- 0
.gitignore View File

@@ -0,0 +1 @@
cprime

+ 2
- 0
Makefile View File

@@ -0,0 +1,2 @@
build:
gcc -o cprime $(shell find src -name '*.c') -lm -O3

+ 67
- 0
index.html View File

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

+ 55
- 0
js/cprime.js View File

@@ -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");
}
}

+ 25
- 0
server.js View File

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

+ 104
- 0
src/main.c View File

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

// Print
printfac(num, buf);
}

fflush(stdout);

if (c == EOF)
return 0;
}

sieve_free(&s);

return 0;
}

+ 116
- 0
src/sieve.c View File

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

+ 22
- 0
src/sieve.h View File

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

Loading…
Cancel
Save