2012-02-03 19:46:17 -06:00
|
|
|
// based on:
|
2012-02-03 21:50:32 -06:00
|
|
|
// http://shootout.alioth.debian.org/
|
|
|
|
// u64q/program.php?test=mandelbrot&lang=python3&id=2
|
2012-02-03 19:46:17 -06:00
|
|
|
//
|
2012-02-03 22:43:48 -06:00
|
|
|
// takes 3 optional args:
|
|
|
|
// square image size, defaults to 80_u
|
|
|
|
// yield frequency, defaults to 10_u (yield every 10 spawns)
|
|
|
|
// output path, default is "" (no output), "-" means stdout
|
|
|
|
//
|
2012-02-03 19:46:17 -06:00
|
|
|
// in the shootout, they use 16000 as image size
|
|
|
|
// yield frequency doesn't seem to have much effect
|
|
|
|
//
|
2012-02-03 22:43:48 -06:00
|
|
|
// writes pbm image to output path
|
2012-02-03 19:46:17 -06:00
|
|
|
|
|
|
|
use std;
|
2012-08-14 15:38:35 -05:00
|
|
|
import io::WriterUtil;
|
2012-03-07 18:48:57 -06:00
|
|
|
import std::map::hashmap;
|
2012-02-03 19:46:17 -06:00
|
|
|
|
2012-07-27 21:32:42 -05:00
|
|
|
struct cmplx {
|
|
|
|
re: f64;
|
|
|
|
im: f64;
|
2012-07-11 17:00:40 -05:00
|
|
|
}
|
|
|
|
|
2012-09-02 20:13:48 -05:00
|
|
|
impl cmplx : ops::Mul<cmplx,cmplx> {
|
2012-07-27 21:32:42 -05:00
|
|
|
pure fn mul(x: cmplx) -> cmplx {
|
|
|
|
cmplx {
|
|
|
|
re: self.re*x.re - self.im*x.im,
|
|
|
|
im: self.re*x.im + self.im*x.re
|
|
|
|
}
|
2012-02-03 21:50:32 -06:00
|
|
|
}
|
2012-07-27 21:32:42 -05:00
|
|
|
}
|
2012-02-03 19:46:17 -06:00
|
|
|
|
2012-09-02 20:13:48 -05:00
|
|
|
impl cmplx : ops::Add<cmplx,cmplx> {
|
2012-07-27 21:32:42 -05:00
|
|
|
pure fn add(x: cmplx) -> cmplx {
|
|
|
|
cmplx {
|
|
|
|
re: self.re + x.re,
|
|
|
|
im: self.im + x.im
|
|
|
|
}
|
2012-02-03 21:50:32 -06:00
|
|
|
}
|
2012-02-03 19:46:17 -06:00
|
|
|
}
|
|
|
|
|
2012-07-27 21:32:42 -05:00
|
|
|
type line = {i: uint, b: ~[u8]};
|
|
|
|
|
2012-02-03 19:46:17 -06:00
|
|
|
pure fn cabs(x: cmplx) -> f64
|
|
|
|
{
|
2012-02-03 21:50:32 -06:00
|
|
|
x.re*x.re + x.im*x.im
|
2012-02-03 19:46:17 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn mb(x: cmplx) -> bool
|
|
|
|
{
|
2012-07-27 21:32:42 -05:00
|
|
|
let mut z = cmplx {re: 0f64, im: 0f64};
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut i = 0;
|
|
|
|
let mut in = true;
|
2012-02-03 21:50:32 -06:00
|
|
|
while i < 50 {
|
|
|
|
z = z*z + x;
|
2012-06-04 19:26:17 -05:00
|
|
|
if cabs(z) >= 4f64 {
|
2012-02-03 21:50:32 -06:00
|
|
|
in = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
in
|
2012-02-03 19:46:17 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn fillbyte(x: cmplx, incr: f64) -> u8 {
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut rv = 0_u8;
|
|
|
|
let mut i = 0_u8;
|
2012-02-03 21:50:32 -06:00
|
|
|
while i < 8_u8 {
|
2012-07-27 21:32:42 -05:00
|
|
|
let z = cmplx {re: x.re + (i as f64)*incr, im: x.im};
|
2012-02-03 21:50:32 -06:00
|
|
|
if mb(z) {
|
|
|
|
rv += 1_u8 << (7_u8 - i);
|
|
|
|
}
|
|
|
|
i += 1_u8;
|
|
|
|
}
|
|
|
|
rv
|
2012-02-03 19:46:17 -06:00
|
|
|
}
|
|
|
|
|
2012-08-15 16:10:46 -05:00
|
|
|
fn chanmb(i: uint, size: uint, ch: comm::Chan<line>) -> ()
|
2012-02-03 19:46:17 -06:00
|
|
|
{
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut crv = ~[];
|
2012-06-04 19:26:17 -05:00
|
|
|
let incr = 2f64/(size as f64);
|
|
|
|
let y = incr*(i as f64) - 1f64;
|
|
|
|
let xincr = 8f64*incr;
|
2012-06-30 18:19:07 -05:00
|
|
|
for uint::range(0_u, size/8_u) |j| {
|
2012-07-27 21:32:42 -05:00
|
|
|
let x = cmplx {re: xincr*(j as f64) - 1.5f64, im: y};
|
2012-06-25 18:22:22 -05:00
|
|
|
vec::push(crv, fillbyte(x, incr));
|
2012-02-03 21:50:32 -06:00
|
|
|
};
|
|
|
|
comm::send(ch, {i:i, b:crv});
|
2012-02-03 19:46:17 -06:00
|
|
|
}
|
|
|
|
|
2012-02-03 22:43:48 -06:00
|
|
|
type devnull = {dn: int};
|
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
impl devnull: io::Writer {
|
2012-06-29 18:26:56 -05:00
|
|
|
fn write(_b: &[const u8]) {}
|
2012-08-14 15:38:35 -05:00
|
|
|
fn seek(_i: int, _s: io::SeekStyle) {}
|
2012-02-03 22:43:48 -06:00
|
|
|
fn tell() -> uint {0_u}
|
|
|
|
fn flush() -> int {0}
|
2012-08-14 15:38:35 -05:00
|
|
|
fn get_type() -> io::WriterType { io::File }
|
2012-02-03 22:43:48 -06:00
|
|
|
}
|
|
|
|
|
2012-08-15 16:10:46 -05:00
|
|
|
fn writer(path: ~str, writech: comm::Chan<comm::Chan<line>>, size: uint)
|
2012-02-03 19:46:17 -06:00
|
|
|
{
|
2012-08-27 16:22:25 -05:00
|
|
|
let p: comm::Port<line> = comm::Port();
|
|
|
|
let ch = comm::Chan(p);
|
2012-02-03 21:50:32 -06:00
|
|
|
comm::send(writech, ch);
|
2012-08-14 15:38:35 -05:00
|
|
|
let cout: io::Writer = match path {
|
2012-08-03 21:59:04 -05:00
|
|
|
~"" => {
|
2012-08-14 15:38:35 -05:00
|
|
|
{dn: 0} as io::Writer
|
2012-02-03 22:43:48 -06:00
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
~"-" => {
|
2012-03-12 22:04:27 -05:00
|
|
|
io::stdout()
|
2012-02-03 22:43:48 -06:00
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => {
|
2012-02-03 22:43:48 -06:00
|
|
|
result::get(
|
2012-08-24 17:28:43 -05:00
|
|
|
io::file_writer(&Path(path),
|
2012-08-14 15:38:35 -05:00
|
|
|
~[io::Create, io::Truncate]))
|
2012-02-03 22:43:48 -06:00
|
|
|
}
|
|
|
|
};
|
2012-07-14 00:57:48 -05:00
|
|
|
cout.write_line(~"P4");
|
2012-08-22 19:24:52 -05:00
|
|
|
cout.write_line(fmt!("%u %u", size, size));
|
2012-03-14 14:07:23 -05:00
|
|
|
let lines = std::map::uint_hash();
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut done = 0_u;
|
|
|
|
let mut i = 0_u;
|
2012-02-03 21:50:32 -06:00
|
|
|
while i < size {
|
|
|
|
let aline = comm::recv(p);
|
|
|
|
if aline.i == done {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("W %u", aline.i);
|
2012-02-03 21:50:32 -06:00
|
|
|
cout.write(aline.b);
|
|
|
|
done += 1_u;
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut prev = done;
|
2012-02-03 21:50:32 -06:00
|
|
|
while prev <= i {
|
|
|
|
if lines.contains_key(prev) {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("WS %u", prev);
|
2012-04-24 17:18:24 -05:00
|
|
|
// FIXME (#2280): this temporary shouldn't be
|
|
|
|
// necessary, but seems to be, for borrowing.
|
2012-06-29 18:26:56 -05:00
|
|
|
let v : ~[u8] = lines.get(prev);
|
2012-04-24 17:18:24 -05:00
|
|
|
cout.write(v);
|
2012-02-03 21:50:32 -06:00
|
|
|
done += 1_u;
|
|
|
|
lines.remove(prev);
|
|
|
|
prev += 1_u;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
else {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("S %u", aline.i);
|
2012-02-03 21:50:32 -06:00
|
|
|
lines.insert(aline.i, aline.b);
|
|
|
|
};
|
|
|
|
i += 1_u;
|
|
|
|
}
|
2012-02-03 19:46:17 -06:00
|
|
|
}
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn main(args: ~[~str]) {
|
|
|
|
let args = if os::getenv(~"RUST_BENCH").is_some() {
|
|
|
|
~[~"", ~"4000", ~"10"]
|
2012-05-24 00:53:50 -05:00
|
|
|
} else {
|
|
|
|
args
|
|
|
|
};
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
let path = if vec::len(args) < 4_u { ~"" }
|
2012-06-03 09:45:23 -05:00
|
|
|
else { args[3] };
|
|
|
|
|
|
|
|
let yieldevery = if vec::len(args) < 3_u { 10_u }
|
|
|
|
else { uint::from_str(args[2]).get() };
|
|
|
|
|
|
|
|
let size = if vec::len(args) < 2_u { 80_u }
|
|
|
|
else { uint::from_str(args[1]).get() };
|
2012-05-24 00:53:50 -05:00
|
|
|
|
2012-08-27 16:22:25 -05:00
|
|
|
let writep = comm::Port();
|
|
|
|
let writech = comm::Chan(writep);
|
2012-07-04 14:04:28 -05:00
|
|
|
do task::spawn {
|
2012-02-22 06:18:15 -06:00
|
|
|
writer(path, writech, size);
|
2012-02-03 21:50:32 -06:00
|
|
|
};
|
|
|
|
let ch = comm::recv(writep);
|
2012-06-30 18:19:07 -05:00
|
|
|
for uint::range(0_u, size) |j| {
|
|
|
|
task::spawn(|| chanmb(j, size, ch) );
|
2012-02-03 21:50:32 -06:00
|
|
|
if j % yieldevery == 0_u {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("Y %u", j);
|
2012-02-03 21:50:32 -06:00
|
|
|
task::yield();
|
|
|
|
};
|
|
|
|
};
|
2012-02-03 19:46:17 -06:00
|
|
|
}
|