move shootout-mandelbrot to LinearMap, add depth argument

This commit is contained in:
Ted Horst 2013-02-17 23:48:06 -06:00
parent acc147769e
commit 45f34059af

View File

@ -12,17 +12,20 @@
// http://shootout.alioth.debian.org/
// u64q/program.php?test=mandelbrot&lang=python3&id=2
//
// takes 2 optional args:
// takes 3 optional args:
// square image size, defaults to 80_u
// output path, default is "" (no output), "-" means stdout
// depth (max iterations per pixel), defaults to 50_u
//
// in the shootout, they use 16000 as image size
// in the shootout, they use 16000 as image size, 50 as depth,
// and write to stdout:
//
// ./shootout_mandelbrot 16000 "-" 50 > /tmp/mandel.pbm
//
// writes pbm image to output path
extern mod std;
use io::WriterUtil;
use std::oldmap::HashMap;
use core::hashmap::linear::LinearMap;
struct cmplx {
re: f64,
@ -54,28 +57,26 @@ pure fn cabs(x: cmplx) -> f64
x.re*x.re + x.im*x.im
}
fn mb(x: cmplx) -> bool
fn mb(x: cmplx, depth: uint) -> bool
{
let mut z = cmplx {re: 0f64, im: 0f64};
let mut z = x;
let mut i = 0;
let mut in = true;
while i < 50 {
z = z*z + x;
if cabs(z) >= 4f64 {
in = false;
break;
while i < depth {
if cabs(z) >= 4_f64 {
return false;
}
z = z*z + x;
i += 1;
}
in
true
}
fn fillbyte(x: cmplx, incr: f64) -> u8 {
fn fillbyte(x: cmplx, incr: f64, depth: uint) -> u8 {
let mut rv = 0_u8;
let mut i = 0_u8;
while i < 8_u8 {
let z = cmplx {re: x.re + (i as f64)*incr, im: x.im};
if mb(z) {
if mb(z, depth) {
rv += 1_u8 << (7_u8 - i);
}
i += 1_u8;
@ -83,15 +84,16 @@ fn fillbyte(x: cmplx, incr: f64) -> u8 {
rv
}
fn chanmb(i: uint, size: uint) -> Line
fn chanmb(i: uint, size: uint, depth: uint) -> Line
{
let mut crv = ~[];
let incr = 2f64/(size as f64);
let y = incr*(i as f64) - 1f64;
let xincr = 8f64*incr;
for uint::range(0_u, size/8_u) |j| {
let x = cmplx {re: xincr*(j as f64) - 1.5f64, im: y};
crv.push(fillbyte(x, incr));
let bsize = size/8_u;
let mut crv = vec::with_capacity(bsize);
let incr = 2_f64/(size as f64);
let y = incr*(i as f64) - 1_f64;
let xincr = 8_f64*incr;
for uint::range(0_u, bsize) |j| {
let x = cmplx {re: xincr*(j as f64) - 1.5_f64, im: y};
crv.push(fillbyte(x, incr, depth));
};
Line {i:i, b:crv}
}
@ -121,34 +123,33 @@ fn writer(path: ~str, pport: pipes::Port<Line>, size: uint)
~[io::Create, io::Truncate]))
}
};
cout.write_line(~"P4");
cout.write_line("P4");
cout.write_line(fmt!("%u %u", size, size));
let lines: HashMap<uint, ~[u8]> = HashMap();
let mut lines: LinearMap<uint, Line> = LinearMap::new();
let mut done = 0_u;
let mut i = 0_u;
while i < size {
let aline = pport.recv();
if aline.i == done {
debug!("W %u", aline.i);
debug!("W %u", done);
cout.write(aline.b);
done += 1_u;
let mut prev = done;
while prev <= i {
if lines.contains_key(&prev) {
debug!("WS %u", prev);
cout.write(lines.get(&prev));
done += 1_u;
lines.remove(&prev);
prev += 1_u;
}
else {
break
}
match lines.pop(&prev) {
Some(pl) => {
debug!("WS %u", prev);
cout.write(pl.b);
done += 1_u;
prev += 1_u;
}
None => break
};
};
}
else {
debug!("S %u", aline.i);
lines.insert(aline.i, copy aline.b); // FIXME: bad for perf
lines.insert(aline.i, aline);
};
i += 1_u;
}
@ -157,11 +158,14 @@ fn writer(path: ~str, pport: pipes::Port<Line>, size: uint)
fn main() {
let args = os::args();
let args = if os::getenv(~"RUST_BENCH").is_some() {
~[~"", ~"4000"]
~[~"", ~"4000", ~"50"]
} else {
args
};
let depth = if vec::len(args) < 4_u { 50_u }
else { uint::from_str(args[3]).get() };
let path = if vec::len(args) < 3_u { ~"" }
else { copy args[2] }; // FIXME: bad for perf
@ -172,7 +176,7 @@ fn main() {
let pchan = pipes::SharedChan(pchan);
for uint::range(0_u, size) |j| {
let cchan = pchan.clone();
do task::spawn || { cchan.send(chanmb(j, size)) };
do task::spawn { cchan.send(chanmb(j, size, depth)) };
};
writer(path, pport, size);
}