package skywriting.examples.pi; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import uk.co.mrry.mercator.task.Task; public class PiMapper implements Task { /** 2-dimensional Halton sequence {H(i)}, * where H(i) is a 2-dimensional point and i >= 1 is the index. * Halton sequence is used to generate sample points for Pi estimation. */ private static class HaltonSequence { /** Bases */ static final int[] P = {2, 3}; /** Maximum number of digits allowed */ static final int[] K = {63, 40}; private long index; private double[] x; private double[][] q; private int[][] d; /** Initialize to H(startindex), * so the sequence begins with H(startindex+1). */ HaltonSequence(long startindex) { index = startindex; x = new double[K.length]; q = new double[K.length][]; d = new int[K.length][]; for(int i = 0; i < K.length; i++) { q[i] = new double[K[i]]; d[i] = new int[K[i]]; } for(int i = 0; i < K.length; i++) { long k = index; x[i] = 0; for(int j = 0; j < K[i]; j++) { q[i][j] = (j == 0? 1.0: q[i][j-1])/P[i]; d[i][j] = (int)(k % P[i]); k = (k - d[i][j])/P[i]; x[i] += d[i][j] * q[i][j]; } } } /** Compute next point. * Assume the current point is H(index). * Compute H(index+1). * * @return a 2-dimensional point with coordinates in [0,1)^2 */ double[] nextPoint() { index++; for(int i = 0; i < K.length; i++) { for(int j = 0; j < K[i]; j++) { d[i][j]++; x[i] += q[i][j]; if (d[i][j] < P[i]) { break; } d[i][j] = 0; x[i] -= (j == 0? 1.0: q[i][j-1]); } } return x; } } @Override public void invoke(InputStream[] fis, OutputStream[] fos, String[] args) { /** * inputs: none. */ /** * args: (int) number of samples, (int) initial offset. */ long numSamples = Long.parseLong(args[0]); long offset = Long.parseLong(args[1]); final HaltonSequence haltonsequence = new HaltonSequence(offset); long numInside = 0L; long numOutside = 0L; for (long i = 0; i < numSamples; ++i) { //generate points in a unit square final double[] point = haltonsequence.nextPoint(); //count points inside/outside of the inscribed circle of the square final double x = point[0] - 0.5; final double y = point[1] - 0.5; if (x*x + y*y > 0.25) { numOutside++; } else { numInside++; } } /** * output: single file containing (long) numInside, (long) numOutside. */ try { DataOutputStream out = new DataOutputStream(fos[0]); out.writeLong(numInside); out.writeLong(numOutside); out.close(); } catch (IOException ioe) { throw new RuntimeException(ioe); } } public static void main(String[] args) { int numMappers = Integer.parseInt(args[0]); int numSamples = Integer.parseInt(args[1]); ByteArrayOutputStream[] mapOutputs = new ByteArrayOutputStream[numMappers]; InputStream[] reduceInputs = new ByteArrayInputStream[numMappers]; for (int i = 0; i < numMappers; ++i) { mapOutputs[i] = new ByteArrayOutputStream(); new PiMapper().invoke(new InputStream[] {}, new OutputStream[] { mapOutputs[i] }, new String[] { Integer.toString(numSamples), Integer.toString(i * numSamples) }); reduceInputs[i] = new ByteArrayInputStream(mapOutputs[i].toByteArray()); } ByteArrayOutputStream reduceOutput = new ByteArrayOutputStream(); new PiReducer().invoke(reduceInputs, new OutputStream[] { reduceOutput }, new String[] { }); try { System.out.printf("Result is: %f\n", new DataInputStream(new ByteArrayInputStream(reduceOutput.toByteArray())).readDouble()); } catch (IOException ioe) { throw new RuntimeException(ioe); } } }