I am trying to learn python and I have tried to convert a code snippet in js to python. I have created a function in js to calculate GCD as follows:
// program to find the GCD of two integers
let gcd
function GCD() {
// take input
const number1 = prompt('Enter a first positive integer: ')
const number2 = prompt('Enter a second positive integer: ')
// looping from 1 to number1 and number2
for (let i = 1; i <= number1 && i <= number2; i++) {
if( number1 % i == 0 && number2 % i == 0) {
gcd = i
}
}
// display the gcd
document.write(`GCD of ${number1} and ${number2} is ${gcd}.`)
}
GCD()
If I supply the first integer as 9 and the second integer of 3, I get the GCD as 3.
I have tried to convert this to a python program as follows:
def gcd():
gcd = 0
num1 = int(input("Enter a first positive integer: "))
num2 = int(input("Enter a second positive integer: "))
for i in range(1, i<=num1 and i<=num2):
if num1 % i == 0 and num2 % i == 0:
gcd = i
print(f"GCD of: {num1} and: {num2} is {gcd}")
gcd()
But I don't know how to get the for loop in python quite right. If I change the for statement to:
def gcd():
gcd = 0
num1 = int(input("Enter a first positive integer: "))
num2 = int(input("Enter a second positive integer: "))
for i in range(1, num1 and num2):
if num1 % i == 0 and num2 % i == 0:
gcd = i
print(f"GCD of: {num1} and: {num2} is {gcd}")
gcd()
and I give the same input as before of 9 and 3, I get GCD of 1
You can't have an equivalent syntax as i <= number1 && i <= number2 as it is a boolean expression that works as stop condition which is checked at every iteration.
While a for loop in python code generates values with boudaries, to do the same, iterate until the lowest value:
for i in range(1, min(num1, num2) + 1):
if num1 % i == 0 and num2 % i == 0:
gcd = i
To use the condition of the JS code, you need a while loop:
i = 1
while i <= num1 and i <= num2:
if num1 % i == 0 and num2 % i == 0:
gcd = i
i += 1
this is a solution based on while loop
def gcd():
gcd=0
num1 = int(input("Enter a first positive integer: "))
num2 = int(input("Enter a second positive integer: "))
i = 1
while(i <= num1 and i <= num2):
if(num1 % i == 0 and num2 % i == 0):
gcd = i
i = i + 1
print("GCD : ", gcd)
gcd()
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed last month.
Improve this question
I'm studying recursive functions, and one I came across is the greatest common divisor. I was working through a very long and complicated piece of code that was going nowhere, and when I looked up the solution, I see it's super short:
function gcd(num1, num2) {
if (num2 === 0) {
return num1;
}
return gcd (num2, num1 % num2);
}
I'm struggling to wrap my brain around how this works in the recursive return function call. Num2 becomes the first parameter for some reason, and how does the second parameter work? Is num1 % num2 the new value of num1? How is num2 going to get to 0? I don't see how it's value changes.
I'm struggling to wrap my brain around how this works in the recursive return function call. Num2 becomes the first parameter for some reason, and how does the second parameter work? Is num1 % num2 the new value of num1? How is num2 going to get to 0? I don't see how it's value changes.
num2 becomes the first argument to a new function call. We're not changing the value of the num1 we have, but telling JS that in the next call, the first parameter will get the value from what's currently in num2. Similarly, we calculate the next value of the second parameter as num1 % num2. (To understand how the math works, you might read up on the Euclidean algorithm, but the basic point is that for positive integers a and b, gcd (a, b) is precisely the same as gcd (b, a % b).)
So now we have two new numbers to test, and we call gcd with these two numbers, and, crucially, when that function returns, we return its result as our own:
return gcd (num2, num1 % num2);
//^^^^^^
This process stops when num2 is zero. Then we can simply return num1.
We can add some logging to your function, using an additional parameter, depth to track the recursion depth, initializing it at first to 0. That could give us output like this:
in gcd (120, 42)
num2 <> 0
value of num1 for the next call is num2: 42
calculating value of num2 for next call: num1 % num2: 120 % 42 ==> 36
calling gcd (42, 36)
in gcd (42, 36)
num2 <> 0
value of num1 for the next call is num2: 36
calculating value of num2 for next call: num1 % num2: 42 % 36 ==> 6
calling gcd (36, 6)
in gcd (36, 6)
num2 <> 0
value of num1 for the next call is num2: 6
calculating value of num2 for next call: num1 % num2: 36 % 6 ==> 0
calling gcd (6, 0)
in gcd (6, 0)
num2 == 0
returning 6
returning 6
returning 6
returning 6
which you can see by expanding and running this snippet:
const log = (depth, s) => console .log (' ' .repeat (depth) + s)
function gcd (num1, num2, depth = 0) {
log (depth, `in gcd (${num1}, ${num2})`)
if (num2 === 0) {
log (depth, `num2 == 0`)
log (depth, `returning ${num1}`)
return num1
}
log (depth, `num2 <> 0`)
log (depth, `value of num1 for the next call is num2: ${num2}`)
log (depth, `calculating value of num2 for next call: num1 % num2: ${num1} % ${num2} ==> ${num1 % num2}`)
log (depth, `calling gcd (${num2}, ${num1 % num2})`)
const result = gcd (num2, num1 % num2, depth + 1)
log (depth, `returning ${result}`)
return result
}
console .log (gcd (120, 42))
.as-console-wrapper {max-height: 100% !important; top: 0}
It might be tricky to understand without going through examples with pen and paper. num1 % num2 becomes the new value of num1 for each recurring call of the function.
If you try it with gcd(14,4),
4 != 0, 14 % 4 = 2 then next call is gcd(4, 2).
2 != 0, 4 % 2 = 0 then next call is gcd(2, 0).
0 == 0 then greatest common divisor of 14 and 4 is 2. This value is returned all the way up the call stack.
Another example with gcd(5,3):
3 != 0, 5 % 3 = 1 then next call is gcd(3,1).
1 != 0, 3 % 1 = 0 then next call is gcd(1, 0).
0 == 0 then greatest common divisor of 5 and 3 is 1.
An exact equivalent but more clear (to me) code is:
function gcd(num1, num2) {
if (num2 === 0) return num1;
else return gcd (num2, num1 % num2);
}
Now do a few by hand:
console.log(gcd(15, 6));
num2 (6) is not 0 so return gcd(6, 15%6) or gcd(6,3)
num2 (3) is not 0 so return gcd(3, 6%3) or gcd(3,0)
num2 (0) is now 0 so return 3
console.log(gcd(6, 15));
num2 (15) is not 0 so return gcd(15, 6%15) or gcd(15,6)
num2 (6) is not 0 so return gcd(6, 15%6) or gcd(6,3)
num2 (3) is not 0 so return gcd(3, 6%3) or gcd(3,0)
num2 (0) is now 0 so return 3
Or, you can let the code tell you what's going on:
This is for factorial(n) but you could do the same for gcd():
The important point is that "k" is different for each call:
console.log("FINALLY, factorial(5) = ", factorial(5));
function FACTORIAL(num) { // this is without the BS
if (num == 1) return 1;
else return num * factorial(num-1);
}
function factorial(num) { // this shows all
console.log("getting factorial(" + num + ")");
if (num == 1) {
console.log("factorial of 1 is just 1");
return 1;
} else {
console.log("need to get factorial(" + (num-1) + ")");
let k = num * factorial(num - 1);
console.log("got factorial(" + num + ") = " + k);
return k;
}
}
I want to have a code that finds amicable numbers in a certain range, but it only outputs one amicable number instead of all amicable numbers in that range.
How can I solve it? I think it may be a scope error.
Amicable numbers are a pair of numbers that the sum of all the divisors of the first number equals the second number, and the sum of the divisors of the second number equals the first number.
Here is my code:
let sum1 = 1;
let sum2 = 1;
for (let num1 = 3; num1 < 1300; num1++) {
for (let num2 = 3; num2 < 1300; num2++) {
for (let div1 = 2; div1 < num1; div1++) {
if (num1 % div1 === 0) {
sum1 += div1
}
}
for (let div2 = 2; div2 < num2; div2++) {
if (num2 % div2 === 0) {
sum2 += div2
}
}
if (num1 === sum2 && sum1 === num2) {
console.log(num1 + " and " + num2 + " are amicable numbers!")
}
}
}
Your code is very inefficient, having to calculate the sum of the divisors on every iterartion - even though you have previously calculated the sum of divisors for this number.
I tend to find it easier to think about this sort of problem in multiple steps. Step 1, calculate the sum of divisors for any given number:
const sumDivisors = num => {
let res = 0;
for(let i=1;i<num;i++)
if( (num % i) == 0)
res += i
return res;
}
Step 2, gather the numbers in the desired range and all their sums of divisors
var divisors = new Array(1300).fill(0).map( (_,i) => i)
.reduce( (acc,num) => ({...acc, [num]: sumDivisors(num)}))
The above gives you an object with num as the key and sum (of divisors) as the value.
{
"1": 0,
"2": 1,
"3": 1,
"4": 3,
"5": 1,
"6": 6,
"7": 1,
"8": 7,
.. etc
}
Step3, look for any item in the list where
key less than value (this also covers key != value and stops you getting both ways in the result ie 220,284 & 284,220)
value matches another key
Put it all together you get the below code which gives the expected results
const sumDivisors = num => {
let res = 0;
for(let i=1;i<num;i++)
if( (num % i) == 0)
res += i
return res;
}
var divisors = new Array(1300).fill(0).map( (_,i) => i)
.reduce( (acc,num) => ({...acc, [num]: sumDivisors(num)}))
var amicable = Object.entries(divisors)
.filter( ([num,sum]) => num < sum && divisors[sum] == num);
for(let [num1,num2] of amicable)
console.log(num1 + " and " + num2 + " are amicable numbers!")
You may like to compare the performance difference here between your original code (fixed to work) and the code in this answer: https://jsbench.me/jekosj89v4/1 The improvement in speed is a factor of 1000
Your code is never resets the sums so it will never find a match.
I don't know how to make it very efficient because I don't know about complexity, but here is my algorithm:
First, export the sum of dividers to a function so we can use it for any given number.
Then, loop through the numbers up to 1300 for example and use the function to find the sum of dividers for each number. When you have the sum, this is the number you want to check backwards (if the sum dividers of that number is equal to the original number they are amicable pair), you don't have to check all the numbers because the sum of dividers will give you only one number.
If the sum of dividers is less than the number, we already checked it and found the pair. If the number is equal to the sum it is the same number, this is not a pair.
So this is my final code:
const getDividersSum = (num) => {
let sum = 0;
for (let i = 1; i <= num / 2; i++) {
if (num % i === 0) {
sum += i;
}
}
return sum;
}
for (let num = 3; num < 1300; num++) {
const amicableNum = getDividersSum(num);
if (amicableNum !== num && num < amicableNum) {
if (getDividersSum(amicableNum) === num) {
console.log('Amicable nums: ', num, amicableNum);
}
}
}
I believe you need to move the declarations of sum1 and sum2 inside the second for loop. Check out this fiddle. (Edit: reason is because the sums continue to grow rather than resetting each time.)
Note, I changed a bit of code to ensure that the numbers were distinct (see num1 !== num2 on line 18 of the fiddle) and to avoid repeated pairs (see num2 < num1 rather than num2 < 1300 on line 2 of the fiddle.)
I don't really see how this could be wrong code.
In few examples, there is no output at all or it's only "10" in this one.
var num2 = 10;
while (num2 >= 10 && num2 <= 40 && num2%2===0){
console.log(num2);
num2++;
}
or like this:
var num2 = 10;
while (num2 >= 10 && num2 <= 40){
if (num2%2===0){
console.log(num2);
num2++;
}}
Your first loop stops after the first iteration because 11 is not an even number, so num2%2===0 is false.
Your second loop never stops because it only increments num2 if it's even (from 10 to 11), but 11 is not even and so num2 never changes.
Fix:
var num2 = 10;
while (num2 >= 10 && num2 <= 40) {
if (num2%2===0) {
console.log(num2);
}
num2++;
}
I.e. always increment num2, but only print the even numbers.
Alternatively:
var num2 = 10;
while (num2 >= 10 && num2 <= 40) {
console.log(num2);
num2 += 2;
}
I.e. start at an even number and always increment by 2.
For a homework assignment, I need to return the remainder after dividing num1 by num2 WITHOUT using the built-in modulo (%) operator. I'm able to get most tests to pass with the following code, but I'm stuck on how to account for -/+ signs of the given numbers. I need to carry over whichever sign is on num1, and also return a positive number if the num2 is negative - it's blowing my mind how to do this... :) Any clarity would be greatly appreciated! I'm not exactly looking for the straight up answer here, more that I seem to be missing something obvious... Maybe I need a new approach?
function modulo(num1, num2) {
if (num1 === 0) {
return 0;
}
if (num2 === 0 || isNaN(num1) || isNaN(num2)) {
return NaN;
}
if (num1 < num2) {
return num1;
}
if (num1 > 0 && num2 > 0) {
var counter = num1;
while (counter >= Math.abs(num2)) {
counter = counter - num2;
}
return counter;
}
}
var output = modulo(25, 4);
console.log(output); // 1
If you think about the mathematical process to calculate modulus you might be able see how you can do this without having to resort to a bunch of case statements. Instead think of it this way, you're just calculating a remainder:
Given 2 numbers a and b, you can compute mod(a,b) by doing the following:
q = a / b; //finding quotient (integer part only)
p = q * b; //finding product
remainder = a - p; //finding modulus
Using this idea, you should be able to transfer it to JS. You said you're not looking for the straight up answer so that's all I'll say!
Edit: here is the code, like I said in the comments it's exactly the pseudocode I posted above:
function modulo(a,b){
q = parseInt(a / b); //finding quotient (integer part only)
p = q * b; //finding product
return a - p; //finding modulus
}
This will return the exact same values as using %
You might be overthinking this. You basically stated the solution in your question:
I need to carry over whichever sign is on num1, and also return a positive number if the num2 is negative
The second part isn't accurate, but I suspect you just misspoke. A positive number should be returned when num2 is negative unless num1 is negative.
At any rate, the important takeaway is that if num1 is negative the result will be negative, and otherwise the result will be positive. The sign of num2 is discarded.
Starting the code you've written (which others will be quick to point out isn't the simplest solution), the fix is to compute the remainder using both numbers' absolute values, and then apply num1's original sign to the result.
function modulo(num1, num2) {
var sign = num1 < 0 ? -1 : 1;
var dividend = Math.abs(num1);
var divisor = Math.abs(num2);
if (dividend === 0) {
return 0;
}
if (dividend === 0 || isNaN(dividend) || isNaN(divisor)) {
return NaN;
}
if (dividend < divisor) {
return sign * dividend;
}
var counter = dividend;
while (counter >= divisor) {
counter = counter - divisor;
}
return sign * counter;
}
console.log( 25 % 4, modulo( 25, 4));
console.log(-25 % 4, modulo(-25, 4));
console.log( 25 % -4, modulo( 25, -4));
console.log(-25 % -4, modulo(-25, -4));
.as-console-wrapper{min-height:100%;}
This is the basic formula:
dividend = divisor * quotient + remainder
From this equation you can calculate the remainder.
I've just began Javascript in college. One task is to define and call a function to find the maximum number from 3 numbers entered by the user. I know there is a max() function but we were told to do it manually using if and else if.
I'm going wrong somewhere as you can see. It's just telling me the max is 0 everytime.
function maxNum(num1, num2, num3){
var max = 0;
if(num1 > num2){
if(num1 > num3){
num1 = max;
}
else{
num3 = max;
}
}
else{
if(num2 > num3){
num2 = max;
}
}
return max;
}
for(i=0;i<3;i++){
parseInt(prompt("Enter a number"));
}
document.write(maxNum());
Or you can use ES6 syntax, to compute largest of three numbers in easier way,
const largest = a => F = b => G = c => ((a > b && a > c) ? a : (b > a && b > c) ? b : c)
console.time()
console.log(largest(53)(30907)(23333))
console.timeEnd()
One problem you have is that you do not save the number the user inputs. You prompt them, parse it as an int and then nothing. You have to pass the 3 numbers into maxNum()
Here is a working example that uses proper left hand assignment and saves the number. Also it is a good idea to use >= instead of > because the user can enter 2 of the same number
function maxNum(num1, num2, num3){
var max = 0;
if((num1 >= num2) && (num1 >= num3)){
max = num1;
}
else if((num2 >= num1) && (num2 >= num3)){
max = num2;
}
else{
max = num3;
}
return max;
}
var arr = [];
for(i=0;i<3;i++){
arr[i] = parseInt(prompt("Enter a number"));
}
document.write(maxNum.apply(this, arr));
easiest way:
function maxNum(num1, num2, num3){
var tmp = 0;
if(num1 < num2 && num3 < num2) {
tmp = num2;
} else if(num3 < num1){
tmp = num1;
} else {
tmp = num3;
}
return tmp;
}
var arr = [];
for(var i = 0; i < 3; i++) {
arr[i] = prompt("Enter a number");
}
console.log(maxNum.apply(this, arr));
First in javascript and most modern programming language assignment like a = b copies the value of b into the variable a. It is not equivalent to b = a (which copies the value of a into the variable b). It's common to write a = 1, but a syntax error in most languages to write 1 = a. Thus, you don't want to write num1 = max, but instead write max = num1.
Second, your logic is incorrect as it won't treat the case maxNum(1,2,3) correctly. (Work through the logic when num1 < num2 and num2 < num3. The following code would work:
function maxNum(num1, num2, num3){
var max = 0;
if(num1 > num2){
if(num1 > num3){
max = num1;
}
else{
max = num3;
}
}
else{
if(num2 > num3){
max = num2;
} else {
max = num3;
}
}
return max;
}
Granted, I would probably write something like
function max3num(num1, num2, num3) {
var max_so_far = num1;
if (num2 > max_so_far) {
max_so_far = num2;
}
if (num3 > max_so_far) {
max_so_far = num3;
}
return max_so_far;
}
as the logic is very clear and it will be easy to extend to a max function with a larger number of elements to compare if necessary. (Adding in a for loop could make it variadic fairly easily). It is straightforward to see the logic works, because we start with the first element being the maximum so far (max_so_far), then consider if the second element is larger -- if so we assign that as max_so_far, and keep continuing until we have compared all the elements to the max_so_far. After we have considered each element once, we then return the max_so_far which will now be the maximum of all of them.
No real need for a function here, just compare them as the come in!
var max = 0;
for(var i=0;i<3;i++){
var val = parseInt(prompt("Enter a number"));
max = max > val ? max : val;
}
alert(max);
The updated direct answer is this :
function maxNum(num1, num2, num3){
return [num1, num2, num3].sort(function (a, b) { return b - a })[0];
}
If written like this, it can easily be modified to take any amount of numbers by passing it an array of said numbers.
var numArray = [num1, num2, num3, num4, ...];
function maxNum(numArray){
return numArray.sort(function (a, b) { return b - a })[0];
}
The details :
Take an array :
[5,42,16]
Now sort it.
[5,42,16].sort()
But this wont work because javascript .sort requires a function to be passed in. This function tells it how to sort the array.
This will sort it highest to lowest, e.g. a is less then b.
function (a, b) { return b - a }
This will sort it lowest to highest, e.g. b is less then a.
function (a, b) { return a - b }
So we add it in :
[5,42,16].sort(function (a, b) { return b - a })
But this returns the sorted array, not the maximum number.
So we pick the first element in the array :
[5,42,16].sort(function (a, b) { return b - a })[0]
Lastly, you can pull out the sort function. This is mostly for demo purposes though.
var maxSorter = function (a, b) { return b - a };
function maxNum(numArray){
return numArray.sort(maxSorter)[0];
}
//Raihan
// program to find the largest among three numbers
// take input from the user using Prompt
let num1 = parseFloat(prompt("Enter first number: "));
let num2 = parseFloat(prompt("Enter second number: "));
let num3 = parseFloat(prompt("Enter third number: "));
let largest = Math.max(num1, num2, num3);
// display the result
document.write("The largest number is " + largest);
**//another way**
const num1 = parseFloat(prompt("Enter first number: "));
const num2 = parseFloat(prompt("Enter second number: "));
const num3 = parseFloat(prompt("Enter third number: "));
// check the condition
if(num1 >= num2 && num1 >= num3) {
document.write("Largest Number : " + num1)
}
else if (num2 >= num1 && num2 >= num3) {
document.write("Largest Number : " + num2)
}
else {
document.write("Largest Number : " + num3)
}