232 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
		
		
			
		
	
	
			232 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
|  | <!DOCTYPE html> | ||
|  | <!-- vdc.js (C) 2013-present SheetJS http://sheetjs.com --> | ||
|  | <!-- vim: set ts=2: --> | ||
|  | <html> | ||
|  |   <head> | ||
|  |     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||
|  |     <title>VDC Live Demo</title> | ||
|  |   </head> | ||
|  |   <body> | ||
|  |     <b>VDC Live Demo</b><br /> | ||
|  |     <a href="https://github.com/SheetJS/js-vdc">Source Code</a><br /> | ||
|  |     <a href="https://github.com/SheetJS/js-vdc/issues">Issues?  Something look weird?  Click here and report an issue</a><br /> | ||
|  |     <br /> | ||
|  |     <div> | ||
|  | Using the van der Corput sequences for bases 2,3 we can generate a sequence of | ||
|  | quasirandom points in the unit square.  The sequence is said to be | ||
|  | <a href="https://en.wikipedia.org/wiki/Low-discrepancy_sequence">low-discrepancy</a> | ||
|  | (basically the points are somewhat more uniformly spread across the square; you | ||
|  | would expect a truly random sequence of points to have some concentrated lumps | ||
|  | and small areas with no points). | ||
|  | <br /><br /> | ||
|  | quasi-Monte Carlo methods generally have better error properties compared to the | ||
|  | standard random and pseudo-random MC methods.  As a demonstration, we will | ||
|  | estimate π by sampling points in the unit square.  The left side shows the | ||
|  | VDC estimate using bases 2 (x) and 3 (y).  The right side shows the random | ||
|  | estimate by repeatedly calling Math.random. | ||
|  | <br /><br /> | ||
|  | The graphs show the results of sampling many points and estimating PI.  Below | ||
|  | the graphs, the PI value shows the calculated estimate, "err %" shows the | ||
|  | relative error (smaller is better) and "ln err" shows the natural log of the | ||
|  | error (smaller is better). | ||
|  | <br /><br /> | ||
|  | VDC sequences can be "seeded" by setting the starting index for the calculation. | ||
|  | In this demo a random integer is chosen using Math.random. | ||
|  | <br /><br /> | ||
|  | The values and graphs are calculated in your browser window.  If the graphs do | ||
|  | not appear or the values are not calculated, please report the issue! | ||
|  | </div> | ||
|  |     <br /> | ||
|  |     <div width=620> | ||
|  |       <div style="float:left"> | ||
|  |         <b><center id="ltext">VDC (2,3) Sampling </center></b> | ||
|  |         <br /> | ||
|  |         <canvas id="canvas1" width=300 height=300></canvas> | ||
|  |         <br /> | ||
|  |         <b><center id="lout">Estimate of PI: </center></b> | ||
|  |       </div> | ||
|  |       <div style="float:right"> | ||
|  |         <b><center id="rtext">Math.random Sampling </center></b> | ||
|  |         <br /> | ||
|  |         <canvas id="canvas2" width=300 height=300></canvas> | ||
|  |         <br /> | ||
|  |         <b><center id="rout">Estimate of PI: </center></b> | ||
|  |       </div> | ||
|  |     </div> | ||
|  |   </body> | ||
|  |   <script src="http://d3js.org/d3.v2.js"></script> | ||
|  |   <script src="vdc.js"></script> | ||
|  |   <script src="https://cdn.rawgit.com/SheetJS/printj/master/printj.js"></script> | ||
|  |   <script> | ||
|  |     /*jshint browser:true */ | ||
|  | var PTS = 10000; | ||
|  | var seed = (Math.random()*100000)|0; | ||
|  | document.getElementById("ltext").innerHTML += PTS + " points; seed " + seed; | ||
|  | document.getElementById("rtext").innerHTML += PTS + " points"; | ||
|  | var canvas1, canvas2; | ||
|  | 
 | ||
