I want to create a web-based demonstration of differential privacy. To do this, I need a JavaScript implementation of the Laplace noise distribution.
I've been unable to find basic noise distributions in JavaScript, such as Gaussian. This is surprising, because I would like that there would be lots of cool JavaScript demos showing how the distribution builds up, draw by draw, to produce a pretty bell-shaped curve.
How do I generate a Laplace noise distribution in Javascript?
function sgn(x) {
return x < 0 ? -1 : 1;
}
// From wikipedia:
// Lap(X) = mu - b sgn(U) ln (1-2|U|) where U is a random variable between -0.5 and 0.5
function laplace(mu, b) {
var U = Math.random() - 0.5;
return mu - (b * sgn(U) * Math.log(1 - 2* Math.abs(U)));
}
function privatize(F,deltaF,epsilon) {
return F + laplace(0.0, deltaF/epsilon);
}
Related
I reached out for help recently on math.stackexchange.com with a question about 2 dimensional algebra. The answer was promptly provided but it's in mathematical notation unfamiliar to me and the person giving the answer has stopped responding to my questions. While I am extremely grateful to BStar for providing this information, he/she has stopped replying both on the site and the chat, and doesn't seem interested in helping me understand it to the point that I could write programming code to calculate the desired point P. I respect that, but it leaves me stuck for now. Could someone help me convert this sequence of steps into a programming language such as Javascript? (I am actually working in PHP, but Javascript would be more convenient to represent in a runnable Snippet on stackoverflow .. I'm happy with any current language that I can translate into PHP).
The post is at https://math.stackexchange.com/questions/4110517/trig-101-calculate-coords-of-point-p-such-that-it-is-distance-n-from-line-ab-an/4110550?noredirect=1#comment8504010_4110550
The answer given is in Latex but here's a screenshot of it:
The latest description of the process by the author BStar: "Here is the process: First calculate cos B and use arccos to get B. Second calculate tanθ to get θ with arctan by using |BP| is the same from two triangles. Knowing these, we can get vectors BA’ and B’P, thus vectors OA and OP. We get θ to grt vector BA’ in this case, not the other way around. "
I can follow up until step (5) where the comma notation comes in, i.e. k = (-xb, -yb)(xc - xb, yc - yb) / ac. This seems to make k a two dimensional vector but I don't think I ever worked with this notation. Later, k is used in step (6) and (6a) to calculate theta, appearing both in the numerator and denominator of a fraction. I have no idea how to expand this to get an actual value for theta.
(Edit Note: The author BStar assumed point A is at the origin, so (xa, ya) = (0, 0) but I cannot make that assumption in the real world. Thus the vector BA in Step 1 is actually (xa - xb, ya - yb) and his formula for k shown above is actually k = (xa - xb, ya - yb)(xc - xb, yc - yb) / ac. This expansion needs to be carried through the calculation but it's not a major change.)
If we were to frame this in Javascript, I could lay out a framework of what is known at the beginning of the calculation. It's not productive to represent every single step of the mathematical proof given by BStar, but I'm not sure exactly what steps can be left as processes in the mathematical proof and what steps need expounding in code.
/* Known points - A, B, C */
var xa = 10, ya = 10;
var xb = 100, yb = 500;
var xc = 700, yc = 400;
/* Known lengths m and n (distance perpendicularly from AB and AC) */
var m = 30;
var n = 50;
/* Point we want to calculate, P */
var px = 0, py = 0;
/* Calculation goes here - some Javascript notes:
* var a = Math.sin(angInRadians);
* var b = Math.asin(opposite / hypotenuse);
* var c = Math.pow(number, 2); // square a number
* var d = Math.sqrt(number);
*/
/* Print the result */
console.log('Result: P (' + px + ', ' + py + ')');
How would one express the maths from the diagram in the programming snippet above?
I think I can get you to the angle of B but I'm not very good with math and get lost with all those variables. If you are stuck at figuring out the angle try this and see if it does what you want. It seems to do what step 5 is asking but double check my work.
let pointA = {x: 100, y: 0};
let pointB = {x: 20, y: 20};
let pointC = {x: 0, y: 100};
let distBA_x = pointB.x - pointA.x;
let distBA_y = pointB.y - pointA.y;
//let BA_a = Math.sqrt(distBA_x*distBA_x + distBA_y*distBA_y);
let distBC_x = pointB.x - pointC.x;
let distBC_y = pointB.y - pointC.y;
//let BC_c = Math.sqrt(distBC_x*distBC_x + distBC_y*distBC_y);
var angle = Math.atan2(distBA_x * distBC_y - distBA_y * distBC_x, distBA_x * distBC_x + distBA_y * distBC_y);
if(angle < 0) {angle = angle * -1;}
var degree_angle = angle * (180 / Math.PI);
console.log(degree_angle)
I've laid it out on a canvas so you can see it visually and change the parameters. Hope it helps. Here's the Codepen https://codepen.io/jfirestorm44/pen/RwKdpRw
BA • BC is a "dot product" between two vectors. The result is a single number: It's the sum of the products of vector components. If the vectors are (x1,y1) and (x2,y2) the dot product is x1x2+y1y2.
Assuming you don't have a library for vector calculations and don't want to create one, the code for computing k would be:
k = (-xb*(xc - xb)-yb*(yc - yb)) / ac
I have asked a question very similar to this so I will mention the previous solutions at the end, I have a website that calculates π with the client's CPU while storing it on a server, so far I've got:
'701.766.448.388' points inside the circle, and '893.547.800.000' in total, these numbers are calculated using this code. (working example at: https://jsfiddle.net/d47zwvh5/2/)
let inside = 0;
let size = 500;
for (let i = 0; i < iterations; i++) {
var Xpos = Math.random() * size;
var Ypos = Math.random() * size;
var dist = Math.hypot(Xpos - size / 2, Ypos - size / 2);
if (dist < size / 2) {
inside++;
}
}
The problem
(4 * 701.766.448.388) / 893.547.800.000 = 3,141483638
This is the result we get, which is correct until the fourth digit, 4 should be 5.
Previous problems:
I messed up the distance calculation.
I placed the circle's from 0...499 which should be 0...500
I didn't use float, which decreased the 'resolution'
Disclamer
It might just be that I've reached a limit but this demonstration used 1 million points and got 3.16. considering I've got about 900 billion I think it could be more precisely.
I do understand that if I want to calculate π this isn't the right way to go about it, but I just want to make sure that everything is right so I was hoping anyone could spot something wrong or do I just need more 'dots'.
EDIT: There are quite a few mentions about how unrealistic the numbers where, these mentions where correct and I have now updated them to be correct.
You could easily estimate what kind of error (error bars) you should get, that's the beauty of the Monte Carlo. For this, you have to compute second momentum and estimate variance and std.deviation. Good thing is that collected value would be the same as what you collect for mean, because you just added up 1 after 1 after 1.
Then you could get estimation of the simulation sigma, and error bars for desired value. Sorry, I don't know enough Javascript, so code here is in C#:
using System;
namespace Pi
{
class Program
{
static void Main(string[] args)
{
ulong N = 1_000_000_000UL; // number of samples
var rng = new Random(312345); // RNG
ulong v = 0UL; // collecting mean values here
ulong v2 = 0UL; // collecting squares, should be the same as mean
for (ulong k = 0; k != N; ++k) {
double x = rng.NextDouble();
double y = rng.NextDouble();
var r = (x * x + y * y < 1.0) ? 1UL : 0UL;
v += r;
v2 += r * r;
}
var mean = (double)v / (double)N;
var varc = ((double)v2 / (double)N - mean * mean ) * ((double)N/(N-1UL)); // variance
var stdd = Math.Sqrt(varc); // std.dev, should be sqrt(Pi/4 (1-Pi/4))
var errr = stdd / Math.Sqrt(N);
Console.WriteLine($"Mean = {mean}, StdDev = {stdd}, Err = {errr}");
mean *= 4.0;
errr *= 4.0;
Console.WriteLine($"PI (1 sigma) = {mean - 1.0 * errr}...{mean + 1.0 * errr}");
Console.WriteLine($"PI (2 sigma) = {mean - 2.0 * errr}...{mean + 2.0 * errr}");
Console.WriteLine($"PI (3 sigma) = {mean - 3.0 * errr}...{mean + 3.0 * errr}");
}
}
}
After 109 samples I've got
Mean = 0.785405665, StdDev = 0.410540627166729, Err = 1.29824345388086E-05
PI (1 sigma) = 3.14157073026184...3.14167458973816
PI (2 sigma) = 3.14151880052369...3.14172651947631
PI (3 sigma) = 3.14146687078553...3.14177844921447
which looks about right. It is easy to see that in ideal case variance would be equal to (Pi/4)*(1-Pi/4). It is really not necessary to compute v2, just set it to v after simulation.
I, frankly, don't know why you're getting not what's expected. Precision loss in summation might be the answer, or what I suspect, you simulation is not producing independent samples due to seeding and overlapping sequences (so actual N is a lot lower than 900 trillion).
But using this method you control error and check how computation is going.
UPDATE
I've plugged in your numbers to show that you're clearly underestimating the value. Code
N = 893_547_800_000UL;
v = 701_766_448_388UL;
v2 = v;
var mean = (double)v / (double)N;
var varc = ((double)v2 / (double)N - mean * mean ) * ((double)N/(N-1UL));
var stdd = Math.Sqrt(varc); // should be sqrt(Pi/4 (1-Pi/4))
var errr = stdd / Math.Sqrt(N);
Console.WriteLine($"Mean = {mean}, StdDev = {stdd}, Err = {errr}");
mean *= 4.0;
errr *= 4.0;
Console.WriteLine($"PI (1 sigma) = {mean - 1.0 * errr}...{mean + 1.0 * errr}");
Console.WriteLine($"PI (2 sigma) = {mean - 2.0 * errr}...{mean + 2.0 * errr}");
Console.WriteLine($"PI (3 sigma) = {mean - 3.0 * errr}...{mean + 3.0 * errr}");
And output
Mean = 0.785370909522692, StdDev = 0.410564786603016, Err = 4.34332975349809E-07
PI (1 sigma) = 3.14148190075886...3.14148537542267
PI (2 sigma) = 3.14148016342696...3.14148711275457
PI (3 sigma) = 3.14147842609506...3.14148885008647
So, clearly you have problem somewhere (code? accuracy lost in representation? accuracy lost in summation? repeated/non-independent sampling?)
any FPU operation will decrease your accuracy. Why not do something like this:
let inside = 0;
for (let i = 0; i < iterations; i++)
{
var X = Math.random();
var Y = Math.random();
if ( X*X + Y*Y <= 1.0 ) inside+=4;
}
if we probe first quadrant of unit circle we do not need to change the dynamic range by size and also we can test the distances in powered by 2 form which get rid of the sqrt. These changes should increase the precision and also the speed.
Not a JAVASCRIPT coder so I do not know what datatypes you use but you need to be sure you do not cross its precision. In such case you need to add more counter variables to ease up the load on it. For more info see: [edit1] integration precision.
As your numbers are rather big I bet you crossed the boundary already (there should be no fraction part and trailing zeros are also suspicious) For example 32bit float can store only integers up to
2^23 = 8388608
and your 698,565,481,000,000 is way above that so even a ++ operation on such variable will cause precision loss and when the exponent is too big it even stop adding...
On integers is this not a problem but once you cross the boundary depending on internal format the value wraps around zero or negates ... But I doubd that is the case as then the result would be way off from PI.
I am aware that random integers can be generated in JavaScript like this:
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
But what I want is a set of random numbers that are biased towards a specific value.
As an example, if my specific center value is 200, I want a set of random numbers that has a large range, but mostly around 200. Hopefully there will be a function like
biasedRandom(center, biasedness)
It sounds like a Gaussian distribution might be about right here.
This stackoverflow post describes how to produce something that is Gaussian in shape. We can then scale and shift the distribution by two factors;
The mean (200 in this case) which is where the distribution is centred
The variance which gives control over the width of the distribution
I have included a histogram of the generated numbers (using plotly) in my example so you can easily see how varying these two parameters v and mean affects the numbers generated. In your real code you would not need to include the plotly library.
// Standard Normal variate using Box-Muller transform.
function randn_bm() {
var u = 0, v = 0;
while(u === 0) u = Math.random(); //Converting [0,1) to (0,1)
while(v === 0) v = Math.random();
return Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v );
}
//generate array
// number of points
let n = 50;
// variance factor
let v = 1;
// mean
let mean = 200;
let numbers = []
for (let i=0; i<n;i++){
numbers.push(randn_bm())
}
// scale and shift
numbers = numbers.map( function (number){ return number*v + mean})
// THIS PURELY FOR PLOTTING
var trace = {
x: numbers,
type: 'histogram',
};
var data = [trace];
Plotly.newPlot('myDiv', data);
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id="myDiv"></div>
In JavaScript, there is no native cbrt method available. In theory, you could use a method like this:
function cbrt(x) {
return Math.pow(x, 1 / 3);
}
However, this fails because identities in mathematics don't necessarily apply to floating point arithmetic. For example, 1/3 cannot be accurately represented using a binary floating point format.
An example of when this fails is the following:
cbrt(Math.pow(4, 3)); // 3.9999999999999996
This gets worse as the number gets larger:
cbrt(Math.pow(165140, 3)); // 165139.99999999988
Is there any algorithm which is able to calculate a cube root value to within a few ULP (preferably 1 ULP if possible)?
This question is similar to Computing a correctly rounded / an almost correctly rounded floating-point cubic root, but keep in mind that JavaScript doesn't have any higher-precision number types to work with (there is only one number type in JavaScript), nor is there a built-in cbrt function to begin with.
You can port an existing implementation, like this one in C, to Javascript. That code has two variants, an iterative one that is more accurate and a non-interative one.
Ken Turkowski's implementation relies on splitting up the radicand into mantissa and exponent and then reassembling it, but this is only used to bring it into the range between 1/8 and 1 for the first approximation by enforcing a binary exponent between -2 and 0. In Javascript, you can do this by repeatedly dividing or multiplying by 8, which should not affect accuracy, because it is just an exponent shift.
The implementation as shown in the paper is accurate for single-precision floating-point numbers, but Javascript uses double-precision numbers. Adding two more Newton iterations yields good accuracy.
Here's the Javascript port of the described cbrt algorithm:
Math.cbrt = function(x)
{
if (x == 0) return 0;
if (x < 0) return -Math.cbrt(-x);
var r = x;
var ex = 0;
while (r < 0.125) { r *= 8; ex--; }
while (r > 1.0) { r *= 0.125; ex++; }
r = (-0.46946116 * r + 1.072302) * r + 0.3812513;
while (ex < 0) { r *= 0.5; ex++; }
while (ex > 0) { r *= 2; ex--; }
r = (2.0 / 3.0) * r + (1.0 / 3.0) * x / (r * r);
r = (2.0 / 3.0) * r + (1.0 / 3.0) * x / (r * r);
r = (2.0 / 3.0) * r + (1.0 / 3.0) * x / (r * r);
r = (2.0 / 3.0) * r + (1.0 / 3.0) * x / (r * r);
return r;
}
I haven't tested it extensively, especially not in badly defined corner cases, but the tests and comparisons with pow I have done look okay. Performance is probably not so great.
Math.cbrt has been added to ES6 / ES2015 specification so at least first check to see if it defined. It can be used like:
Math.cbrt(64); //4
instead of
Math.pow(64, 1/3); // 3.9999999999999996
You can use formula for pow computation
x^y = exp2(y*log2(x))
x^(1/3) = exp2(log2(x)*1/3)
= exp2(log2(x)/3)
base for log,exp can be any but 2 is directly implemented on most FPU's
now you divide by 3 ... and 3.0 is represented by FP accurately.
or you can use bit search
find the exponent of output (e= ~1/3 of integer part bit count of x)
create appropriate fixed number y (mantissa=0 and exponent=e)
start bin search from MSB bit of y
toggle bit to one
if (y*y*y>x) toggle bit back to zero
loop #3 with next bit (stop after LSB)
The result of binary search is as precise as it can be (no other method can beat it) ... you need mantissa-bit-count iterations for this. You have to use FP for computation so conversion of your y to float is just copying mantissa bits and set exponent.
See pow on integer arithmetics in C++
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
Did you ever played the "Tank wars" game?
I'm programming this game with JavaScript + Canvas (for a personal challenge), and what I need is an algorithm for generating that random green land every time I start the game, but I'm not too good at maths, so I can't do it myself.
I don't want someone to give me the code, I only want the idea for the algorithm.
Thanks!
(9 segments)
Fiddle demo
(7 segments)
The main generation function look like this:
var numOfSegments = 9; // split horizontal space
var segment = canvas.width / numOfSegments; // calc width of each segment
var points = [], calcedPoints;
var variations = 0.22; // adjust this: lower = less variations
var i;
//produce some random heights across the canvas
for(i=0; i < numOfSegments + 1; i++) {
points.push(segment * i);
points.push(canvas.height / 2.8 + canvas.height * variations * Math.random());
}
//render the landscape
ctx.beginPath();
ctx.moveTo(canvas.width, canvas.height);
ctx.lineTo(0, canvas.height);
calcedPoints = ctx.curve(points); // see below
ctx.closePath();
ctx.fillStyle = 'green';
ctx.fill();
The curve() function is a separate function which generate a cardinal spline. In here you can modify it to also store tension values to make more spikes. You can also used the generated points as a basis for where and at what angle the tanks will move at.
The function for cardinal spline:
CanvasRenderingContext2D.prototype.curve = function(pts, tension, numOfSegments) {
tension = (tension != 'undefined') ? tension : 0.5;
numOfSegments = numOfSegments ? numOfSegments : 16;
var _pts = [], res = [], t, i, l, r = 0,
x, y, t1x, t2x, t1y, t2y,
c1, c2, c3, c4, st, st2, st3, st23, st32;
_pts = pts.concat();
_pts.unshift(pts[1]);
_pts.unshift(pts[0]);
_pts.push(pts[pts.length - 2]);
_pts.push(pts[pts.length - 1]);
l = (_pts.length - 4);
for (i = 2; i < l; i+=2) {
//overrides and modifies tension for each segment.
tension = 1 * Math.random() - 0.3;
for (t = 0; t <= numOfSegments; t++) {
t1x = (_pts[i+2] - _pts[i-2]) * tension;
t2x = (_pts[i+4] - _pts[i]) * tension;
t1y = (_pts[i+3] - _pts[i-1]) * tension;
t2y = (_pts[i+5] - _pts[i+1]) * tension;
st = t / numOfSegments;
st2 = st * st;
st3 = st2 * st;
st23 = st3 * 2;
st32 = st2 * 3;
c1 = st23 - st32 + 1;
c2 = -(st23) + st32;
c3 = st3 - 2 * st2 + st;
c4 = st3 - st2;
x = c1 * _pts[i] + c2 * _pts[i+2] + c3 * t1x + c4 * t2x;
y = c1 * _pts[i+1] + c2 * _pts[i+3] + c3 * t1y + c4 * t2y;
res[r++] = x;
res[r++] = y;
} //for t
} //for i
l = res.length;
for(i=0;i<l;i+=2) this.lineTo(res[i], res[i+1]);
return res; //return calculated points
}
Look into perlin noise generation, this in combination with a good smoothing algorithm can produce some pretty good terrain, and is fairly quick. There is a reference version of the code kicking around the net somewhere, which should provide you with a fairly hefty headstart
First you need a point that is random y (between 55,65); got x=0
So this is the origin point for the green, lets keep it as x1,y1 (x1 always 0).
Then you need a random integer between 30 to 40. This is x2. And a random y which is in the range y1 + 8 to y1 + 20.
Then x3 and y3 on same principle (lets call it formula type 1)
Now you need to first get a random either -1 or 1, this will be directions of y4. So y4 can go higher than y3 or lower ... this will be formula type 2.
You need to keep a max and min y for a new y, if it crosses that then go the other way -> this will be a correction type formula 3.
Xn keeps increasing till its >= width of board.
Join the lines in a eclipses ... and looks like web searches is the way to go !
I am sure there are a lot of coded libraries that you could use to make this easy. But if you are trying to code this by yourself, here is my idea.
You need to define terrain from everything else. So every part of your environment is a cluster for example. You need to define how are separated these clusters, by nodes(points) for example.
You can create a polygon from a sequence of points, and this polygon can become whatever you want, in this case terrain.
See that on the image you passed, there are peaks, those are the nodes (points). Remember to define also nodes on the borders of your environment.
There are surely a novel, written algorithms, either fractal as #DesertIvy pointed out or others, maybe there are libraries as well, but if you want toi generate what is in the image, it can be pretty straightforward, since it is just (slightly curved) lines between points. If you do it in phases, not trying to be correct at once, it is easy:
Split x region of your game screen into sections (with some minimal and maximal width) using random (you may be slightly off in last section, but it does not matter as much, I think). Remember the x-es where sections meet (including the ones at game screen border)
Prepare some data structure to include y-s as well, on previously remembered x-s. Start with leftmost.y = 0, slope = Math.random()-0.5;.
Generate each next undefined y beginning with 1: right.y = left.y + slope * (right.x-left.x); as well as update slope after each y: slope += Math.random()-0.5;. Do not bother, for the moment, if it all fits into game screen.
If you want arcs, you can generate "curviness" parameter for each section randomly which represent how much the middle of the line is bumped compared to straight lines.
Fit the ys into the game screen: first find maximal and minimal generated y (mingeny, maxgeny) (you can track this while generating in point 4). Choose where the max and min y in game screen (minscry, maxscry) (say at the top fourth and at the bottom fourth). Then transform generated ys so that it spans between minscry and maxscry: for every point, do apoint.y = minscry + (maxscry-minscry)/(maxgeny-mingeny)*(apoint.y-mingeny).
Now use lines between [x,y] points as a terrain, if you want to use "curviness", than add curvemodifier to y for any particular x in a section between leftx and rightx. The arc need not to be a circle: I would suggest a parabola or cosine which are easy to produce: var middle = (left.x+right.x)/2; var excess = (x-left)/(middle-left); and then either var curvemodifier = curviness * (1-excess*excess); or var curvemodifier = curviness * Math.cos(Math.PI/2*excess).
Wow...At one point I was totally addicted to tank wars.
Since you are on a learning adventure...
You might also learn about the context.globalCompositeOperation.
This canvas operation will let you grab an image of actual grass and composite it into your game.
You can randomize the grass appearance by changing the x/y of your drawImage();
Yes, the actual grass would probably be too distracting to include in your finished game, but learning about compositing would be valuable knowledge to have.
...and +1 for the question: Good for you in challenging yourself !