HTML, JS Logic not working - javascript

I am trying to create a js logic function to solve the variables in an equation like this: 2x+5x=16. The problem is that it is supposed to output x=3 y=2, but instead, it outputs x=-11 y=1.
function solver(){
//Get c1, c2, and the answer
var c1=parseInt(prompt("Enter the coefficient of x:", "Example: 2 if you have 2x"));
var c2=parseInt(prompt("Enter the coefficient of y:", "Example: 3 if you have 3y"));
var answer=parseInt(prompt("Enter the answer:", "Example: 2x=4 it would be 4"));
//set other variables
var x;
var y;
var m;
//setup
x=answer/c1;
m=answer%c1;
//loop
while(true){
//if it is not an integer or it is 0
if (isInt(m/c2) === false || m/c2 == 0){
x=x-1;
m=answer%x;
}else if (isInt(m/c2)===true && m/c2 != 0){
x=x;
y=m/c2;
break;
}
}
alert("x="+x+" y="+y);
}
function isInt(n) {
return n % 1 === 0;
}
<h1>EXAMPLE: 2x+5y=16</h1>
<button onclick="solver()">Solve!</button>

Because if
nx+ky=a and x=a/n,
ky=a-(na)/n=0,
but if
x=f, y=(a-nf)/k.
You have infinitely many solutions for linear function with two unknowns.

Are you aware that there are infinite amounts of solutions?
and any given X and y that sastisfy x = 8 - 2.5y will be true?, in fact you can program the algorithm fixing y = 0, and you will get x = 8.
so you can either input two sets of xy solutions or you have infinite answers.
As a thumb rule, you need as much equations as vars
PD: I dont really get what are you doing inside the loop

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 setTimeout into two loops