|  | // from http://bl.ocks.org/syntagmatic/3341641 (WTFPL) | ||
|  | var renderQueue = (function(func) { | ||
|  |   var _queue = [],                  // data to be rendered | ||
|  |       _rate = 1000,                 // number of calls per frame | ||
|  |       _invalidate = function() {},  // invalidate last render queue | ||
|  |       _clear = function() {};       // clearing function | ||
|  | 
 | ||
|  |   var rq = function(data) { | ||
|  |     if (data) rq.data(data); | ||
|  |     _invalidate(); | ||
|  |     _clear(); | ||
|  |     rq.render(); | ||
|  |   }; | ||
|  | 
 | ||
|  |   rq.render = function() { | ||
|  |     var valid = true; | ||
|  |     _invalidate = rq.invalidate = function() { | ||
|  |       valid = false; | ||
|  |     }; | ||
|  | 
 | ||
|  |     function doFrame() { | ||
|  |       if (!valid) return true; | ||
|  |       var chunk = _queue.splice(0,_rate); | ||
|  |       chunk.map(func); | ||
|  |       timer_frame(doFrame); | ||
|  |     } | ||
|  | 
 | ||
|  |     doFrame(); | ||
|  |   }; | ||
|  | 
 | ||
|  |   rq.data = function(data) { | ||
|  |     _invalidate(); | ||
|  |     _queue = data.slice(0);   // creates a copy of the data | ||
|  |     return rq; | ||
|  |   }; | ||
|  | 
 | ||
|  |   rq.add = function(data) { | ||
|  |     _queue = _queue.concat(data); | ||
|  |   }; | ||
|  | 
 | ||
|  |   rq.rate = function(value) { | ||
|  |     if (!arguments.length) return _rate; | ||
|  |     _rate = value; | ||
|  |     return rq; | ||
|  |   }; | ||
|  | 
 | ||
|  |   rq.remaining = function() { | ||
|  |     return _queue.length; | ||
|  |   }; | ||
|  | 
 | ||
|  |   // clear the canvas | ||
|  |   rq.clear = function(func) { | ||
|  |     if (!arguments.length) { | ||
|  |       _clear(); | ||
|  |       return rq; | ||
|  |     } | ||
|  |     _clear = func; | ||
|  |     return rq; | ||
|  |   }; | ||
|  | 
 | ||
|  |   rq.invalidate = _invalidate; | ||
|  | 
 | ||
|  |   var timer_frame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { setTimeout(callback, 17); }; | ||
|  | 
 | ||
|  |   return rq; | ||
|  | }); | ||
|  | 
 | ||
|  | // --- | ||
|  | var color = d3.scale.linear() | ||
|  |    .domain([0, 0.5, 1]) | ||
|  |       .range(["#ef2212", "#e7c767", "#2799df"]) | ||
|  |       .interpolate(d3.interpolateHcl); | ||
|  | 
 | ||
|  | var VDC2 = VDC({b:2,n:seed}); | ||
|  | var VDC3 = VDC({b:3,n:seed}); | ||
|  | var VDC5 = VDC({b:5,n:seed}); | ||
|  | 
 | ||
|  | var in1 = 0, in2 = 0, out1 = 0, out2 = 0; | ||
|  | 
 | ||
|  | function update1() { | ||
|  |   var mypi = (in1 / (in1 + out1))*4, err = Math.abs(mypi - Math.PI)/Math.PI, lnerr = Math.log(err); | ||
|  |   document.getElementById("lout").innerHTML = PRINTJ.sprintf("PI = %f <br />err%% = %f<br />ln err = %f", mypi, err, lnerr); | ||
|  | } | ||
|  | function update2() { | ||
|  |   var mypi = (in2 / (in2 + out2))*4, err = Math.abs(mypi - Math.PI)/Math.PI, lnerr = Math.log(err); | ||
|  |   document.getElementById("rout").innerHTML = PRINTJ.sprintf("PI = %f <br />err%% = %f<br />ln err = %f", mypi, err, lnerr); | ||
|  | } | ||
|  | 
 | ||
