Improving Javascript Mandelbrot Plot Performance - javascript

I have written a javascript program which plots the Mandelbrot set with the normal pretty colours approaching the boundary. I was planning on adding a zoom function next but it is far far too slow for this to be sensible.
I have posted the most important portion of the code here:
while (x * x < 2 && y * y < 2 && iteration < max_iteration) {
xtemp = (x * x) - (y * y) + xcord;
y = (2 * x * y) + ycord;
x = xtemp;
iteration = iteration + 1;
}
and have linked to a jsfiddle with the whole page here: http://jsfiddle.net/728dn2m0/
I have a few global variables which I could take into the main loop but that would result in additional calculations for every single pixel. I read on another SO question that an alternative to the 1x1 rectangle was to use image data but the performance difference was disputed. Another possibility would be rewriting the while statement as some other conditional loop but I'm not convinced that would give me the gains I'm looking for.
I'd consider myself a newbie so I'm happy to hear comments on any aspect of the code but what I'm really after is something which will massively increase performance. I suspect I'm being unreasonable in my expectations of what javascript in the browser can manage but I hope that I'm missing something significant and there are big gains to be found.
Thanks in advance,
Andrew

Using setInterval as an external loop construct slows the calculation down. You set it to 5 ms for a single pixel, however the entire Mandelbrot map calculation can be done within 1 second. So a single call to your function draws a pixel very quickly and then waits about the 99.99% of that 5 milliseconds.
I replaced
if (m<=(width+1))
with
while (m<=(width+1))
and removed the setInterval.
This way the entire calculation is done in one step, without refresh to the screen and without using setInterval as an external loop construct. I forked your script and modified it: http://jsfiddle.net/karatedog/2o4gjrv2/6/
In the script I modified the bailout condition from (x*x < 2 && y*y < 2) to (x < 2 && y < 2) just as I suggested in a previous comment and revealed some hidden pixel, check the difference!

I had indeed missed something significant. The timer I had used in order to prevent the page hanging while the set was plotted was limiting the code to one pixel every 5 milliseconds, in other words 200 pixels per second. Not clever!
I am now plotting one line at a time and it runs a lot better. Not yet real time but it is a lot quicker.
Thanks for the ideas. I will look into the escape condition to see what it should be.
A new jsfiddle with the revised code is here: http://jsfiddle.net/da1qyh9y/
and the for statement I've added is here:
function main_loop() {
if (m<=(width+1)) {
var n;
for (n=0; n<height; n=n+1) {

Related

Optimize animation with javascript assigning value

I am building an animation with lots of effects and animation in a website. I am trying to optimize the efficiency of those animations since some of them are a little complex to low CPU/RAM devices. The animations are not smooth as I want as you can see here https://www.empresasite.com.br
So I realize in many parts of my code I do this:
var x = 38; //this value changes every 50ms
document.getElementById("a").style.left = document.getElementById("b").style.left = document.getElementById("c").style.left = document.getElementById("d").style.left = document.getElementById("e").style.left = x + "px";
Actually it's a simplification above, I run the code above with at least 13 elements a = b = c = d .... m = x; and at least with 4 properties (left, height, box-shadow and background-color).
So I was wondering if there is any better alternative to assign the same value to multiple elements/objects at once?
Maybe the code below would be faster? I used it but I didnt see a significant improvement in animation, maybe I should have seen it?
var x = 38;
x = x + "px";
document.getElementById("a").style.left = x;
document.getElementById("b").style.left = x;
document.getElementById("c").style.left = x;
document.getElementById("d").style.left = x;
document.getElementById("e").style.left = x;
I think the code above should be faster right? I say this cause every element updates its own property (left) retrieving the value from "x". In the first example I gave MAYBE javascript is assigning the value of the previous element in the chain of "=" sign so it has to assign "x" to the first element then assign the value of the first element to the second... go on.
Do you know exactly what jquery does when I use this:
$(".elements").css({left:x});
Does it use some optimization?
You could increase performance no-end by using translate instead of modifying position.
Using the jQuery variation you asked will not make any difference, as you are still modifying position left.
After playing around with most of the javascript benchmarking tools online I came up to this conclusion:
1) Jquery is the faster method of all native js solutions I used. Maybe Jquery uses some sort of optimization when you apply the same property to lots of elements at once! So you should rely on $(".class").css("left",x) to apply the x value to left property for hundreds of elements and it will be the faster solution;
2) The second solution is apply x individually TO EACH element. Example:
var x = 38;
document.getElementById("a").style.left = x;
document.getElementById("b").style.left = x;
3) The worst solution was actually the one I was using in the website that I was facing not smooth animations. So avoid this:
document.getElementById("a").style.left = document.getElementById("b").style.left = ... = ... = x;
The difference from the 1st solution to the 3rd is really noticeable. You can check it in the links below (pay special attention to the animation at the top):
1) https://www.empresasite.com.br/?q=principal&before -> this is using the 3rd solution
2) https://www.empresasite.com.br/?q=principal -> this is using the 1st solution
In a computer with lots of resources you may not see a difference but if you run this in a computer with 4GB of RAM or less you will see a big impact!
Hope this helps anyone that does not have smooth animations!

