Euler Project 2 in Javascript - javascript

I am going through the Odin Project and part of that is doing questions 1-3 in the Euler project. I am stumped on question 2:
"By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms."
I am so frustrated! What am I doing wrong? Here's what I have so far. Thanks!
function f() {
var fib = [];
fib.push(1,2,3);
var i = fib.length;
var total = 0;
while(fib[i] < 4000000) {
var x = fib[i-2] + fib [i-1];
if(x % 2 == 0) {
total += x;
}
} return total;
}
console.log(f());

The fibonacci sequences starts 1, 1, 2, not 1, 2, 3.
Also, your solution looks like it will work, but you are storing every number in the sequence instead of just the last two, so this will gobble memory comparatively.

As #DLeh notes, the fibonacci sequence starts with 1,1,2 - not 1,2,3. However, that doesn't change the result of summing the even valued items. The problem you're having is that at this point:
while(fib[i] < 4000000) {
fib[i] is undefined, so the function immediately exits with the total staying at 0. Also within the while loop, you're not pushing the next item in the sequence into your array. The below code fixes both of these problems:
function f() {
var fib = [];
fib.push(1,1);
var i = fib.length;
var total = 0;
while(fib[i-1] < 4000000) {
var x = fib[i-2] + fib [i-1];
fib.push(x);
i = fib.length;
if(x % 2 == 0) {
total += x;
}
} return total;
}
console.log(f()); //4613732
#DLeh also pointed out that you're storing more numbers than needed, this solution works without using the array:
function f() {
var f1 = 1;
var f2 = 1;
var total = 0;
while (f2 < 4000000) {
var t = f1 + f2;
if (t % 2 == 0)
total += t;
f1 = f2;
f2 = t;
}
return total;
}
console.log(f()); //4613732

Just for grins, note that you can do this problem without any use of %, and just + operations. Every third value in the sequence is even. That is, 2 is followed by 3 (odd), and then 3 + 2 is 5 (odd), but that sum of two odd numbers gets us back to even (8) and the cycle repeats.
Thus:
function evenFibTotal(limit) {
var a = 1, b = 1, c = 2, total = 0;
while (c < limit) {
total += c;
a = b + c;
b = a + c;
c = a + b;
}
return total;
}
On each iteration, the second trailing value is set to the next value in the sequence (b + c), and that plus the current one is the first trailing value, and finally the next even Fibonacci number is the sum of those two.
(There's also the closed solution but it's no fun :)

Related

that returns the sum of all numbers between two chosen numbers

I'm totally stuck at one excersise question. Can someone help me out with this question?
Create a function sumRangeNumbers() that returns the sum of all numbers
between two chosen numbers. The function should take two arguments, one
representing the lowest boundary and one that represents the highest
boundary. For example, the arguments 10 and 20 should return the sum of
10+11+12+13...+20.
for (var i = 0; i < 82; i++) {
document.write(i + i + '+');
}
How do I write the loop that sums all the numbers with an function?
The answer of DCR already provides a nice implementation and is probably what you were looking for. However, with a little mathematical knowledge you can make the function a little easier.
We know that the sum of 1 to n is n(n+1)/2 by looking at this wikipedia page.
The sum of a to b, is simply the sum of 1 to b minus the sum of 1 to a - 1 (we also want to include a itself).
The sum between a and b is then b(b + 1)/2 - (a - 1)(a)/2 and therefore your function becomes:
const a = 10
const b = 20
function sumRangeNumbers(a, b) {
const high = Math.max(a, b);
const low = Math.min(a, b);
return high * (high + 1) / 2 - (low - 1) * (low) / 2;
}
console.log(sumRangeNumbers(a, b)); // 165
console.log(sumRangeNumbers(b, a)); // 165
console.log(sumRangeNumbers(5, 7)); // 18
function sumRangeNumber (num1, num2) {
let total = 0
for (let i = num1; i <= num2; i++) {
total += i
}
return total
}
You are on the right track with a for loop. What we did here was in place of declaring i as zero we passed the low value and in the comparison we pass the high value. This creates the range ie 10-20. From there each loop we add I too total which is declared outside fo the loop so as to not have it reset and we add to it.
As a previous comment mentioned, this is kinda doing your HW for you, so give the above function a shot and play around with it and change things to make sure you understand whats happening.
you need to first create a function and then you need to call it.
function sum(x,y){
var sum = 0;
for(let i = x;i<=y;i++){
sum = sum + i;
}
console.log(sum)
}
sum(1,10);
const sumRange = (num1, num2) => (
min = Math.min(num1, num2),
Array(Math.abs(num1 - num2) + 1)
.fill().map((_, i) => i + min)
.reduce((sum, el) => sum + el, 0)
);
console.log(sumRange(20, 10));
console.log(sumRange(10, 20));
function sumRangeNumbers(lower, upper) {
let total = 0;
for (let index=lower; index<=upper; index++) {
total = total + index;
}
return total;
}
document.write(sumRangeNumbers(10,20));
Simple:
function sumRangeNumbers(from, to) {
let result = 0;
for (let i = from; i <= to; i++) {
result += i;
}
return result;
}
If the numbers belong to range of natural numbers, then why do you need a loop. Just use the fact that sum from low to high=
((high-low+1) * (low + high)) / 2
Give this a shot:
function getSum(x,y) {
sum += x
console.log(sum, x)
if (x == y) { return sum }
else { return getSum(x+1,y) }
}
sum = 0
Here's a simple example using your current attempt. Keep in mind, you'll want to some error handling for cases where they give you an invalid high/low number.
IE:
if (lowNum >= highNum) { console.error('invalid range'); }
and maybe this too
if (typeof lowNum !== 'number' && typeof highNum !== 'number') { console.error('Invalid inputs'); }
function sumUp(lowNum, highNum) {
if (lowNum >= highNum) { throw new Error('Invalid Range'); }
// Initialize total at 0
let total = 0;
// Loop through numbers between lowNum and highNum.
// Do not include lowNum and highNum in the addition
for (let i = lowNum + 1; i < highNum; i++) {
// Increment the total with the 'in-between number (i)'
total += i;
}
// Return the result
return total;
}
// Test 1 (should be 44)
console.log(2 + 3 + 4 + 5 + 6 + 7 + 8 + 9, sumUp(1, 10));
// Test 2 (should be 315)
console.log(50 + 51 + 52 + 53 + 54 + 55, sumUp(49, 56));
// If you really want to do document.write
document.write(sumUp(49, 56));
// Test 3 (should fail)
console.log(sumUp(15, 3));

Counting every 5th for loop

I'm having a hard time with this problem here:
Write a function named sumEvery5th that accepts a non-negative integer n and returns the sum of the integers divisible by 5 from 1 to n, including n itself. Use a for loop.
This is what I have so far:
var sumEvery5th = function(n){
let sum = 0;
for(let i = 1; n % 5 == 0; i++){
sum+ i
};
return sum;
}
I feel like I'm really close. Thanks for the help in advance.
You can start your loop at 5, since 1, 2... are not divisible by 5. And instead of i++, you can directly go 5 by 5, until i is greater than n:
var sumEvery5th = function(n) {
let sum = 0;
for (let i = 5; i <= n; i += 5) {
sum += i;
};
return sum;
}
console.log(sumEvery5th(10)); // 5 + 10 = 15
console.log(sumEvery5th(18)); // 5 + 10 + 15 = 30
First I think you should understand how a for loop works.
var sumEvery5th = function(n){
let sum = 0;
for(let i = 1; n % 5 == 0; i++){
sum+ i
};
return sum;
}
What you are doing, step by step, is:
Declaring a variable i with value 1.
Dividing n by 5 and taking the remainder value and comparing it with 0. In case it's true, you are skipping the code block inside the for and moving towards the return sum; line.
(In case you haven't skipped the code block in step 2) Run the code block with the new i value.
(In case you haven't skipped the code block in step 2) Incrementing the i value.
Go back to step 2.
Usually your for condition will depend in the variable declared in step 1. What you want to do is run the for code block n times.
For that, you need to change your condition from n % 5 == 0 to i <= n. This will make sure to run the code block while your i is less or equal than n, starting with a value of 1.
Now, inside your code block you add your divisible by 5 logic, checking against i value.
for(let i = 1; i <= n; i++){
if (i%5 == 0) sum += i;
};
Now let's say I called sumEvery5th(5).
Declare a variable i with value 1.
Check if i (1) is less than or equal n (5).
Go inside the code block.
Check if i%5 is 0.
It's not.
Increment i, now i = 2.
Check if i (2) is less than or equal n (5).
...And so on, until i = 6, and in that case the code block is skipped and the program will continue its course.
Ps.: There are ways to improve the performance of this algorithm, but now that you understand your for loop a bit better I'll leave it to you :)
var sumEvery5th = function(n){
let sum = 0;
for(let i = 1; i <= n; i++){
if (i % 5 === 0) {
sum += i;
}
}
return sum;
}

while loop test case errors

The question as per the practice course is :
Write a JavaScript program to find the maximum integer n such that (1 + 2 + ... + n <= given integer ) is true. For eg. If a given integer is 10, value of maximum integer n is 4 so that 1+2+3+4 <= 10 is true. Your output code should be in the format console.log("Value of n is ", variableName)
My code is :
var num = prompt("Enter a number");
function test(x) {
var sum = 1,
n = 1,
a = 0;
while (sum <= x) {
sum += n;
n = n + 1;
a += 1;
}
return a;
}
var output = test(num);
console.log("Result is :", output);
I'm getting the correct outputs as per the test cases I've entered(10-4,15-5,16-6,17-6) but the website says there is something wrong with the program.
What am i doing wrong?
Better answer than looping: exploit maths. Starting with Triangular number formula:
1 + 2 + ... + n = n * (n + 1) / 2
Thus, for input x, you need to find n such that
n * (n + 1) / 2 <= x
To solve this, we need to clean up the inequality, then use the quadratic equation formula:
n^2 + n <= 2x
n^2 + n - 2x <= 0
n <= (-1 + sqrt(1 + 8x)) / 2
as the final solution. e.g. for
x = 10: n <= (-1 + sqrt(81)) / 2; n <= 4
x = 16: n <= (-1 + sqrt(128)) / 2; n <= 5.156854249492381
Round the upper limit down, and you have the largest allowed integer. Translated into JavaScript:
function test(x) {
return Math.floor((Math.sqrt(8 * x + 1) - 1) / 2);
}
var num = prompt("Enter a number");
console.log("Result is :", test(num));
Consider if the passed value is 11. Then, the maximum integer n should be 4, because 1+2+3+4 < 11 is true, while 1+2+3+4+5 < 11 is false. Your current code outputs 5 for an input of 11, though, which is incorrect; your while loop is sometimes overshooting sum.
You also need to initialize sum to start at 0, not at 1.
Subtract one from a before returning it:
function test(x) {
var sum = 0,
n = 1,
a = 0;
while (sum <= x) {
sum += n;
n = n + 1;
a += 1;
console.log(a, sum);
}
return a - 1;
}
console.log(test(10));
console.log(test(11));
var num = prompt("Enter a number");
var output = test(num);
console.log("Result is :", output);
The code below should work for you. Basically, what I did was that if the input is 10, and your sum is 9, it will still go into the while loop. Then it will add n again and now your number is greater than your input (which is 10), but you still return it. Here what I did is that at the end of the while loop, if your sum is greater than your input, subtract one from a. That way it will still execute, but it will fix the problem.
Also another error I noticed was that sum started at 1, and n started at 1. You wanted 1+2+3+...+n, however using your previous method, you got 1+1+2+3+...+n.
var num = prompt("Enter a number");
function test(x) {
var sum = 0,
n = 1,
tempSum = 1,
a = 0;
while (sum <= x) {
sum += n;
n++;
a++;
if (sum > x) {
a--;
}
}
return a;
}
var output = test(num);
console.log("Result is :", output);
Your order of operation is a little funky; all you have to do is add the incrementor. The while false case will make sure the sum only passes over the number once. So when you return, reduce the number by one:
var num = prompt("Enter a number");
var output = test(num);
console.log("Result is :", output);
function test(num){
let sum = 0
let inc = 0
while(sum<=num)
sum+=++inc
return --inc;
}
This is a reduced version of your code, basically we increment first the number to add (n) in each iteration, and then we add it to the variable holding the sum. When the loop conditions evaluates to false you need to decrement one to n to get your value:
var num = prompt("Enter a number");
function test(x)
{
var sum = 0, n = 0;
while (sum <= x)
{
sum += (++n);
}
return --n;
}
var output = test(num);
console.log("Result is :", output);
I think this will work for you:
var num = prompt("Enter a number");
function test(x) {
var sum = 1,
n = 0;
while ((sum+n) <= x) {
n = n + 1;
sum += n;
}
return n;
}
var output = test(num);
console.log("Result is :", output);
Try below function to find max Number
function maxNumber(a){
var i=1,sum=0,maxNumber=0;
while(sum<=a) {
sum=sum+i;
if(sum<=a)
{
maxNumber=i;
}
i+=1;
}
return maxNumber;
}
doubled checked condition sum<=a to preserve the previous loop value and if condition not satisfied that means current loop value is not useful so returned preserved value of previous loop
Output tested :
Below will help you get the job done.
var num = prompt("Enter a number");
function findMaxNumber(num){
var sum = 0;
var counter = 0;
while(sum < num){
if(sum + counter > num){
break; // Exit loop
}
sum = sum + counter;
counter++;
}
return --counter; // Loop will cause this to be 1 higher than the max int.
}
console.log('Result is: ' + findMaxNumber(num));

Sum of odd numbers until reached limit in Javascript

While I was solving a question saying "add odd numbers from 1 to 20", I coded this:
var i, sum=0;
for (i=2; i<=20; i*2){
sum=sum+i;
}
document.write(sum);
When I launched it through a browser, it did not work. However, when I fixed i*2 into i+=2, it worked.
What am I missing? Am I not able to use *(multiplier) in For Loops?
If you need to add odd numbers from 1 to 20, then you need i+=2 as the third parameter of the for and need to initialize the variable to 1 to get the correct result:
var sum = 0;
for (var i = 1; i <= 20; i += 2) {
sum += i;
}
When you have
i += 2
2 is added to i and the result is stored into i. When you tried
var i, sum=0;
for (i=2; i<=20; i*2){
sum=sum+i;
}
i*2 calculates the value which is twice as big as i, but it will not change the value of i, so this would "work" instead:
var i, sum=0;
for (i=2; i<=20; i*=2){
sum=sum+i;
}
where
i *= 2
not only calculates the value twice as big as i, but stores the result into i as well. However, even though this will run, the result will not be correct, since you are using the wrong formula.
Also, you can calculate the result without using a for:
1 + 2 + ... + n = n * (n + 1) / 2
Assuming that n is pair: and since we know that we are "missing" half the numbers and all the pair numbers are bigger exactly with 1 than the previous impair numbers, we can subtract half of the sequence
n * (n + 1) / 2 - n / 2 = (n * (n + 1) - n) / 2 = (n * (n + 1 - 1)) /
2 = n * n / 2
and now we have exactly the double value of what we need, so the final formula is:
sum = n * n / 4;
Let's make this a function
function getOddSumUpTo(limit) {
if (limit % 2) limit ++;
return limit * limit / 4;
}
and then:
var sum = getOddSumUpTo(20);
Note that we increment limit if it is odd.
The issue is that you're not updating the value of the i in the for loop.
I want add odd numbers from 1 to 20
Then you need to change the initial value of i to 1.
var i, sum = 0;
for (i = 1; i <= 20; i += 2){
sum += i;
}
document.write(sum);
Also, you can find the sum of odd numbers from 1 to 20 by using a formula.
n = 20;
console.log(n % 2 == 0 ? (n * n)/ 4 : ((n + 1) * (n + 1))/4);
You can you just have to do it simillary to what you've written about sum.
You used there i += 2 and not i + 2.
The same way just change i * 2 to i *= 2.
Here is an working example
var i, sum = 0;
for (i = 2; i <= 20; i *= 2) {
console.log(i);
sum += i;
}
document.write(sum);
But a couple of things here.
First of all you wrote
add odd numbers from 1 to 20
and in all your examples you use sum on even numbers.
Secondly, by multiplying you will not achieve your desired goal (as you can see in a snippet above in a console)
So to actually
add odd numbers from 1 to 20
you should do it like this:
var i, sum = 0;
for (i = 1; i <= 20; i += 2) {
console.log(i);
sum += i;
}
document.write(sum);
EDIT
If you want to add even numbers you still can't use multiplying.
Why? Simply because you said yourself that you want a sum of numbers.
So let's say that we start with 2.
If we multiply it by 2 it has the value 4 which is fine.
But now look what happens in the next iteration. Our variable i which has the value 4 is multiplied by 2 and now its new value is 8. So what about 6?
Next iteration multiply 8 by 2 and its new value is 16.
Do you see where this is going?
And when you use i += 2 instead of i *= 2?
So if we start with 2 and than we add 2 its new value is 4.
In next iteration we add 2 to 4 and we have 6.
And so on.
If you want to test it, here is an example with multiplying and adding.
Pay attention to console logs
var i;
console.log("Multiplying");
for (i = 2; i <= 20; i *= 2) {
console.log("i value is: " + i);
}
console.log("Adding");
for (i = 2; i <= 20; i += 2) {
console.log("i value is: " + i);
}
What you are looking is this :
let sum = 0;
for(var i = 2; i <= 20; i += 2){
sum += i;
}
document.write(sum)
Another take on this :
// set to n (what you want). Set to n + 1
var N = 21;
// The main driver code create an array from 0-(N-1) and removes all even nums
let a = Array.apply(null, {length: N}).map(Number.call, _ => +_).filter(_=>_%2)
// console.log the array
console.log(a)
You can use whatever expression in loop header, even this is a valid for loop statement for (;;) which simply runs forever (equivalent to while(true)).
Problem is that you are not updating the i counter in for (i=2; i<=20; i*2) so the i will stays the same throughout the execution of the loop.
If you change it to for (i=2; i<=20; i = i*2) or for (i=2; i<=20; i *=2) then it will work.
It is the same as if you did
let i = 1;
i * 2;
console.log(i);
i = i * 2;
console.log(i);
The first i * 2 doesn't update the i while the second one does.
You can also translate the for loop into while loop to see the error more clearly.
// wrong
let i = 1;
while(i <= 20) {
i * 2;
// do something
}
// right
let i = 1;
while(i <= 20) {
i = i * 2 // or i *= 2
// do something
}
Just a side note, if you wanted to perform sum on more types of sequences efficiently than you could use a generator based approach and write your sum function and describe each type of a sequence with a generator function.
function *generateOdd(start, end) {
for (let i = start; i <= end; i++) {
if (i % 2 === 1) { yield i; }
}
}
function *generateEven(start, end) {
for (let i = start; i <= end; i++) {
if (i % 2 === 0) { yield i; }
}
}
function sumNums(gen, start, end) {
const generator = gen(start, end);
let res = 0;
let item = generator.next();
while (!item.done) {
res += item.value;
item = generator.next();
}
return res;
}
console.log(sumNums(generateOdd, 0, 20));
console.log(sumNums(generateEven, 0, 20));
/* sum of the Odd number using loop */
function sumOfOddNumbers(n){
let sum= 0;
for(let i = 1; i <= n; i++) {
if(i % 2 !== 0){
sum = sum + i;
}
}
return sum;
}
// 567 = 1+3+5+7+9+11+13+15+17+19+21+23+25+27+29+31+33+35+37+39+41+43+45+47
let n = 47;
let sum = sumOfOddNumbers(47);
alert('sumOfOddNumbers(' + n + ') = ' + sum);

Summation\ Addition of two arrays (particular)

"A positive number of whatever length is represented as an array of numerical characters, ergo between '0's and '9's. We know that the most significant cypher is in position of index 0 of the array.
Example:
- Number is 10282
- Array will be number = [1,0,2,8,2]
This considered, create a function of 2 arrays representing two positive numbers that calculates the SUM\ADDITION\SUMMATION of both of them and set it in a third array, containing the sum of the first 2."
This is how the exercise is translated from my own language, italian.
This is my solution but it doesnt entirely work. I have tried with basic stuff like
A=[1,4] and B=[4,7]. The results should be C=[6,1] but it gives me [5,1] as it considers the line where I use the modular but not the one where I say that the -1 index position should take a ++.
Help <3
alert('Insert A length');
var k=asknum();
alert('Insert B length');
var h=asknum();
var A = new Array(k);
var B = new Array(h);
// asknum() is only defined in this particular environment we are
// using at the university. I guess the turnaround would be -prompt-
function readVet(vet){//inserts values in index positions
for(i=0;i<vet.length;i++)
vet[i]=asknum();
}
readVet(A);//fills array
readVet(B);//fills array
function sumArray(vet1,vet2){
var C = new Array();
for(i=vet1.length-1;i>(-1);i--){
for(n=vet2.length-1;n>(-1);n--){
C[i]=vet1[i]+vet2[i];
if(C[i]>9){
C[i]=C[i]%10;
C[i-1]=C[i-1]++;
}
}
}
return C;
}
print(sumArray(A,B));
I'm not sure what you're doing with a nested for loop here. You just need one. Also, to make said loop really simple, normalize the arrays first so that both are the length of the larger array + 1 element (in case of carry). Then correct the result on the way out of the function.
function normalizeArray(array, digits) {
var zeroCnt = digits - array.length,
zeroes = [];
while (zeroCnt--) {
zeroes.push(0);
}
return zeroes.concat(array);
}
function sumArrays(a1, a2) {
var maxResultLength = Math.max(a1.length, a2.length) + 1;
a1 = normalizeArray(a1, maxResultLength);
a2 = normalizeArray(a2, maxResultLength);
var result = normalizeArray([], maxResultLength);
var i = maxResultLength - 1, // working index
digit = 0, // working result digit
c = 0; // carry (0 or 1)
while (i >= 0) {
digit = a1[i] + a2[i] + c;
if (digit > 9) {
c = 1;
digit -= 10;
} else {
c = 0;
}
result[i--] = digit;
}
/* If there was no carry into the most significant digit, chop off the extra 0 */
/* If the caller gave us arrays with a bunch of leading zeroes, chop those off */
/* but don't be an idiot and slice for every digit like sqykly =D */
for (i = 0 ; i < result.length && result[i] === 0 ; i++) {
/* result = result.slice(1); don't do that, or anything */
}
return result.slice(i);
}
That gives the expected output.
I may be missing something because the other answers look much more complicated, but here's my attempt at providing an answer based on the question:
// Takes an array and generates the sum of the elements
function addArrayNumbers(arr) {
return arr.reduce(function (p, c) {
return String(p) + String(c);
});
}
// Sums two numbers and returns an array based on that sum
function addCombinedNumbers(a, b) {
return String(Number(a) + Number(b)).split('');
}
var arrone = [1, 4];
var arrtwo = [4, 7];
var one = addArrayNumbers(arrone);
var two = addArrayNumbers(arrtwo);
var c = addCombinedNumbers(one, two); // [6,1]
Fiddle
I followed a different approach that may very well be less efficient than yours, but i consider it to be much clearer. One important thing is that i reverse the arrays so the least significant bit is first. Comments are in the code.
function sum(a,b){
// ensure a is the largest of the two arrays
if (a.length < b.length)
return sum(b,a);
// flip the arrays so the least significant digit is first
a = a.reverse();
b = b.reverse();
// c will hold the result (reversed at first)
var c = [];
// add each number individually
var carry = a.reduce(function(carry,digitA,index){
// digitA is guaranteed to be a number, digit from b is not!
var sum = digitA + (b[index] || 0) + carry;
c.push(sum%10);
return Math.floor(sum/10); // this is carried to the next step of the addition
},0); // initial carry is 0
if (carry) c.push(1); // resolve if carry exists after all digits have been added
return c.reverse();
}
// Usage:
console.log(sum([1,0,8,3],[1,3,5])); // [1, 2, 1, 8]
console.log(sum([8,3],[7,9])); // [1, 6, 2]
PS: There are many problems with your code. For one, you cannot use two nested loops:
var a = [0,1];
var b = [2,3];
for (var i=0; i<a.length; i++) {
for (var j=0; j<b.length; j++) {
console.log(a[i] + ' ' + b[i]);
}
}
// will output: 0 2, 0 3, 1 2, 1 3
// you want something along the lines of: 0 2, 1 3
What you want is a single loop that iterates over both arrays simultaneously.
My attempt at an efficient solution:
function efficientSum(a,b){
var i = a.length, j = b.length;
if (i<j) return efficientSum(j,i);
var q = 0, c = [];
c.length = i;
while (i) {
c[--i] = a[i] + (b[--j] || 0) + q;
q = c[i] > 9 ? ((c[i]-=10),1) : 0; // comma operator, ugly!
}
if (q) c.unshift(1);
return c;
}

Categories