|  | function generate1(n) { | ||
|  |   return d3.range(n).map(function(i) { | ||
|  |     var x = VDC2.next(), y = VDC3.next(); | ||
|  |     if(x*x + y*y <= 1) in1++; else out1++; | ||
|  |     if((in1 + out1) % 100 === 0) update1(); | ||
|  |     return [ canvas1.width*x, canvas1.height*y, color(VDC5.next()) ]; | ||
|  |   }); | ||
|  | } | ||
|  | 
 | ||
|  | function generate2(n) { | ||
|  |   return d3.range(n).map(function(i) { | ||
|  |     var x = Math.random(), y = Math.random(); | ||
|  |     if(x*x + y*y <= 1) in2++; else out2++; | ||
|  |     if((in2 + out2) % 100 === 0) update2(); | ||
|  |     return [ canvas2.width*x, canvas2.height*y, color(Math.random()) ]; | ||
|  |   }); | ||
|  | } | ||
|  | 
 | ||
|  | function make_dot(ctx) { | ||
|  |   return function(pos) { | ||
|  |     ctx.fillStyle = pos[2]; | ||
|  |     ctx.beginPath(); | ||
|  |     ctx.fillRect(pos[0]-1,pos[1]-1,2,2); | ||
|  |     ctx.stroke(); | ||
|  |     ctx.fill(); | ||
|  |   }; | ||
|  | } | ||
|  | 
 | ||
|  | function make_clear_canvas(ctx, canvas) { | ||
|  |   return function() { ctx.clearRect(0,0,canvas.width,canvas.height); make_boundary(canvas, ctx); }; | ||
|  | } | ||
|  | 
 | ||
|  | function make_boundary(canvas, ctx) { | ||
|  |   ctx.beginPath(); | ||
|  |   ctx.arc(0, canvas.height, canvas.width, 0, 2*Math.PI); | ||
|  |   ctx.stroke(); | ||
|  | } | ||
|  | 
 | ||
|  | window.onload = function() { | ||
|  | canvas1 = document.getElementById("canvas1"); | ||
|  | var ctx1 = canvas1.getContext("2d"); | ||
|  | ctx1.globalCompositeOperation = "destination-over"; | ||
|  | 
 | ||
|  | canvas2 = document.getElementById("canvas2"); | ||
|  | var ctx2 = canvas2.getContext("2d"); | ||
|  | ctx2.globalCompositeOperation = "destination-over"; | ||
|  | 
 | ||
|  | make_boundary(canvas1, ctx1); | ||
|  | make_boundary(canvas2, ctx2); | ||
|  | 
 | ||
|  | var dot1 = make_dot(ctx1); | ||
|  | var dot2 = make_dot(ctx2); | ||
|  | 
 | ||
|  | var clear_canvas1 = make_clear_canvas(ctx1, canvas1); | ||
|  | var clear_canvas2 = make_clear_canvas(ctx2, canvas2); | ||
|  | 
 | ||
|  | 
 | ||
|  | var render1 = renderQueue(dot1).clear(clear_canvas1); | ||
|  | var render2 = renderQueue(dot2).clear(clear_canvas2); | ||
|  | 
 | ||
|  | render1(generate1(PTS)); | ||
|  | render2(generate2(PTS)); | ||
|  | }; | ||
|  |   </script> | ||
|  |   <script type="text/javascript"> | ||
|  |     var _gaq = _gaq || []; | ||
|  |     _gaq.push(['_setAccount', 'UA-36810333-1']); | ||
|  |     _gaq.push(['_trackPageview']); | ||
|  | 
 | ||
|  |     (function() { | ||
|  |       var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; | ||
|  |       ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | ||
|  |       var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); | ||
|  |     })(); | ||
|  |   </script> | ||
|  | </html> |