Links: https://github.com/VirxEC/CalcPlus/blob/master/assets/Library.js and https://virxec.github.io/CalcPlus/PreviewLibrary/ these are just links to the main code if needed. The first link is the source, the second is the run environment.
The function expo has a very critical issue. I will explain what it does, then I will explain the exact issue and what I've tried to fix it. So the function is meant to calculate exponents up to 264-1 digits long. (For the answer.) It works by running the multiplication function multiple times (on lines 196-197: final = multi(num1, num1); for (var i="2"; isLessThan(i, num2); i=add({num:i.split(""),isNeg:false,decimals:0}, {num:["1"],isNeg:false,decimals:0})) final = multi(final, num1);)
The objects that you see are passed into the isLessThan() function are examples of me passing pre-parsed numbers to the function doesn't have to re-parse them and take up computer resources. This passing of a pre-parsed object is where the error is. On line 197, you can see final = multi(final, num1); The final variable is not pre-parsed for obvious reasons, but num1 is. However, if you go into the chrome debugger and watch the num1 variable, the multi() function changes the content of the property num1.num from (if you did 264) from ["2"] to ["0","2"] causing and incorrect answer.
I've tested force-removing this behavior is intended for the multi function, but it shouldn't be modifying the argument. I've tried naming the variable something else, using const, and trying to set the object to be read-only nothing has worked. I've even tried something like this:
num1save = num1;
final = multi(num1, num1);
for (var i="2"; isLessThan(i, num2); i=add({num:i.split(""),isNeg:false,decimals:0}, {num:["1"],isNeg:false,decimals:0})) {
final = multi(final, num1);
num1 = num1save;
}
However, somehow, the variable manages to change num1save. Any variable referenced at some point to the object is changed. I have no idea why this is happening. This same thing happens with the isLessThan() function and the variable num2 on line 197.
This includes only the required code, so the lines won't match up:
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// https://github.com/VirxEC/CalcPlus/blob/master/LICENSE
function parseNums(num1pre, num2pre, mode) {
if (["string", "object"].indexOf(typeof num1pre) == -1) throw new TypeError("The first number wasn't a string (or object). It has to be a string (or object). Note that an object input is ment to submit a pre-parsed number.");
if (["string", "object"].indexOf(typeof num2pre) == -1) throw new TypeError("The second number wasn't a string (or object). It has to be a string (or object). Note that an object input is ment to submit a pre-parsed number.");
if (typeof mode != "number" || [1, 2, 3, 4, 5].indexOf(mode) == -1) throw new TypeError("The mode must be a number from 1-5.");
var num1 = num1pre,
num2 = num2pre,
skip = false,
stringMode1 = true,
stringMode2 = true,
neg = [false, false, false],
decimal = 0,
decimal1 = 0,
decimal2 = 0,
num1pos, num2pos, maxChar, numl;
if (num1.num != undefined) neg[1] = num1pre.isNeg, decimal1 = num1pre.decimals, num1 = num1pre.num, stringMode1 = false;
if (num2.num != undefined) neg[2] = num2pre.isNeg, decimal2 = num2pre.decimals, num2 = num2pre.num, stringMode2 = false;
if (stringMode1 && num1.split("-").length == 2) num1 = num1.split("-")[1], neg[1] = true;
if (stringMode2 && num2.split("-").length == 2) num2 = num2.split("-")[1], neg[2] = true;
if (neg[1] != neg[2] && mode != 1 && mode != 2) neg[0] = true;
if (stringMode1) num1 = num1.split('').filter(w => w != ",");
if (stringMode2) num2 = num2.split('').filter(w => w != ",");
num1pos = num1.indexOf("."), decimal1 = num1pos != -1 ? num1.filter(w => w != ".").length - num1pos : 0, num2pos = num2.indexOf("."), decimal2 = num2pos != -1 ? num2.filter(w => w != ".").length - num2pos : 0, decimal = mode == 1 || mode == 2 ? Math.max(decimal1, decimal2) : mode == 3 ? decimal1 + decimal2 : decimal1 - decimal2, maxChar = Math.max(num1.length, num2.length);
for (var i = 0; !skip && num2.length == maxChar && i < num2.length && (((neg[1] || neg[2]) && mode == 1) || mode == 2); i++)
if (+num2[i] > +num1[i]) neg[0] = true, skip = true;
if (decimal < 0) decimal = 0;
if (maxChar == num2.length && mode == 3) num1 = [num2, num2 = num1][0]
if (decimal1 != decimal2 && [1, 2].indexOf(mode) > -1) {
if (decimal1 == decimal)
for (var i = 0; i < decimal1 - decimal2; i++) num2.push("0");
else if (decimal2 == decimal)
for (var i = 0; i < decimal2 - decimal1; i++) num1.push("0");
}
if (num1.length != num2.length && [1, 2].indexOf(mode) > -1) {
numl = [num1.length, num2.length];
if (maxChar == numl[0])
for (var i = 0; i < numl[0] - numl[1]; i++) num2.unshift("0");
else if (maxChar != num1[0])
for (var i = 0; i < numl[1] - numl[0]; i++) num1.unshift("0");
}
if (mode == 3 && neg.every(e => (e == true))) neg[0] = false;
return {
num1: {
num: num1,
isNeg: neg[1],
decimals: decimal1
},
num2: {
num: num2,
isNeg: neg[2],
decimals: decimal2
},
isNeg: neg[0],
maxChar: maxChar,
decimals: decimal
};
}
function formatNums(final, decimals, neg) {
if (typeof final == "string") {
if (decimals > 0) {
final = final.split("");
final.splice(final.length - decimals, 0, ".");
final = final.join("");
}
} else if (typeof final == "object") {
if (decimals > 0) {
final = final.reverse();
final.splice(final.length - decimals, 0, ".");
final = final.join("");
} else final = final.reverse().join("");
}
final = neg[0] ? "-" + final : final;
final = ["", ".", "-"].indexOf(final) > -1 ? "0" : final;
return final;
}
function add() {
function tempadd(num1, num2) {
var parsedNums = parseNums(num1, num2, 1),
neg = [parsedNums.isNeg, parsedNums.num1.isNeg, parsedNums.num2.isNeg],
maxChar = parsedNums.maxChar,
decimal = [parsedNums.decimals, parsedNums.num1.decimals, parsedNums.num2.decimals],
num1 = parsedNums.num1.num,
num2 = parsedNums.num2.num,
time, final = [],
carry = "0",
finali;
if (neg[2]) return sub(parsedNums.num1, {
num: num2,
isNeg: false,
decimals: decimal[1]
});
else if (neg[1]) return sub(parsedNums.num2, {
num: num1,
isNeg: false,
decimals: decimal[2]
});
for (var i = maxChar - 1; i >= 0; i--) {
finali = maxChar - i - 1;
if (time != i + 1) carry = "0";
final[finali] = String(+num1[i] + (+num2[i]) + (+carry));
if (+final[finali] > 9) {
var temp = final[finali].split('');
final[finali] = temp[1], carry = temp[0], time = i;
if (i - 1 < 0) final.push(carry);
}
}
return formatNums(final, decimal[0], neg);
}
var permfinal, a = arguments;
if (Array.isArray(a[0])) a = a[0];
permfinal = tempadd(a[0], a[1]);
for (var i = 2; i < a.length; i++) permfinal = tempadd(permfinal, a[i]);
return permfinal;
}
function sub() {
function tempsub(num1pre, num2pre) {
var parsedNums = parseNums(num1pre, num2pre, 2),
neg = [parsedNums.isNeg, parsedNums.num1.isNeg, parsedNums.num2.isNeg],
maxChar = parsedNums.maxChar,
decimal = [parsedNums.decimals, parsedNums.num1.decimals, parsedNums.num2.decimals],
num1 = parsedNums.num1.num,
num2 = parsedNums.num2.num,
final = [],
finali, fans;
if (neg[0] && !neg[1] && !neg[2]) num1 = [num2, num2 = num1][0];
else if (neg[1] && neg[2]) num1 = [num2, num2 = num1][0];
else if (neg[2] && !neg[1]) return add(parsedNums.num1, {
num: num2,
isNeg: false,
decimals: decimal[2]
});
else if (neg[1] && !neg[2]) return "-" + add({
num: num1,
isNeg: false,
decimals: decimal[1]
}, parsedNums.num2);
for (var i = maxChar - 1; i >= 0; i--) {
finali = maxChar - i - 1, fans = num1[i] - num2[i];
if (fans < 0 && i != 0) {
var j = i - 1;
final[finali] = String(fans + 10), num1[j] = String(num1[j] - 1);
while (num1[j] < 0 && j != 0) num1[j] = String((+num1[j]) + 10), j = j - 1, num1[j] = String(num1[j] - 1);
} else if (fans < 0 && i == 0) final[finali] = String(fans).split("-")[1];
else final[finali] = fans;
}
return formatNums(final, decimal[0], neg);
}
var permfinal, a = arguments;
if (Array.isArray(a[0])) a = a[0];
permfinal = tempsub(a[0], a[1]);
for (var i = 2; i < a.length; i++) permfinal = tempsub(permfinal, a[i]);
return permfinal;
}
function isLessThan() {
function templessthan(num1, num2) {
var num = sub(num2, num1);
if (num.split("-").length == 1 && num != 0) return true;
return false;
}
var permfinal, a = arguments;
if (Array.isArray(a[0])) a = a[0];
permfinal = templessthan(a[0], a[1]);
for (var i = 2; i < a.length; i++) permfinal = templessthan(permfinal, a[i]);
return permfinal;
}
function multi() {
function tempmulti(num1pre, num2pre) {
var parsedNums = parseNums(num1pre, num2pre, 3),
neg = [parsedNums.isNeg, parsedNums.num1.isNeg, parsedNums.num2.isNeg],
final = "",
decimals = parsedNums.decimals,
numArray = [],
num2 = parsedNums.num2,
num1 = parsedNums.num1;
if (num2.num.length == 1 && num2.num[0] == "1") return formatNums(num2.num, decimals, neg);
else if (num2.length == 1 && num2[0] == "0") return "1";
else {
final = add(num1, num1);
for (var i = "2"; isLessThan(i, num2); i = add({
num: i.split(""),
isNeg: false,
decimals: 0
}, {
num: ["1"],
isNeg: false,
decimals: 0
})) final = add(final, num1);
}
return formatNums(final, decimals, neg);
}
var permfinal, a = arguments;
if (Array.isArray(a[0])) a = a[0];
permfinal = tempmulti(a[0], a[1]);
for (var i = 2; i < a.length; i++) permfinal = tempmulti(permfinal, a[i]);
return permfinal;
}
function expo() {
function tempexpo(num1pre, num2pre) {
var parsedNums = parseNums(num1pre, num2pre, 5),
num1 = parsedNums.num1,
num2 = parsedNums.num2,
decimals = parsedNums.decimals,
decimal2 = parsedNums.num2.decimals,
neg = [parsedNums.isNeg, parsedNums.num1.isNeg, parsedNums.num2.isNeg],
numArray = [],
final = "";
if (neg[1]) num1.num.unshift("-");
if (neg[2]) num2.num.unshift("-");
if (decimal2 > 0) {
// root_of_decimal2*10(num1)**(num2*(10*decimal2))
alert("Decimal exponents aren't supported yet");
throw new TypeError("Decimal exponents aren't supported yet");
} else {
if (num2.num.length == 1 && num2.num[0] == "1") return formatNums(num2.num, decimals, false);
else if (num2.num.length == 1 && num2.num[0] == "0") return "1";
else {
final = multi(num1, num1);
for (var i = "2"; isLessThan(i, num2); i = add({
num: i.split(""),
isNeg: false,
decimals: 0
}, {
num: ["1"],
isNeg: false,
decimals: 0
})) {
final = multi(final, num1);
console.log(num1, num2, i);
}
return final;
}
//Need to fix div -> if (neg[2]) return div("1", final);
}
}
var permfinal, a = arguments;
if (Array.isArray(a[0])) a = a[0];
permfinal = tempexpo(a[0], a[1]);
for (var i = 2; i < a.length; i++) permfinal = tempexpo(permfinal, a[i]);
return permfinal;
}
console.log(expo("2", "64"));
Why is this happening? Is there a work-around?
If you saw the previous post, sorry. I've been very frustrated with this bug.
Doing the following:
var num1save = JSON.parse(JSON.stringify(num1));
var num2save = JSON.parse(JSON.stringify(num2));
sets a save variable that isn't just a reference but is instead a good copy and then doing this to set the save:
num1 = JSON.parse(JSON.stringify(num1save));
num2 = JSON.parse(JSON.stringify(num2save));
doesn't prevent the problem from happening, but prevents it from causing any issues. Appling this in a way other than in the for loop would prevent the issue from happening.
I'm looking to identify a category based on this table:
I have an if statement that seems to work for some conditions, but not others. R, P, and Q are working, but conditions that go between numbers aren't returning the right category.
If statement:
function getCategory(featureFunctionalScore, featureDysfunctionalScore) {
if (featureFunctionalScore == 4 && featureDysfunctionalScore == -2) {
return "Performance";
} else if (featureFunctionalScore == 4 && featureDysfunctionalScore <= -1 && featureDysfunctionalScore > 4) {
return "Attractive"
} else if (featureFunctionalScore <= -1 && featureFunctionalScore > 4 && featureDysfunctionalScore == 4) {
return "Expected"
} else if ((featureFunctionalScore >= -2 && featureFunctionalScore <= 2 && featureDysfunctionalScore == -2) || (featureFunctionalScore == -2 && featureDysfunctionalScore >= -2 && featureDysfunctionalScore <= 2)) {
return "Reverse"
} else if ((featureFunctionalScore == 4 && featureDysfunctionalScore == -2) || (featureFunctionalScore == 2 && featureDysfunctionalScore == -1) || (featureFunctionalScore == -1 && featureDysfunctionalScore == 2) || (featureFunctionalScore == -2 && featureDysfunctionalScore == 4)) {
return "Questionable"
} else {
return "Indifferent"
};
};
Am I missing something important?
Update
This statement works in Excel, but I'm struggling to get it to work in JS:
=IF(OR(AND(C3 <= 2, B3 <= -1), AND(C3 <= -1, B3 <= 2)), "R", IF(AND(C3 <= 2, C3 >= -1, B3 <= 2, B3 >= -1), "I", IF(AND(C3 >= 2,B3 >= -1, B3 <= 2),"A", IF(AND(C3 <= 2, B3 <= 4, B3 >= 2), "M", IF(AND(C3 >= 2, B3 >= 2), "P", "Q")))))
This should be what you're looking for. I'm sure it could be optimized, but it works. JSFiddle: https://jsfiddle.net/yxb7tr9n/
function getCategory(x,y){
var answer = -999;
if (x == 4 && y == 4){
answer = "p";
}else if([-1,0,2].indexOf(x) >= 0 && y == 4){
answer = "A";
}else if((x == -2 && y == 4) || (x == -1 && y == 2) || (x == 4, y == -2)){
answer = "Q";
}else if(x == 4 && [-1,0,2].indexOf(y) >= 0) {
answer = "M";
}else if((x == -1 && [-1,0].indexOf(y) >= 0) || (x == 0 && [-1,0,2].indexOf(y) >= 0) || (x == 2 && [0,2].indexOf(y) >= 0)){
answer = "I";
}else if ((x == -2 && [-2,-1,0,2].indexOf(y) >= 0) || (y == -2 && [-2,-1,0,2].indexOf(x) >= 0)) {
answer = "R";
}else{
answer = "??";
}
return answer;
}
UPDATE: Alternate version using a coordinate mapping system. JSFiddle: https://jsfiddle.net/g2d6p4rL/4/
function indexOfCustom (parentArray, searchElement) {
for ( var i = 0; i < parentArray.length; i++ ) {
if ( parentArray[i][0] == searchElement[0] && parentArray[i][1] == searchElement[1] ) {
return i;
}
}
return -1;
}
function getCategory2(x,y){
var p = [[4,4]];
var q = [[-2,4],[-1,2],[2,-1],[4,-2]];
var a = [[-1,4],[0,4],[2,4]];
var m = [[4,2],[4,0],[4,-1]];
var i = [[0,2],[2,2],[-1,0],[0,0],[2,0],[-1,-1],[0,-1]];
var r = [[-2,2],[-2,0],[-2,-1],[-2,-2],[-1,-2],[0,-2],[2,-2]];
coord = [x,y];
if (indexOfCustom(p,coord) >= 0){
return "p";
} else if (indexOfCustom(q,coord) >= 0){
return "Q";
} else if (indexOfCustom(a,coord) >= 0){
return "A";
} else if (indexOfCustom(m,coord) >= 0){
return "M";
} else if (indexOfCustom(i,coord) >= 0){
return "I";
} else if (indexOfCustom(r,coord) >= 0){
return "R";
}else{
return "??";
}
}
Output of all answers:
[-2,-2] = R
[-2,-1] = R
[-2,0] = R
[-2,2] = R
[-2,4] = Q
[-1,-2] = R
[-1,-1] = I
[-1,0] = I
[-1,2] = Q
[-1,4] = A
[0,-2] = R
[0,-1] = I
[0,0] = I
[0,2] = I
[0,4] = A
[2,-2] = R
[2,-1] = Q
[2,0] = I
[2,2] = I
[2,4] = A
[4,-2] = Q
[4,-1] = M
[4,0] = M
[4,2] = M
[4,4] = p
Is there a way that I can combine these two codes into one? I want to check if some variables are equal to 0 or equal to 1 or equal to 2 or greater than 2 and less than 5 or greater than 5. Should I write a code for each variable or I can write a code for all variables?
<script>
if (NRIRDL==0){
XRIRDL=0;
}
else if (NRIRDL == 1){
XRIRDL = 1;
}
else if (NRIRDL == 2){
XRIRDL = 1.8;
}
else if (NRIRDL > 2 && NRIRDL < 5){
XRIRDL = 0.9 * NRIRDL;
}
else {
XRIRDL = NRIRDL - 1;
}
// code below is the same as code above, but variables are different.
if (NRIRDR==0){
XRIRDR=0;
}
else if (NRIRDR == 1){
XRIRDR = 1;
}
else if (NRIRDR == 2){
XRIRDR = 1.8;
}
else if (NRIRDR > 2 && NRIRDR < 5){
XRIRDR = 0.9 * NRIRDR;
}
else {
XRIRDR = NRIRDR - 1;
}
</script>
actually, it can be written shorter with ternary operator and without multiple if conditions, check it out:
function getValue(n) {
return n >= 2 && n < 5 ? n * 0.9 : n == 0 ? 0 : n == 1 ? 1 : n - 1;
}
var var1 = 0;
var var2 = 1;
var var3 = 2;
var var4 = 3;
var var5 = 5;
console.log(getValue(var1)); // outputs 0
console.log(getValue(var2)); // outputs 1
console.log(getValue(var3)); // outputs 1.8
console.log(getValue(var4)); // outputs 2.7
console.log(getValue(var5)); // outputs 4
Just use getValue(n) function: pass your variable and it will return needed value that can be stored into another variable like var XRIRDL = getValue(NRIRDL); or var XRIRDR = getValue(NRIRDR);
You could make it into a function:
function yourFunction(val) {
if (val == 0){
return 0;
}
else if (val == 1){
return 1;
}
else if (val == 2){
return 1.8;
}
else if (val > 2 && val < 5){
return 0.9 * val;
}
else {
return val - 1;
}
XRIDR = yourFunction(NRIDR);
XRIDL = yourFunction(NRIDL);
When you OR the two inputs together, you lose valuable information about which one of the two inputs triggered that condition.
Mike's answer might not fit your needs because you can't update the values independently of one another (i.e. if NRIDR == 0 and NRIDL == 2, it sounds like you don't want both XRIDR and XRIDL to equal 1.8.)
You could put it inside a function. Here's a copy paste of your code inside a function.
function xrirdr(dr_or_dl){
var XRIRDL = null;
if (dr_or_dl==0){
XRIRDL=0;
}
else if (dr_or_dl == 1){
XRIRDL = 1;
}
else if (dr_or_dl == 2){
XRIRDL = 1.8;
}
else if (dr_or_dl > 2 && dr_or_dl < 5){
XRIRDL = 0.9 * dr_or_dl;
}
else {
XRIRDL = dr_or_dl - 1;
}
return XRIRDL;
}
You can pass NRIRDL or NRIRDR in the function and it will get you your XRIRDL
<script>
if (NRIRDL==0 || NRIRDR==0 ){
XRIRDL=0;
XRIRDR=0;
}
else if (NRIRDL == 1 || NRIRDR == 1)){
XRIRDL = 1;
XRIRDR = 1;
}
else if (NRIRDL == 2 || NRIRDR == 2)){
XRIRDL = 1.8;
XRIRDR = 1.8;
}
else if ((NRIRDL > 2 && NRIRDL < 5) || (NRIRDR > 2 && NRIRDR < 5) ){
XRIRDL = 0.9 * NRIRDL;
XRIRDR = 0.9 * NRIRDR;
}
else {
XRIRDL = NRIRDL - 1;
XRIRDR = NRIRDR - 1;
}
</script>
So I have this javascript, but it's not working.
var verbs = [ ["ambulo", "ambulare", "ambulavi", "ambulatus"], ["impedio", "impedire", "impedivi", "impeditus"] ]
var verbNumber = verbs.length - 1;
function randomIntFromInterval(min,max) {
return Math.floor(Math.random()*(max-min+1)+min);
}
/* Picks a verb */
var thisVerb = verbs[randomIntFromInterval(0, verbNumber)];
/* Checks the conjugation */
var second = thisVerb[1];
var secondLength = second.length;
var start = secondLength - 3;
var secondEnding = second.substring(start, secondLength);
var conjugationNumber = 0;
if (secondEnding === "are") {
conjugationNumber = 1;
} else if (secondEnding === "ēre") {
conjugationNumber = 2;
} else if (secondEnding === "ere") {
conjugationNumber = 3;
} else if (secondEnding === "ire") {
conjugationNumber = 4;
} else {
console.log("error");
};
/* Randomly picks how to conjugate */
var tense = randomIntFromInterval(1, 6);
var person = randomIntFromInterval(1, 3);
var number = randomIntFromInterval(1, 2);
var voice = randomIntFromInterval(1, 2);
/* Conjugates */
var thisDictEntry = 0;
if ((conjugationNumber === 1 || 2) && (tense === 1 || 2 || 3)) {
thisDictEntry = 2;
} else if ((conjugationNumber === 3 || 4) && (tense === 1 || 2 || 3)) {
thisDictEntry = 1;
} else if ((tense === 4 || 5 || 6) && (voice === 1)) {
thisDictEntry = 3;
} else if ((conjugationNumber === 3 || 4) && (voice === 2)) {
thisDictEntry = 4;
} else {
console.log("Error");
};
What should happen is a random verb (array within an array) is picked, then becomes randomly conjugated. All the code works up until the if/else if/else statements under the /* Conjugates */. That, for some reason, always sets thisDictEntry to 2.
Why?
The first condition:
((conjugationNumber === 1 || 2) && (tense === 1 || 2 || 3))
should be:
((conjugationNumber === 1 || conjugationNumber === 2) && (tense === 1 || tense === 2 || tense === 3))
the problem with your version is that javascript does the following:
conjugationNumber === 1 // this results in true/false
or
2 // this is always true
because js evaluates it as truthy.