Using f(x) = 1/x in JavaScript - javascript

Every millisecond, variable light is incremented by one until it reaches 1/3rd of variable universe, or until it's 3 times the variable matter.
if (light < (universe * (1/3)) || light < matter * 3 && light <= universe) {
light++;
}
Instead, I want light to increase slower the closer it gets to the top,
(1/3rd universe or 3 * matter)
like this picture ( f(x) = 1/x ).
How do I do this?

Something like this might work:
var speed = 10;
var target = Math.max(universe / 3, Math.min(universe, matter * 3));
if (light < target) {
light += (target - light) / speed;
}

You need to make sure that light is a floating point variable, the ++ operator would usually used just for integers.
You just need to add on 1/light on each iteration
-
var light = 0.0;
if (...) {
light += 1/light;
}

So here speed starts out by 100, and then i added a interval so it continues every 1000milliseconds/1second and it will go on.
(function(){
setInterval(function(){
var speed= 99999999;
if(light<(universe/3) || light<(matter*3) && light <= universe)){
light+=speed;
speed--;
}
},1000)
})()
And Yes.. Infinty is a keyword in javascript.

Related

Trying to optimize my code to either remove nested loop or make it more efficient

A friend of mine takes a sequence of numbers from 1 to n (where n > 0)
Within that sequence, he chooses two numbers, a and b
He says that the product of a and b should be equal to the sum of all numbers in the sequence, excluding a and b
Given a number n, could you tell me the numbers he excluded from the sequence?
Have found the solution to this Kata from Code Wars but it times out (After 12 seconds) in the editor when I run it; any ideas as too how I should further optimize the nested for loop and or remove it?
function removeNb(n) {
var nArray = [];
var sum = 0;
var answersArray = [];
for (let i = 1; i <= n; i++) {
nArray.push(n - (n - i));
sum += i;
}
var length = nArray.length;
for (let i = Math.round(n / 2); i < length; i++) {
for (let y = Math.round(n / 2); y < length; y++) {
if (i != y) {
if (i * y === sum - i - y) {
answersArray.push([i, y]);
break;
}
}
}
}
return answersArray;
}
console.log(removeNb(102));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I think there is no reason for calculating the sum after you fill the array, you can do that while filling it.
function removeNb(n) {
let nArray = [];
let sum = 0;
for(let i = 1; i <= n; i++) {
nArray.push(i);
sum += i;
}
}
And since there could be only two numbers a and b as the inputs for the formula a * b = sum - a - b, there could be only one possible value for each of them. So, there's no need to continue the loop when you find them.
if(i*y === sum - i - y) {
answersArray.push([i,y]);
break;
}
I recommend looking at the problem in another way.
You are trying to find two numbers a and b using this formula a * b = sum - a - b.
Why not reduce the formula like this:
a * b + a = sum - b
a ( b + 1 ) = sum - b
a = (sum - b) / ( b + 1 )
Then you only need one for loop that produces the value of b, check if (sum - b) is divisible by ( b + 1 ) and if the division produces a number that is less than n.
for(let i = 1; i <= n; i++) {
let eq1 = sum - i;
let eq2 = i + 1;
if (eq1 % eq2 === 0) {
let a = eq1 / eq2;
if (a < n && a != i) {
return [[a, b], [b, a]];
}
}
}
You can solve this in linear time with two pointers method (page 77 in the book).
In order to gain intuition towards a solution, let's start thinking about this part of your code:
for(let i = Math.round(n/2); i < length; i++) {
for(let y = Math.round(n/2); y < length; y++) {
...
You already figured out this is the part of your code that is slow. You are trying every combination of i and y, but what if you didn't have to try every single combination?
Let's take a small example to illustrate why you don't have to try every combination.
Suppose n == 10 so we have 1 2 3 4 5 6 7 8 9 10 where sum = 55.
Suppose the first combination we tried was 1*10.
Does it make sense to try 1*9 next? Of course not, since we know that 1*10 < 55-10-1 we know we have to increase our product, not decrease it.
So let's try 2*10. Well, 20 < 55-10-2 so we still have to increase.
3*10==30 < 55-3-10==42
4*10==40 < 55-4-10==41
But then 5*10==50 > 55-5-10==40. Now we know we have to decrease our product. We could either decrease 5 or we could decrease 10, but we already know that there is no solution if we decrease 5 (since we tried that in the previous step). So the only choice is to decrease 10.
5*9==45 > 55-5-9==41. Same thing again: we have to decrease 9.
5*8==40 < 55-5-8==42. And now we have to increase again...
You can think about the above example as having 2 pointers which are initialized to the beginning and end of the sequence. At every step we either
move the left pointer towards right
or move the right pointer towards left
In the beginning the difference between pointers is n-1. At every step the difference between pointers decreases by one. We can stop when the pointers cross each other (and say that no solution can be obtained if one was not found so far). So clearly we can not do more than n computations before arriving at a solution. This is what it means to say that the solution is linear with respect to n; no matter how large n grows, we never do more than n computations. Contrast this to your original solution, where we actually end up doing n^2 computations as n grows large.
Hassan is correct, here is a full solution:
function removeNb (n) {
var a = 1;
var d = 1;
// Calculate the sum of the numbers 1-n without anything removed
var S = 0.5 * n * (2*a + (d *(n-1)));
// For each possible value of b, calculate a if it exists.
var results = [];
for (let numB = a; numB <= n; numB++) {
let eq1 = S - numB;
let eq2 = numB + 1;
if (eq1 % eq2 === 0) {
let numA = eq1 / eq2;
if (numA < n && numA != numB) {
results.push([numA, numB]);
results.push([numB, numA]);
}
}
}
return results;
}
In case it's of interest, CY Aries pointed this out:
ab + a + b = n(n + 1)/2
add 1 to both sides
ab + a + b + 1 = (n^2 + n + 2) / 2
(a + 1)(b + 1) = (n^2 + n + 2) / 2
so we're looking for factors of (n^2 + n + 2) / 2 and have some indication about the least size of the factor. This doesn't necessarily imply a great improvement in complexity for the actual search but still it's kind of cool.
This is part comment, part answer.
In engineering terms, the original function posted is using "brute force" to solve the problem, iterating every (or more than needed) possible combinations. The number of iterations is n is large - if you did all possible it would be
n * (n-1) = bazillio n
Less is More
So lets look at things that can be optimized, first some minor things, I'm a little confused about the first for loop and nArray:
// OP's code
for(let i = 1; i <= n; i++) {
nArray.push(n - (n - i));
sum += i;
}
??? You don't really use nArray for anything? Length is just n .. am I so sleep deprived I'm missing something? And while you can sum a consecutive sequence of integers 1-n by using a for loop, there is a direct and easy way that avoids a loop:
sum = ( n + 1 ) * n * 0.5 ;
THE LOOPS
// OP's loops, not optimized
for(let i = Math.round(n/2); i < length; i++) {
for(let y = Math.round(n/2); y < length; y++) {
if(i != y) {
if(i*y === sum - i - y) {
Optimization Considerations:
I see you're on the right track in a way, cutting the starting i, y values in half since the factors . But you're iterating both of them in the same direction : UP. And also, the lower numbers look like they can go a little below half of n (perhaps not because the sequence start at 1, I haven't confirmed that, but it seems the case).
Plus we want to avoid division every time we start an instantiation of the loop (i.e set the variable once, and also we're going to change it). And finally, with the IF statements, i and y will never be equal to each other the way we're going to create the loops, so that's a conditional that can vanish.
But the more important thing is the direction of transversing the loops. The smaller factor low is probably going to be close to the lowest loop value (about half of n) and the larger factor hi is probably going to be near the value of n. If we has some solid math theory that said something like "hi will never be less than 0.75n" then we could make a couple mods to take advantage of that knowledge.
The way the loops are show below, they break and iterate before the hi and low loops meet.
Moreover, it doesn't matter which loop picks the lower or higher number, so we can use this to shorten the inner loop as number pairs are tested, making the loop smaller each time. We don't want to waste time checking the same pair of numbers more than once! The lower factor's loop will start a little below half of n and go up, and the higher factor's loop will start at n and go down.
// Code Fragment, more optimized:
let nHi = n;
let low = Math.trunc( n * 0.49 );
let sum = ( n + 1 ) * n * 0.5 ;
// While Loop for the outside (incrementing) loop
while( low < nHi ) {
// FOR loop for the inside decrementing loop
for(let hi = nHi; hi > low; hi--) {
// If we're higher than the sum, we exit, decrement.
if( hi * low + hi + low > sum ) {
continue;
}
// If we're equal, then we're DONE and we write to array.
else if( hi * low + hi + low === sum) {
answersArray.push([hi, low]);
low = nHi; // Note this is if we want to end once finding one pair
break; // If you want to find ALL pairs for large numbers then replace these low = nHi; with low++;
}
// And if not, we increment the low counter and restart the hi loop from the top.
else {
low++;
break;
}
} // close for
} // close while
Tutorial:
So we set the few variables. Note that low is set slightly less than half of n, as larger numbers look like they could be a few points less. Also, we don't round, we truncate, which is essentially "always rounding down", and is slightly better for performance, (though it dosenit matter in this instance with just the single assignment).
The while loop starts at the lowest value and increments, potentially all the way up to n-1. The hi FOR loop starts at n (copied to nHi), and then decrements until the factor are found OR it intercepts at low + 1.
The conditionals:
First IF: If we're higher than the sum, we exit, decrement, and continue at a lower value for the hi factor.
ELSE IF: If we are EQUAL, then we're done, and break for lunch. We set low = nHi so that when we break out of the FOR loop, we will also exit the WHILE loop.
ELSE: If we get here it's because we're less than the sum, so we need to increment the while loop and reset the hi FOR loop to start again from n (nHi).

Javascript Easing not working correctly - EaseInCirc?

using Javascript in Photoshop Scripting, I wish to change the Opacity of X layers from Opacity 0 to Opacity 100, but in a gradual/slow to lastly hastened manner e.g. 'EaseInCirc' I believe.
The code I am using (not successfully) is: https://jsfiddle.net/09onhmy7/
numberOfLayers = 20;
myOpacity = 0;
x=0;
for(i = 0 ; i < numberOfLayers ; i++){
myIncrements = EaseExpo(i, 1, x, numberOfLayers);
x = myIncrements + myIncrements;
myOpacity = myOpacity + parseInt(myIncrements,10);
if (myOpacity > 100) {myOpacity = 100 ;}
document.write(myOpacity+",");
}
I found the EaseExpo(EaseInCirc) code on-line (http://gizma.com/easing/):
// t = current time
// b = start value
// c = change in value
// d = duration
// (t and d) can be frames
function EaseExpo(t, b, c, d) {
//EaseInCirc
return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
}
…but so far the code returns values that don't distribute as expected from 0 - 100 -- and most likely never will, as I don't know how to go about transposing them to suit the 0-100 bounds.
Basically, I'm trying to create an iteration of values (that aren't lineal) from 0 - X to represent a rate of change that slowly ramps up to maximum velocity (I'm pretty sure it’s a squareroot graph/function?) that I'm trying to replicate.
The values that will be input will always start at 0, but could have a maximum of any value.
The trick is, I need to be able to always transpose the end values into a 0-100 result.
e.g. A) 40 values = 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,30,32,34,36,39,42,46,51,58,68,83,100
e.g. B) 18 values = 1,3,5,7,9,11,13,15,17,20,23,27,32,39,49,64,88,100
I cant for the life of me work out how to do it -- or should I be using different math to achieve what I want?
Many thanks in advance, Livy

setInterval dosn't work as expected

function startAutoScrolling() {
var distance = y2 - y1;
var speed = distance / dateDiff;
interval1 = setInterval(function() { doAutoScrolling(speed); }, 1);
}
here I want to decrease step on 0.1
but it dosn't work like that, and I don't know why
function doAutoScrolling(step) {
document.getElementById(CONTEINER).scrollTop += step;
if (isGoingDown) {
step = step - 0.1;
console.log("step - 1: " + step);
if (step <= 0) {
clearInterval(interval1);
}
} else { // there is continue below
here I want to increase step and if condition have to stop execution of block
but it doesn`t work also
step += 0.01;
if (step >= 0) {
clearInterval(interval1);
}
}
}
You're using the Javascript comma-operator in place where you most probably want to use a decimal, e.g.:
step = step - 0,1;
Should be:
step = step - 0.1;
More about the comma-operator:
What does a comma do in JavaScript expressions?
When is the comma operator useful?
UPDATE (after commas to dots -change)
Primitives are passed-by-value in Javascript (see: Does Javascript pass by reference?) so you're basically calling doAutoScrolling over and over again with the same value (the value of speed). You need to do one of the following:
wrap speed in an object in order to pass-by-reference
make speed a global variable or at least defined in the parent context of doAutoScrolling
Replace setInterval with setTimeout and set a new timeout in doAutoScrolling:
var newStep = /* calculate new step */
setTimeout("doAutoScrolling("+newStep+")",1);

Calculating cubic root for negative number

So, to be short,
3√(-8) = (-8)1/3
console.log(Math.pow(-8,1/3));
//Should be -2
But when I test it out, it outputs
NaN
Why? Is it a bug or it is expected to be like this in the first place? I am using JavaScript to draw graphs, but this messes up the graph.
You can use this snippet to calculate it. It also works for other powers, e.g. 1/4, 1/5, etc.
function nthroot(x, n) {
try {
var negate = n % 2 == 1 && x < 0;
if(negate)
x = -x;
var possible = Math.pow(x, 1 / n);
n = Math.pow(possible, n);
if(Math.abs(x - n) < 1 && (x > 0 == n > 0))
return negate ? -possible : possible;
} catch(e){}
}
nthroot(-8, 3);
Source: http://gotochriswest.com/blog/2011/05/06/cube-root-an-beyond/
A faster approach for just calculating the cubic root:
Math.cbrt = function(x) {
var sign = x === 0 ? 0 : x > 0 ? 1 : -1;
return sign * Math.pow(Math.abs(x), 1 / 3);
}
Math.cbrt(-8);
Update
To find an integer based cubic root, you can use the following function, inspired by this answer:
// positive-only cubic root approximation
function cbrt(n)
{
var a = n; // note: this is a non optimized assumption
while (a * a * a > n) {
a = Math.floor((2 * a + (n / (a * a))) / 3);
}
return a;
}
It starts with an assumption that converges to the closest integer a for which a^3 <= n. This function can be adjusted in the same way to support a negative base.
There's no bug; you are raising a negative number to a fractional power; hence, the NaN.
The top hit on google for this is from Dr Math the explanation is pretty good. It says for for real numbers (not complex numbers anyway), a negative number raised to a fractional power may not be a real number. The simplest example is probably
-4 ^ (1/2)
which is essentially computing the square root of -4. Even though the cubic root of -8 does have real solutions, I think that most software libraries find it more efficient not to do all the complex arithmetic and return NaN only when the imaginary part is nonzero and give you the nice real answer otherwise.
EDIT
Just to make absolutely clear that NaN is the intended result, see the official ECMAScript 5.1 Specification, Section 15.8.2.13. It says:
If x<0 and x is finite and y is finite and y is not an integer, the result is NaN.
Again, even though SOME instances of raising negative numbers to fractional powers have exactly one real root, many languages just do the NaN thing for all cases of negative numbers to fractional roots.
Please do not think JavaScript is the only such language. C++ does the same thing:
If x is finite negative and y is finite but not an integer value, it causes a domain error.
Two key problems:
Mathematically, there are multiple cubic roots of a negative number: -2, but also 2 complex roots (see cube roots of unity).
Javascript's Math object (and most other standard math libraries) will not do fractional powers of negative numbers. It converts the fractional power to a float before the function receives it, so you are asking the function to compute a floating point power of a negative number, which may or may not have a real solution. So it does the pragmatic thing and refuses to attempt to calculate such a value.
If you want to get the correct answer, you'll need to decide how mathematically correct you want to be, and write those rules into a non-standard implementation of pow.
All library functions are limited to avoid excessive calculation times and unnecessary complexity.
I like the other answers, but how about overriding Math.pow so it would be able to work with all nth roots of negative numbers:
//keep the original method for proxying
Math.pow_ = Math.pow;
//redefine the method
Math.pow = function(_base, _exponent) {
if (_base < 0) {
if (Math.abs(_exponent) < 1) {
//we're calculating nth root of _base, where n === 1/_exponent
if (1 / _exponent % 2 === 0) {
//nth root of a negative number is imaginary when n is even, we could return
//a string like "123i" but this would completely mess up further computation
return NaN;
}/*else if (1 / _exponent % 2 !== 0)*/
//nth root of a negative number when n is odd
return -Math.pow_(Math.abs(_base), _exponent);
}
}/*else if (_base >=0)*/
//run the original method, nothing will go wrong
return Math.pow_(_base, _exponent);
};
Fiddled with some test cases, give me a shout if you spot a bug!
So I see a bunch of methods that revolve around Math.pow(...) which is cool, but based on the wording of the bounty I'm proposing a slightly different approach.
There are several computational approximations for solving roots, some taking quicker steps than others. Ultimately the stopping point comes down to the degree of precision desired(it's really up to you/the problem being solved).
I'm not going to explain the math in fine detail, but the following are implementations of cubed root approximations that passed the target test(bounty test - also added negative range, because of the question title). Each iteration in the loop (see the while(Math.abs(xi-xi0)>precision) loops in each method) gets a step closer to the desired precision. Once precision is achieved a format is applied to the number so it's as precise as the calculation derived from the iteration.
var precision = 0.0000000000001;
function test_cuberoot_fn(fn) {
var tested = 0,
failed = 0;
for (var i = -100; i < 100; i++) {
var root = fn(i*i*i);
if (i !== root) {
console.log(i, root);
failed++;
}
tested++;
}
if (failed) {
console.log("failed %d / %d", failed, tested);
}else{
console.log("Passed test");
}
}
test_cuberoot_fn(newtonMethod);
test_cuberoot_fn(halleysMethod);
Newton's approximation Implementation
function newtonMethod(cube){
if(cube == 0){//only John Skeet and Chuck Norris
return 0; //can divide by zero, we'll have
} //to settle for check and return
var xi = 1;
var xi0 = -1;
while(Math.abs(xi-xi0)>precision){//precision = 0.0000000000001
xi0=xi;
xi = (1/3)*((cube/(xi*xi))+2*xi);
}
return Number(xi.toPrecision(12));
}
Halley's approximation Implementation
note Halley's approximation takes quicker steps to solving the cube, so it's computationally faster than newton's approximation.
function halleysMethod(cube){
if(cube == 0){//only John Skeet and Chuck Norris
return 0; //can divide by zero, we'll have
} //to settle for check and return
var xi = 1;
var xi0 = -1;
while(Math.abs(xi-xi0)>precision){//precision = 0.0000000000001
xi0=xi;
xi = xi*((xi*xi*xi + 2*cube)/(2*xi*xi*xi+cube));
}
return Number(xi.toPrecision(12));
}
It's Working in Chrome Console
function cubeRoot(number) {
var num = number;
var temp = 1;
var inverse = 1 / 3;
if (num < 0) {
num = -num;
temp = -1;
}
var res = Math.pow(num, inverse);
var acc = res - Math.floor(res);
if (acc <= 0.00001)
res = Math.floor(res);
else if (acc >= 0.99999)
res = Math.ceil(res);
return (temp * res);
}
cubeRoot(-64) // -4
cubeRoot(64) // 4
As a heads up, in ES6 there is now a Math.cbrt function.
In my testing in Google chrome it appears to work almost twice as fast as Math.pow. Interestingly I had to add up the results otherwise chrome did a better job of optimizing away the pow function.
//do a performance test on the cube root function from es6
var start=0, end=0, k=0;
start = performance.now();
k=0;
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.cbrt(i);
//k+=j;
}
end = performance.now();
console.log("cbrt took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.pow(i,0.33333333);
//k+=j;
}
end = performance.now();
console.log("pow took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.cbrt(i);
k+=j;
}
end = performance.now();
console.log("cbrt took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.pow(i,0.33333333);
k+=j;
}
end = performance.now();
console.log("pow took:" + (end-start),k);
Result:
cbrt took:468.28200000163633 0
pow took:77.21999999921536 0
cbrt took:546.8039999977918 1615825909.5248165
pow took:869.1149999940535 1615825826.7510242
//aren't cube roots of negative numbers the same as positive, except for the sign?
Math.cubeRoot= function(n, r){
var sign= (n<0)? -1: 1;
return sign*Math.pow(Math.abs(n), 1/3);
}
Math.cubeRoot(-8)
/* returned value: (Number)
-2
*/
Just want to highlight that in ES6 there is a native cubic root function. So you can just do this (check the support here)
Math.cbrt(-8) will return you -2
this works with negative number and negative exponent:
function nthRoot(x = 0, r = 1) {
if (x < 0) {
if (r % 2 === 1) return -nthRoot(-x, r)
if (r % 2 === -1) return -1 / nthRoot(-x, -r)
}
return x ** (1 / r)
}
examples:
nthRoot( 16, 2) 4
nthRoot( 16, -2) 0.25
nthRoot(-16, 2) NaN
nthRoot(-16, -2) NaN
nthRoot( 27, 3) 3
nthRoot( 27, -3) 0.3333333333333333
nthRoot(-27, 3) -3
nthRoot(-27, -3) -0.3333333333333333

Javascript animate math

I'm struggling to get my head around such simple Math, well at least it seems it should be simple.
I'm basically trying to mirror what jQuery's .animate does, but to no luck.
Here's a simplified version of what I have so far:
var args = {
speed: 1000, // 1 second.
left: 65 // distance.
}, rot, step;
// Terrible math.
rot = step = (((args.left / args.speed) * 10) - 0.10);
var t = setInterval(function() {
if(elem.style.left >= args.left) {
clearInterval(t);
return;
}
rot += step;
elem.style.left = rot;
}, 10);
Please excuse any illogical code (or math), I've been messing around for a good few hours and totally lost my sanity.
Edit:
Here's the way I would do it.
var start_time = Date.now();
// Get the starting time in milliseconds
var t = setInterval(function() {
var delta_time = Date.now() - start_time;
// Get time that has elapsed since starting
if (delta_time >= 1000) {
// if it's been a second
clearInterval(t);
// Stop the timer
elem.style.left = args.left + 'px';
// Set the element to exactly the value it should be (avoids having it set to a float value)
return;
}
elem.style.left = delta_time * args.left / args.speed + 'px';
// Move the element according to how much time has elapsed
}, 10);​
This method has a few advantages. For example, you can adjust the interval to make it more or less smooth, and it won't mess up the animation.
The reason why your solution was taking longer than one second is because of how you used setInterval. setInterval doesn't account for the time your code takes to run, so the total time is always increased by a bit. You can fix this by using delta timing (like in my example).
Try using useing sin and cos to calculate rotation Some what like this
newx = distance * Math.cos(direction) + x
newy = distance * Math.sin(direction) + y
Not sure , this will solve your problem I guess you want to to do a smooth rotation
Try making it as a function it will work , I am not seeing any problem in your math ,
like this
function move(elem) {
var left = 0
function frame() {
left++ // update parameters
elem.style.left = left // show frame
if (left == 100) // check finish condition
clearInterval(id)
}
var id = setInterval(frame, 10) // draw every 10ms
}
Well for one it should be
var args = { ... }
assuming you have the elem set up correctly, you're going to need a inline styling of the attribute you want to animate. Also, you're going to need to parse the style since it has the 'px' attached to it, but you can always add that after you do the math within the interval function.
I set up something here so you can mess around with the settings and whatnot.
edit:
http://jsfiddle.net/mb4JA/2/
edit2:
this should be one second
http://jsfiddle.net/mb4JA/4/
final answer ;) http://jsfiddle.net/mb4JA/10/
You should be able to put any speed in there, and have it animate for that amount of seconds.

Categories

Resources