|
| 1 | +// based on: |
| 2 | +// http://shootout.alioth.debian.org/u64q/program.php?test=mandelbrot&lang=python3&id=2 |
| 3 | +// |
| 4 | +// takes 2 optional numeric args: square image size and yield frequency |
| 5 | +// in the shootout, they use 16000 as image size |
| 6 | +// yield frequency doesn't seem to have much effect |
| 7 | +// |
| 8 | +// writes pbm image to stdout |
| 9 | + |
| 10 | +use std; |
| 11 | +import std::io::writer_util; |
| 12 | + |
| 13 | +type cmplx = {re: f64, im: f64}; |
| 14 | +type line = {i: uint, b: [u8]}; |
| 15 | + |
| 16 | +impl arith for cmplx { |
| 17 | + fn *(x: cmplx) -> cmplx { |
| 18 | + {re: self.re*x.re - self.im*x.im, im: self.re*x.im + self.im*x.re} |
| 19 | + } |
| 20 | + |
| 21 | + fn +(x: cmplx) -> cmplx { |
| 22 | + {re: self.re + x.re, im: self.im + x.im} |
| 23 | + } |
| 24 | +} |
| 25 | + |
| 26 | +pure fn cabs(x: cmplx) -> f64 |
| 27 | +{ |
| 28 | + x.re*x.re + x.im*x.im |
| 29 | +} |
| 30 | + |
| 31 | +fn mb(x: cmplx) -> bool |
| 32 | +{ |
| 33 | + let z = {re: 0., im: 0.}; |
| 34 | + let i = 0; |
| 35 | + let in = true; |
| 36 | + while i < 50 { |
| 37 | + z = z*z + x; |
| 38 | + if cabs(z) >= 4. { |
| 39 | + in = false; |
| 40 | + break; |
| 41 | + } |
| 42 | + i += 1; |
| 43 | + } |
| 44 | + in |
| 45 | +} |
| 46 | + |
| 47 | +fn fillbyte(x: cmplx, incr: f64) -> u8 { |
| 48 | + let rv = 0_u8; |
| 49 | + let i = 0_u8; |
| 50 | + while i < 8_u8 { |
| 51 | + let z = {re: x.re + (i as f64)*incr, im: x.im}; |
| 52 | + if mb(z) { |
| 53 | + rv += 1_u8 << (7_u8 - i); |
| 54 | + } |
| 55 | + i += 1_u8; |
| 56 | + } |
| 57 | + rv |
| 58 | +} |
| 59 | + |
| 60 | +fn chanmb(i: uint, size: uint, ch: comm::chan<line>) -> () |
| 61 | +{ |
| 62 | + let crv = []; |
| 63 | + let incr = 2./(size as f64); |
| 64 | + let y = incr*(i as f64) - 1.; |
| 65 | + let xincr = 8.*incr; |
| 66 | + uint::range(0_u, size/8_u) { |
| 67 | + |j| |
| 68 | + let x = {re: xincr*(j as f64) - 1.5, im: y}; |
| 69 | + crv += [fillbyte(x, incr)]; |
| 70 | + }; |
| 71 | + comm::send(ch, {i:i, b:crv}); |
| 72 | +} |
| 73 | + |
| 74 | +fn writer(writech: comm::chan<comm::chan<line>>, size: uint) |
| 75 | +{ |
| 76 | + let p: comm::port<line> = comm::port(); |
| 77 | + let ch = comm::chan(p); |
| 78 | + comm::send(writech, ch); |
| 79 | + let cout = std::io::stdout(); |
| 80 | + cout.write_line("P4"); |
| 81 | + cout.write_line(#fmt("%u %u", size, size)); |
| 82 | + let lines = std::map::new_uint_hash(); |
| 83 | + let done = 0_u; |
| 84 | + let i = 0_u; |
| 85 | + while i < size { |
| 86 | + let aline = comm::recv(p); |
| 87 | + if aline.i == done { |
| 88 | + #debug("W %u", aline.i); |
| 89 | + cout.write(aline.b); |
| 90 | + done += 1_u; |
| 91 | + let prev = done; |
| 92 | + while prev <= i { |
| 93 | + if lines.contains_key(prev) { |
| 94 | + #debug("WS %u", prev); |
| 95 | + cout.write(lines.get(prev)); |
| 96 | + done += 1_u; |
| 97 | + lines.remove(prev); |
| 98 | + prev += 1_u; |
| 99 | + } |
| 100 | + else { |
| 101 | + break |
| 102 | + } |
| 103 | + }; |
| 104 | + |
| 105 | + } |
| 106 | + else { |
| 107 | + #debug("S %u", aline.i); |
| 108 | + lines.insert(aline.i, aline.b); |
| 109 | + }; |
| 110 | + i += 1_u; |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +fn main(argv: [str]) |
| 115 | +{ |
| 116 | + let size = if vec::len(argv) < 2_u { |
| 117 | + 80u |
| 118 | + } |
| 119 | + else { |
| 120 | + uint::from_str(argv[1]) |
| 121 | + }; |
| 122 | + let yieldevery = if vec::len(argv) < 3_u { |
| 123 | + 10_u |
| 124 | + } |
| 125 | + else { |
| 126 | + uint::from_str(argv[2]) |
| 127 | + }; |
| 128 | + let writep = comm::port(); |
| 129 | + let writech = comm::chan(writep); |
| 130 | + task::spawn { |
| 131 | + || writer(writech, size); |
| 132 | + }; |
| 133 | + let ch = comm::recv(writep); |
| 134 | + uint::range(0_u, size) { |
| 135 | + |j| task::spawn { |
| 136 | + || chanmb(j, size, ch); |
| 137 | + }; |
| 138 | + if j % yieldevery == 0_u { |
| 139 | + #debug("Y %u", j); |
| 140 | + task::yield(); |
| 141 | + }; |
| 142 | + }; |
| 143 | +} |
0 commit comments