Simple way to return values approximating a sin/cosin curve, without using trigonometry?

Apologies in advance for a difficult-to-explain question, for which the answer might simply be "no"...
I have a value -1 >= n <= 1
I'd like to increase its amplitude, say by 2: 2*n
I'd also like to adjust its phase, say by .5: 2*n + .5
How can I do this so that when n increases past 1, it flips signs and reduces itself, for example: when n increases to 1.1, the result is actually .9.
I know this can be done using trig, but I'm having difficulty increasing its amplitude and shifting its phase - by the time I'm done doing both I get this expression:
Math.sin(n*1.57 + Math.PI/4)
And to that expression I still need to perform additional calcs/rounding to get my final values; the expression becomes complicated bloated.
I'm wondering if there's a simpler way to get the desired range/values, avoiding trig altogether? I imagine an operator similar to the modulo, except instead of "resetting" to 0, it reduces in value...
Turns out, a triangle wave solves my problem. It gives oscillating values similar to sine (without ease), and it avoids Math.trig and simplifies my formula. I expanded on the formula given in this SO answer as well as these wikipedia formulas.
Fried Brice's answer suggesting sawtooth was on the right track - but triangle wave is better suited for me, and the 1-line formula makes my eyes feel better.
You can explicitly write out the formula in cases for one period, and use recursion for values outside the fundamental period.
E.g.
function notTrig(x) {
switch (true) {
case (x >= 0 && x < 1):
return x
case (x >= 1 && x < 2):
return 2 - x
default:
notTrig(x - 2)
}
}
This should give you a sawtooth signal with mean 1/2, amplitude 1/2, and period 2. You need to handle negatives as well: exercise left to asker ;-)
Edit: It occurs to me after the fact that I'm misusing the term "sawtooth wave" above. The function I am describing is continuous, and the terms I should be using is "triangle wave." That said, I am very pleased with #calipoop's answer.

Better random function in JavaScript

