I'm trying to write this code for an after effects expression that will move an object a calculated x distance over n number of frames. The movement over each frame is parabolic rather than linear, and so I'm using the nth root code to determine how much the object should move over each frame. I'm putting each of the nth roots into an array to access later when setting the positions for each move.
I'm still learning javascript mainly for AE, so please bear with me if there are things in here I don't fully understand. I think I understand, which is why I'm not sure I'm getting the undefined output for certain n values. Here's the code:
//get Nth root
function nthroot(x, n) {
ng = n % 2;
if ((ng == 1) || x < 0)
x = -x;
var r = Math.pow(x, 1 / n);
n = Math.pow(r, n);
if (Math.abs(x - n) < 1 && (x > 0 === n > 0))
return ng ? -r : r;
}
distance=1515; //will be determined by another portion of the AE expression
frames=6; //will be set by expression control in AE
const myArray = [];
let i = 1;
while (i <= 6) {
myArray.push(nthroot(distance,i++));
}
console.log(myArray);
document.getElementById("demo2").innerHTML = myArray
I put it into a fiddle here. What am I doing wrong? Thanks in advance for any help!
Your "nthroot" function doesn't return values consisistently: if you look at the end of your function you can find this part:
if (Math.abs(x - n) < 1 && (x > 0 === n > 0))
return ng ? -r : r;
if you notice, you are returning a value only if the condition in the if statement is fullfilled, otherwise you are not returning any value.
In JavaScript, a function that doesn't return any value returns "undefined" instead.
In other words, when
Math.abs(x - n) < 1 && (x > 0 === n > 0)
is true, you are returning either "r" or "-r", but when the condition is false you aren't returning any value, so the function returns "undefined".
You have to handle the false case.
Related
as x is constant so it is positive or negative.
because we are checking the value of x which is constant, so it doesn't matter if we put a negative sign before it.
so it will cause an infinity loop as x is still positive.
I'm going to rewrite your code for better readability.
const reversed = (x) => {
if (x < 0) {
return -1 * reversed(-x);
}
}
If we call reversed with x >= 0, then reversed returns undefined because of an implicit return in the JS function.
e.g. reversed(1) // --> undefined
If x < 0, then we return -1 * reversed(-x). x < 0 -> -x > 0.
We already know that reversed called with x >= 0 is undefined, so we get -1 * undefined which results in NaN (Not a Number).
TLDR:
x >= 0 -> reversed(x) -> undefined
x < 0 -> reversed(x) -> NaN
I am trying to wrap my head around recursive functions. I've tried a number of entry level exercises with no success. For example, I put this code into JS fiddle. I intended for it to take the sum of all numbers from 1 to n.
function sumAll(n) {
if (n == 1 ) {
return 1;
} else if (n > 1) {
return sumAll(n--) + n;
}
}
console.log(sumAll(3));
feeding 3 to the function should give me '6'. I get an error, though.
The -- suffix operator will evaluate to the original value of n, and the subtraction from n will happen afterwards (which is also not desired as you still want to do + n). That means the recursive call gets the same value for n as the caller, and so you don't get closer to the end...
Don't use -- here, but -1:
function sumAll(n) {
if (n == 1 ) {
return 1;
}
else if (n > 1) {
return sumAll(n-1) + n;
}
}
console.log(sumAll(3));
Perhaps you will enjoy a repeatable technique that can guide you through designing your recursive function. Let's solve sumAll using inductive reasoning -
If n is zero, return the empty sum, zero
(inductive) n is negative or positive. If n is negative, return the negative result of the subproblem sumAll(-n)
(inductive) n is positive. Return n plus the result of the subproblem sumAll(n - 1)
function sumAll(n) {
if (n == 0) // 1
return 0
else if (n < 0) // 2
return -sumAll(-n)
else
return n + sumAll(n - 1) // 3
}
console.log(sumAll(-10), sumAll(0), sumAll(10))
// -55 0 55
Here is sumAll written using a switch instead. It behaves identically but maybe you will find the syntax nicer to read -
function sumAll(n) {
switch (true) {
case n == 0: return 0 // 1
case n < 0: return -1 * sumAll(-n) // 2
default: return n + sumAll(n - 1) // 3
}
}
console.log(sumAll(-10), sumAll(0), sumAll(10))
// -55 0 55
Here is sumAll again as a pure, functional expression -
const sumAll = (n = 0) =>
n == 0 // 1
? 0
: n < 0 // 2
? -1 * sumAll(-n)
: n + sumAll(n - 1) // 3
console.log(sumAll(-10), sumAll(0), sumAll(10))
// -55 0 55
I was writing an algorithm to compare how many bits are different between 2 numbers using this function
var hammingDistance = function(x, y) {
let result = 0;
while (x !== 0 || y !== 0) {
// This line is incorrect
if (x & 1 !== y & 1) result++;
x = x >> 1;
y = y >> 1;
}
return result;
};
But my result is always 1 less than the correct answer, and it turns our my function is wrong when comparing the left most digit, such as 0011 and 0100. It returns 2 instead of 3.
https://i.imgur.com/P46RyZr.png
I can use XOR instead of !== to get the correct answer. But I'm wondering why?
Your problem is that !== has a higher precedence than &. So your condition is actually (x & (1 !== y)) & 1. Use explicit grouping instead:
if ((x & 1) !== (y & 1)) result++;
It works with ^ because that has a lower precedence than &.
I've written a version of Y that automatically caches old values in a closure using memoization.
var Y = function (f, cache) {
cache = cache || {};
return function (x) {
if (x in cache) return cache[x];
var result = f(function (n) {
return Y(f, cache)(n);
})(x);
return cache[x] = result;
};
};
Now, when almostFibonacci (defined below) is passed into the above function, it returns the value of a large Fibonacci number comfortably.
var almostFibonacci = function (f) {
return function (n) {
return n === '0' || n === '1' ? n : f(n - 1) + f(n - 2);
};
};
However, after a certain value (Number.MAX_SAFE_INTEGER), integers in JavaScript (owing to their IEEE-754 double precision format) are not accurate. So, considering the fact that the only mathematical operations in the Fibonacci function above are addition and subtraction and since operators cannot be overloaded in JavaScript, I wrote naïve implementations of the sum and difference functions (that both use strings to support big integers) which are as follows.
String.prototype.reverse = function () {
return this.split('').reverse().join('');
};
var difference = function (first, second) {
first = first.reverse();
second = second.reverse();
var firstDigit,
secondDigit,
differenceDigits = [],
differenceDigit,
carry = 0,
index = 0;
while (index < first.length || index < second.length || carry !== 0) {
firstDigit = index < first.length ? parseInt(first[index], 10) : 0;
secondDigit = index < second.length ? parseInt(second[index], 10) : 0;
differenceDigit = firstDigit - secondDigit - carry;
differenceDigits.push((differenceDigit + (differenceDigit < 0 ? 10 : 0)).toString());
carry = differenceDigit < 0 ? 1 : 0;
index++;
}
differenceDigits.reverse();
while (differenceDigits[0] === '0') differenceDigits.shift();
return differenceDigits.join('');
};
var sum = function (first, second) {
first = first.reverse();
second = second.reverse();
var firstDigit,
secondDigit,
sumDigits = [],
sumDigit,
carry = 0,
index = 0;
while (index < first.length || index < second.length || carry !== 0) {
firstDigit = index < first.length ? parseInt(first[index], 10) : 0;
secondDigit = index < second.length ? parseInt(second[index], 10) : 0;
sumDigit = firstDigit + secondDigit + carry;
sumDigits.push((sumDigit % 10).toString());
carry = sumDigit > 9 ? 1 : 0;
index++;
}
sumDigits.reverse();
while (sumDigits[0] === '0') sumDigits.shift();
return sumDigits.join('');
};
Now, by themselves, both these functions work perfectly.1
I have now updated the almostFibonacci function to as follows to use the sum function instead of + and the difference function instead of the - operator.
var almostFibonacci = function (f) {
return function (n) {
return n === '0' || n === '1' ? n : sum(f(difference(n, '1')), f(difference(n, '2')));
};
};
As you may have guessed, this does work. It crashes the fiddle in case of even a small number like 10.
Question: What could be wrong? All the functions here work perfectly individually. But in tandem, they seem to fail. Can anyone here help me debug this particularly complex scenario?
1Except an edge case for the difference function. It requires the first argument to be larger than the second.
Now, by themselves, both these functions work perfectly - Except an edge case for the difference function. It requires the first argument to be larger than the second.
And that's the problem. In your fibonacci algorithm you're at some point calculating difference("2", "2"), which needs to yield "0" to work. It does however return the empty string "", which is not tested against as your guard condition for the recursion. When in the next step computing difference("", "1"), the function will fall into an infinite loop.
Solutions:
Fix that edge case (you still won't need to cope with negative numbers)
Don't use strings for the ordinal number, but only for the fibonacci number itself. You hardly will try the compute the (253+1)th fibonacci number, will you? I would assume this to be a significant speed improvement as well.
var fibonacci = Y(function(fib) {
return function(n) {
if (n == 0) return "0";
if (n == 1) return "1";
return sum(fib(n-1), fib(n-2));
};
});
Here is how I solved the problem at hand.
Changes:
I removed the while (differenceDigits[0] === '0') differenceDigits.shift(); statement. Even though this outputs differences without truncated leading zeros, it outputs a '0' in case of an edge case like difference('2', '2').
I edited the return statement in the almostFibonacci function to return n == 0 || n == 1 ? n : sum(f(difference(n, '1')), f(difference(n, '2')));. Notice that I'm checking for 0 and not '0' with a non strict equality operator.1
1The reason I'm doing n == 0 as opposed to n === '0' is because in JavaScript, '00000' == 0 but '00000' !== '0' and in my new updated difference function, without truncated leading zeros, I can't guarantee the number of zeros for a zero output. Well, actually I can. There would be as many zeros as the length of n.
100th Fibonacci - JSFiddle
Below is a function that returns the prime factors of a given number in JavaScript.
I did not write the function but have been studying it to extend my programming knowledge.
My questions are about the while loop that is inside the following if statement.
if(num % x){
x = 3;
while((num % x) && ((x = x+2) < root));
}
Questions
What is the purpose of a while loop if there is no code after it?
What is happening when the while loop evaluates true?
What is happening when the while loop evaluates false?
Here is the function in it's entirety.
function getPrimeFactors(num){
num = Math.floor(num);
var root = 0;
var factors = [];
var doLoop = 1 < num;
var x = 0;
while(doLoop){
root = Math.sqrt(num);
x = 2;
if(num % x){
x = 3;
while((num % x) && ((x = x+2) < root));
}
if(x > root){
x = num;
}else{
x = x;
}
factors.push(x);
doLoop = (x != num);
num = num/x;
}
return factors;
}
Thanks for the help!!!
It is really doing something like this:
if(num % x){
x = 3;
while(num % x){
x = x + 2;
if(x < root)
continue;
else
break;
}
}
Except, two is added to x right in the conditional, so there is no need for a body. The loop will execute until x < root or num % x fails to be true. The body just doesn't have any instructions in it.
Its very similar to what happens when you execute a for loop
for(int i=0; i < n; i++)
;
See there are no instructions in the for-loop body, but the loop will still add one to i until i >= n.
Note the x = x+2 in the while statement. It adds 2 to the value of x repeatedly until the while clause evaluates true.
So a while loop without a body blocks execution until it's clause becomes true. This is only a good idea if you you are mutating a variable in the clause as part of the condition. Otherwise you may end up in an infinite loop.
This code says, in effect, that if x is not evenly divisible by 3, then add 2 to x and continue if the resulting value is less than root. The loop terminates as soon as one of these conditions is no longer true, but, meanwhile, x has been updated along the way.
Note that x = x + 2 evaluates to the assignment's left operand.
The while statement there does change the value of the x variable. It could be rewritten as something like the following:
if (num % x) {
x = 3;
if (num % x){
do {
x = x + 2;
} while (num % x && x < root);
}
}
There is actually one thing happening in the loop:
V
while((num % x) && ((x = x+2) < root));
x = x + 2 is an assignment, you can see it is not a == or === operator but a =.
(x = x + 2) < root means increment x by 2, and then compare it to root.
Using an assignment in the condition part of a while or if statement is generally not recommended, because it makes the code less readable.
The value of x is incremented (by 2) until it is equal to or greater than the value of root
There's an assignment in the while condition/loop. It's evaluated while the loop is running so the value of "x" gets updated every cycle until no longer < root ( besides/and: && num % x < root).
Very clever but I hope this is not an introduction text/book/post to programming.
It seems like your hang-up you're having is with the fact that there's no body in the while statement. Understand that a loop body is optional and that it it behaves in the same way as a loop that does have a body.
Basically the while loop will repeatedly check the condition over and over. Yes, this can result in an infinite loop if coded incorrectly. In this case, 'x' will be incremented by 2 until it reaches or exceeds the value of 'root'.
credit to #Teemu for "reaches or"