I try since few days to create an javascript patern.
I parse an multidimentionnal array with "an for loop" that contain x and y positions as this :
array[1][x]
array[1][y]
array[2][x]
array[2][y]
ect...
i don't know the length the user push x and y numbers in an array and at the end an function is activated then length of the array is fixed. every seconds i want to increase or decrease x and y for one number at the end of the array.length i want to rebegin to parse the array, the parsing function stop when array[1][x] == stopX && array[1][y] == stopY.
i tested different approachs I have bug and infinite loops.
// i know stopX and stopY they are numbers and never change.
var stopX = 25;
var stopy = 49;
//i wish an condition to stop the script as this :
while( array[i][x] != stopX && array[i][y] != stopY ){
for( i = 1 ; i < array.length; i++ ){
(function(){
var j = i;
setTimeout( function(){
//here differents "if( ){" to increase or decrease array[i][x] and array[i][y];
array[i][x] += 1;
array[i][y] += 1;
}, j*1000);
}
}
}
Do i need "while number" as this "w*j*1000" i don't grasp this concept , i don't understand completely the utility of the closure i but that worked better, i think i need an second closure but where and how i can set up this?
In final i replacef "while loop" by setinterval+setTimeout+clearInterval.

Converting a base 10 number to other bases 2 without built in Javascript functions

I am new to coding and javascript and was asked, for an assignment, to convert base 10 numbers to a binary base without using specific Javascript built in methods (like alert(a.toString(16))), and I am only allowed to use loops,arrays and functions. This is what i have so far:
var number = prompt("Enter an unsigned base 10 number");
if (number>=0) {
var base = prompt("Enter b for binary, o for octal, or h for hexadecimal");
if (base=="h"||base=="H") {
;
}
So as you can see, I don't have much to go on. I was curious as to what equation or formula I would use to convert the base 10 number, as well as how i'm supposed to show A=10, B=11, C=12 and so forth for a hexadecimal base. Any help would be greatly appreciated!
edit: This is a rather complicated way to do it,
as Alnitak showed me (see discussion below).
It is more a scibble, or the long way by foot.
Short explanation:
If we want to get the binary of the decimal number 10,
we have to try 2^n so that 2^n is still smaller than 10.
For example 2^3 = 8 (that is OK). But 2^4 = 16 (thats too big).
So we have 2^3 and store a 1 for that in an array at index 3.
Now we have to get the rest of 10-2^3, which is 2, and have to
make the same calculation again until we get a difference of zero.
At last we have to reverse the array because its the other way arround.
var a = prompt("Enter an unsigned base 10 number");
var arr = [];
var i = 0;
function decToBin(x) {
y = Math.pow(2, i);
if (y < x) {
arr[i] = 0;
i++;
decToBin(x);
} else if (y > x) {
i--;
newX = (x - Math.pow(2, i));
arr[i] = 1;
i = 0;
decToBin(newX)
} else if (y == x) {
arr[i] = 1;
result = arr.reverse().join();
}
return result;
}
var b = decToBin(a); // var b holds the result
document.write(b);

Advice on how to code Luhn Credit Card validation with Javascript?

I'm pretty awful at Javascript as I've just started learning.
I'm doing a Luhn check for a 16-digit credit card.
It's driving me nuts and I'd just appreciate if someone looked over it and could give me some help.
<script>
var creditNum;
var valid = new Boolean(true);
creditNum = prompt("Enter your credit card number: ");
if((creditNum==null)||(creditNum=="")){
valid = false;
alert("Invalid Number!\nThere was no input.");
}else if(creditNum.length!=16){
valid = false;
alert("Invalid Number!\nThe number is the wrong length.");
}
//Luhn check
var c;
var digitOne;
var digitTwo;
var numSum;
for(i=0;i<16;i+2){
c = creditNum.slice(i,i+1);
if(c.length==2){
digitOne = c.slice(0,1);
digitTwo = c.slice(1,2);
numSum = numSum + (digitOne + digitTwo);
}else{
numSum = numSum + c;
}
}
if((numSum%10)!=0){
alert("Invalid Number!");
}else{
alert("Credit Card Accepted!");
}
</script>
The immediate problem in your code is your for loop. i+2 is not a proper third term. From the context, you're looking for i = i + 2, which you can write in shorthand as i += 2.
It seems your algorithm is "take the 16 digits, turn them into 8 pairs, add them together, and see if the sum is divisible by 10". If that's the case, you can massively simplify your loop - you never need to look at the tens' place, just the units' place.
Your loop could look like this and do the same thing:
for (i = 1; i < 16; i +=2) {
numSum += +creditNum[i];
}
Also, note that as long as you're dealing with a string, you don't need to slice anything at all - just use array notation to get each character.
I added a + in front of creditNum. One of the issues with javascript is that it will treat a string as a string, so if you have string "1" and string "3" and add them, you'll concatenate and get "13" instead of 4. The plus sign forces the string to be a number, so you'll get the right result.
The third term of the loop is the only blatant bug I see. I don't actually know the Luhn algorithm, so inferred the rest from the context of your code.
EDIT
Well, it would have helped if you had posted what the Luhn algorithm is. Chances are, if you can at least articulate it, you can help us help you code it.
Here's what you want.
// Luhn check
function luhnCheck(sixteenDigitString) {
var numSum = 0;
var value;
for (var i = 0; i < 16; ++i) {
if (i % 2 == 0) {
value = 2 * sixteenDigitString[i];
if (value >= 10) {
value = (Math.floor(value / 10) + value % 10);
}
} else {
value = +sixteenDigitString[i];
}
numSum += value;
}
return (numSum % 10 == 0);
}
alert(luhnCheck("4111111111111111"));
What this does is go through all the numbers, keeping the even indices as they are, but doubling the odd ones. If the doubling is more than nine, the values of the two digits are added together, as per the algorithm stated in wikipedia.
FIDDLE
Note: the number I tested with isn't my credit card number, but it's a well known number you can use that's known to pass a properly coded Luhn verification.
My below solution will work on AmEx also. I submitted it for a code test a while ago. Hope it helps :)
function validateCard(num){
var oddSum = 0;
var evenSum = 0;
var numToString = num.toString().split("");
for(var i = 0; i < numToString.length; i++){
if(i % 2 === 0){
if(numToString[i] * 2 >= 10){
evenSum += ((numToString[i] * 2) - 9 );
} else {
evenSum += numToString[i] * 2;
}
} else {
oddSum += parseInt(numToString[i]);
}
}
return (oddSum + evenSum) % 10 === 0;
}
console.log(validateCard(41111111111111111));
Enjoy - Mitch from https://spangle.com.au
#Spangle, when you're using even and odd here, you're already considering that index 0 is even? So you're doubling the digits at index 0, 2 and so on and not the second position, fourth and so on.. Is that intentional? It's returning inconsistent validations for some cards here compared with another algorithm I'm using. Try for example AmEx's 378282246310005.

reordering objects without impacting other objects

I have a list of items (think, files in a directory), where the order of these items is arbitrarily managed by a user. The user can insert an item between other items, delete items, and move them around.
What is the best way to store the ordering as a property of each item so that when a specific item is inserted or moved, the ordering property of the other items is not affected? These objects will be stored in a database.
An ideal implementation would be able to support inifinite number of insertions/reorders.
The test I'm using to identify the limitations of the approach are as follows:
With 3 items x,y,z, repeatedly take the item on the left and put it between the other two; then take the object on the right and put it between the other two; keep going until some constraint is violated.
For others' reference, I have included some algorithms I have tried.
1.1. Decimals, double-precision
Store the order as a decimal. To insert an between two items with orders x and y, calculate its order as x/2+y/2.
Limitations:
Precision, or performance. Using doubles, when the denominator becomes too big, we end up with x/2+y/2==x . In Javascript, it can only handle 25 shuffles.
function doubles(x,y,z) {
for (var i = 0; i < 10000000; i++) {
//x,y,z
//x->v1: y,v1,z
//z->v2: y,v2,v1
var v1 = y/2 + z/2
var v2 = y/2 + v1/2
x = y
y = v2
z = v1
if (x == y) {
console.log(i)
break
}
}
}
>doubles(1, 1.5, 2)
>25
1.2. Decimals, BigDecimal
The same as above, but using BigDecimal from https://github.com/iriscouch/bigdecimal.js. In my test, the performance degraded unusably quickly. It might be a good choice for other frameworks, but not for client-side javascript.
I threw that implementation away and don't have it anymore.
2.1. Fractions
Store the order as a (numerator, denominator) integer tuple. To insert an item between items xN/xD and yN/yD, give it a value of (xN+yN)/(xD+yD) (which can easily be shown to be between the other two numbers).
Limitations:
precision or overflow.
function fractions(xN, xD, yN, yD, zN, zD){
for (var i = 0; i < 10000000; i++) {
//x,y,z
//x->v1: y,v1,z
//z->v2: y,v2,v1
var v1N = yN + zN, v1D = yD + zD
var v2N = yN + v1N, v2D = yD + v1D
xN = yN, xD=yD
yN = v2N, yD=v2D
zN = v1N, zd=v1D
if (!isFinite(xN) || !isFinite(xD)) { // overflow
console.log(i)
break
}
if (xN/xD == yN/yD) { //precision
console.log(i)
break
}
}
}
>fractions(1,1,3,2,2,1)
>737
2.2. Fractions with GCD reduction
The same as above, but reduce fractions using a Greatest Common Denomenator algorithm:
function gcd(x, y) {
if(!isFinite(x) || !isFinite(y)) {
return NaN
}
while (y != 0) {
var z = x % y;
x = y;
y = z;
}
return x;
}
function fractionsGCD(xN, xD, yN, yD, zN, zD) {
for (var i = 0; i < 10000000; i++) {
//x,y,z
//x->v1: y,v1,z
//z->v2: y,v2,v1
var v1N = yN + zN, v1D = yD + zD
var v2N = yN + v1N, v2D = yD + v1D
var v1gcd=gcd(v1N, v1D)
var v2gcd=gcd(v2N, v2D)
xN = yN, xD = yD
yN = v2N/v2gcd, yD=v2D/v2gcd
zN = v1N/v1gcd, zd=v1D/v1gcd
if (!isFinite(xN) || !isFinite(xD)) { // overflow
console.log(i)
break
}
if (xN/xD == yN/yD) { //precision
console.log(i)
break
}
}
}
>fractionsGCD(1,1,3,2,2,1)
>6795
3. Alphabetic
Use alphabetic ordering. The idea is to start with an alphabet (say, ascii printable range of [32..126]), and grow the strings. So, ('O' being the middle of our range), to insert between "a" and "c", use "b", to insert between "a" and "b", use "aO", and so forth.
Limitations:
The strings would get so long as to not fit in a database.
function middle(low, high) {
for(var i = 0; i < high.length; i++) {
if (i == low.length) {
//aa vs aaf
lowcode=32
hicode = high.charCodeAt(i)
return low + String.fromCharCode( (hicode - lowcode) / 2)
}
lowcode = low.charCodeAt(i)
hicode = high.charCodeAt(i)
if(lowcode==hicode) {
continue
}
else if(hicode - lowcode == 1) {
// aa vs ab
return low + 'O';
} else {
// aa vs aq
return low.slice(0,i) + String.fromCharCode(lowcode + (hicode - lowcode) / 2)
}
}
}
function alpha(x,y,z, N) {
for (var i = 0; i < 10000; i++) {
//x,y,z
//x->v1: y,v1,z
//z->v2: y,v2,v1
var v1 = middle(y, z)
var v2 = middle(y, v1)
x = y
y = v2
z = v1
if(x.length > N) {
console.log(i)
break
}
}
}
>alpha('?', 'O', '_', 256)
1023
>alpha('?', 'O', '_', 512)
2047
Perhaps I have missed something fundamental and I will admit I know little enough about javascript, but surely you can just implement a doubly-linked list to deal with this? Then re-ordering a,b,c,d,e,f,g,h to insert X between d and e you just unlink d->e, link d->X and then link X->e and so on.
Because in any of the scenarios above, either you will run out of precision (and your infinite ordering is lost) or you'll end up with very long sort identifiers and no memory :)
Software axiom #1: KEEP IT SIMPLE until you have found a compelling, real and proven reason to make it more complicated.
So, I'd argue that it's extra and unnecessary code and maintenance to maintain your own order property when the DOM is already doing it for you. Why not just let the DOM maintain the order and you can dynamically generate a set of brain-dead simple sequence numbers for the current ordering any time you need it? CPUs are plenty fast to generate new sequence numbers for all items anytime you need it or anytime it changes. And, if you want to save this new ordering on the server, just send the whole sequence to the server.
Implementing one of these splitting sequences so you can always insert more objects without ever renumbering anything is going to be a lot of code and a lot of opportunities for bugs. You should not go there until it's been proven that you really need that level of complication.
Store the items in an array, and use splice() to insert and delete elements.
Or is this not acceptable because of the comment you made in response to the linked list answer?
The problem you are trying to solve is potentially insertion sort which has a simple implementation of O(n^2). But there are ways to improve it.
Suppose there is an order variable associated to each element. You can assign these orders smartly with large gaps between variables and get an amortized O(n*log(n)) mechanism. Look at (Insertion sort is nlogn)

Categories

Resources