I'm currently making a Conway's Game of Life reproduction in JavaScript and I've noticed that the function Math.random() is always returning a certain pattern. Here's a sample of a randomized result in a 100x100 grid:
Does anyone knows how to get better randomized numbers?
ApplyRandom: function() {
var $this = Evolution;
var total = $this.Settings.grid_x * $this.Settings.grid_y;
var range = parseInt(total * ($this.Settings.randomPercentage / 100));
for(var i = 0; i < total; i++) {
$this.Infos.grid[i] = false;
}
for(var i = 0; i < range; i++) {
var random = Math.floor((Math.random() * total) + 1);
$this.Infos.grid[random] = true;
}
$this.PrintGrid();
},
[UPDATE]
I've created a jsFiddle here: http://jsfiddle.net/5Xrs7/1/
[UPDATE]
It seems that Math.random() was OK after all (thanks raina77ow). Sorry folks! :(. If you are interested by the result, here's an updated version of the game: http://jsfiddle.net/sAKFQ/
(But I think there's some bugs left...)
This line in your code...
var position = (y * 10) + x;
... is what's causing this 'non-randomness'. It really should be...
var position = (y * $this.Settings.grid_x) + x;
I suppose 10 was the original size of this grid, that's why it's here. But that's clearly wrong: you should choose your position based on the current size of the grid.
As a sidenote, no offence, but I still consider the algorithm given in #JayC answer to be superior to yours. And it's quite easy to implement, just change two loops in ApplyRandom function to a single one:
var bias = $this.Settings.randomPercentage / 100;
for (var i = 0; i < total; i++) {
$this.Infos.grid[i] = Math.random() < bias;
}
With this change, you will no longer suffer from the side effect of reusing the same numbers in var random = Math.floor((Math.random() * total) + 1); line, which lowered the actual cell fillrate in your original code.
Math.random is a pseudo random method, that's why you're getting those results. A by pass i often use is to catch the mouse cursor position in order to add some salt to the Math.random results :
Math.random=(function(rand) {
var salt=0;
document.addEventListener('mousemove',function(event) {
salt=event.pageX*event.pageY;
});
return function() { return (rand()+(1/(1+salt)))%1; };
})(Math.random);
It's not completly random, but a bit more ;)
A better solution is probably not to randomly pick points and paint them black, but to go through each and every point, decide what the odds are that it should be filled, and then fill accordingly. (That is, if you want it on average %20 percent chance of it being filled, generate your random number r and fill when r < 0.2 I've seen a Life simulator in WebGL and that's kinda what it does to initialize...IIRC.
Edit: Here's another reason to consider alternate methods of painting. While randomly selecting pixels might end up in less work and less invocation of your random number generator, which might be a good thing, depending upon what you want. As it is, you seem to have selected a way that, at most some percentage of your pixels will be filled. IF you had kept track of the pixels being filled, and chose to fill another pixel if one was already filled, essentially all your doing is shuffling an exact percentage of black pixels among your white pixels. Do it my way, and the percentage of pixels selected will follow a binomial distribution. Sometimes the percentage filled will be a little more, sometimes a little less. The set of all shufflings is a strict subset of the possibilities generated this kind of picking (which, also strictly speaking, contains all possibilities for painting the board, just with astronomically low odds of getting most of them). Simply put, randomly choosing for every pixel would allow more variance.
Then again, I could modify the shuffle algorithm to pick a percentage of pixels based upon numbers generated from a binomial probability distribution function with a defined expected/mean value instead of the expected/mean value itself, and I honestly don't know that it'd be any different--at least theoretically--than running the odds for every pixel with the expected/mean value itself. There's a lot that could be done.
console.log(window.crypto.getRandomValues(new Uint8Array(32))); //return 32 random bytes
This return a random bytes with crypto-strength: https://developer.mozilla.org/en/docs/Web/API/Crypto/getRandomValues
You can try
JavaScript Crypto Library (BSD license). It is supposed to have a good random number generator. See here an example of usage.
Stanford JavaScript Crypto Library (BSD or GPL license). See documentation for random numbers.
For a discussion of strength of Math.random(), see this question.
The implementation of Math.random probably is based on a linear congruential generator, one weakness of which is that a random number depends on the earlier value, producing predictable patterns like this, depending on the choice of the constants in the algorithm. A famous example of the effect of poor choice of constants can be seen in RANDU.
The Mersenne Twister random number generator does not have this weakness. You can find an implementation of MT in JavaScript for example here: https://gist.github.com/banksean/300494
Update: Seeing your code, you have a problem in the code that renders the grid. This line:
var position = (y * 10) + x;
Should be:
var position = (y * grid_x) + x;
With this fix there is no discernible pattern.
You can using the part of sha256 hash from timestamp including nanoseconds:
console.log(window.performance.now()); //return nanoseconds inside
This can be encoded as string,
then you can get hash, using this: http://geraintluff.github.io/sha256/
salt = parseInt(sha256(previous_salt_string).substring(0, 12), 16);
//48 bits number < 2^53-1
then, using function from #nfroidure,
write gen_salt function before, use sha256 hash there,
and write gen_salt call to eventListener.
You can use sha256(previous_salt) + mouse coordinate, as string to get randomized hash.

Changing a value gradually for animation

Let's suppose I have a variable dimension which I want to change from a value a to a value b.
a and b are integers and the first is major than the second.
To do this linearly I should do:
while (dimension < a)
dimension = dimension + 1
But what if I want it to grow exponentially? I totally suck at math and I can't figure this out. I was trying:
while (dimension < a)
dimension = dimension * dimension
the point is the value gets out of control almost immediately, it gets huge (way bigger than a)
Even if I try to use a huge scale (by setting a to a gigantic value) I can't get this done... And yet it seems these guys did it, and I think it should be easy too!
They also manage to do the same with all sorts of crazy equations all of which would be easily to me if only I were able to implement just one!
I just want a value to increase from 1 to 2 but gradually...
Hope someone can help, thanks!
One extremely simple way to do it is to have a second counter that gets incremented by a smaller amount each iteration, and multiply it by the original counter to set it. Example, in your case:
step = 1.2;
while(dimension < a) {
dimension = Math.max(dimension * step, a);
step += 0.1;
}
Tweaking the values will probably be necessary to achieve the exact desired effect, but that's the general idea of it.
The call to Math.max will make sure that the value never goes over your goal.

Check if two objects are facing eachother

I've searched all over and couldn't find an answer to this seemingly common question, surprisingly. The problem I'm currently facing is checking if the player is facing an enemy, then if so within what range of the players' view (adjustable) and if it's within that range then move away in the nearest safe direction.
Here's a picture :D
So, how would I accomplish this? I have the x, y, and direction, of every ship object. This is my last failed attempt, attempting to consider that the player's direction will be exactly 180 degrees away from the enemy's direction relative to the player.
var direction=Math.direction(this.x,this.y,player.x,player.y,1),
playerview=Math.abs(direction)-Math.abs(player.direction-180)
if(Math.abs(playerview)<10) {
console.log('in view')
this.xVelocity+=AI.speed*Math.sin(playerview*Math.PI/180)
this.xVelocity+=AI.speed*Math.cos(playerview*Math.PI/180)
}
In this example, 10 would be the range. Of course, I've only managed to make ships rotate to the right, so aside from the detection only working on half a circle I can't make the enemy go to the right side either. Any ideas?
In Your code, You are modifying this.xVelocity twice instead of modifying this.yVelocity.
I guess, Math.direction is not in the JavaScript/ECMA standard. Are You sure, You are using it correctly? Consider Math.atan2.
Moreover, You should provide a definition of "facing each other".
If it's "seeing each other", then Your comment "in view" is misleading.
But the main issue is:
Math.abs(angleInDegrees) modifies the angle!
The correct way to build an absolute value of an angle is:
while (angleInDegrees < 0)
{
angleInDegrees += 360;
}
// If necessary, add this too:
while (angleInDegrees >= 360)
{
angleInDegrees -= 360;
}
-10 and 350 are identical, -10 and 10 are 20 degrees apart.
For further explanation, let's call the code above normalizeAngle
(Note: For huge values, the loop may run very long or even forever. If such values may occur, this should be checked.)
The following should do the trick:
playerview = normalizeAngle(direction - player.direction - 180)
if (playerview < range || playerview > 360-range) {
By the way: "playerview" should be the mininum from the player's field of view and the enemy's field of view.

Categories

Resources