Karatsuba Algorithm implemented in JavaScript not accurate - javascript

I am trying to implement the Karatsuba Algorithm in JavaScript. Below is my Implementation:
var bigInt = require("big-integer");
function bigKaratsuba(num1, num2) {
if (Number(num1) < 10 || Number(num2) < 10) {
return (Number(num1)*Number(num2)).toString();
}
var len1 = String(num1).length;
var len2 = String(num2).length;
var m = Math.max(len1, len2);
var m2 = Math.floor(m/2);
var high1 = String(num1).substring(0, m-m2);
var low1 = String(num1).substring(m-m2, len1);
var high2 = String(num2).substring(0, m-m2);
var low2 = String(num2).substring(m-m2, len2);
var high1 = bigInt(String(num1).substring(0, m-m2));
var low1 = bigInt(String(num1).substring(m-m2, len1));
var high2 = bigInt(String(num2).substring(0, m-m2));
var low2 = bigInt(String(num2).substring(m-m2, len2));
var low1AndHigh1 = low1.add(high1).toString();
var low2AndHigh2 = low2.add(high2).toString();
var high1 = String(high1);
var low1 = String(low1);
var high2 = String(high2);
var low2 = String(low2);
var z0 = bigKaratsuba(low1, low2);
var z1 = bigKaratsuba(low1AndHigh1, low2AndHigh2);
var z2 = bigKaratsuba(high1, high2);
var z0_int = bigInt(z0);
var z1_int = bigInt(z1);
var z2_int = bigInt(z2);
var product = z2_int.times(Math.pow(10, m2*2)).add(z1_int.minus(z2_int).minus(z0_int).times(Math.pow(10, m2))).add(z0_int);
return String(product);
}
bigKaratsuba(15, 15);
<script src="http://peterolson.github.com/BigInteger.js/BigInteger.min.js"></script>
This implementation works perfectly for small value, however while I am trying to calculate
3141592653589793238462643383279502884197169399375105820974944592 times
2718281828459045235360287471352662497757247093699959574966967627, the answer gose wrong, what I got is
8541020071716445382689180042569347598344699394502900911882868254737925119641226981222291225174629534283004908305569988292269254, which is not correct. The correct answer is 8539734222673567065463550869546574495034888535765114961879601127067743044893204848617875072216249073013374895871952806582723184 which I got it from here.
I have tried search on the stackoverflow but I haven't find any solution to my problem. There is no error or anything when I run my code. Any help or pointer will be highly appreciated. Thanks in advance for all the people who are being helpful.

With the great help of #Spektre and #greybeard, I managed to solve this problem. Below is the correct code:
var bigInt = require("big-integer");
function bigKaratsuba(num1, num2) {
if (Number(num1) < 10 || Number(num2) < 10) {
return (Number(num1)*Number(num2)).toString();
}
var len1 = String(num1).length;
var len2 = String(num2).length;
var m = Math.max(len1, len2);
var m2 = Math.floor(m/2);
var high1 = bigInt(String(num1).substring(0, len1-m2));
var low1 = bigInt(String(num1).substring(len1-m2, len1));
var high2 = bigInt(String(num2).substring(0, len2-m2));
var low2 = bigInt(String(num2).substring(len2-m2, len2));
var low1AndHigh1 = low1.add(high1).toString();
var low2AndHigh2 = low2.add(high2).toString();
var high1 = String(high1);
var low1 = String(low1);
var high2 = String(high2);
var low2 = String(low2);
var z0 = bigKaratsuba(low1, low2);
var z1 = bigKaratsuba(low1AndHigh1, low2AndHigh2);
var z2 = bigKaratsuba(high1, high2);
var z0_int = bigInt(z0);
var z1_int = bigInt(z1);
var z2_int = bigInt(z2);
var z1MinusZ2MinusZ0 = z1_int.minus(z2_int).minus(z0_int).toString();
var product = bigInt(addTrailingZero(z2, m2*2)).add(bigInt(addTrailingZero(z1MinusZ2MinusZ0, m2))).add(z0);
return String(product);
}
function addTrailingZero (numericString, numberOfZeroAdded) {
for (var i = 0; i < numberOfZeroAdded; i++) {
numericString = numericString + "0";
}
return numericString;
}
<script src="http://peterolson.github.com/BigInteger.js/BigInteger.min.js"></script>
As #Spektre pointed out, my original solution does truncate the mantissa since the biggest safe integer is 2^53-1. So one should add zero instead of doing the multiplication, besides it's also faster to add zero I believe.(Let me know if I am wrong).
Besides after trying the number suggested by #greybeard, I found that my original code snippet doesn't provide the correct solution so I changed it to
var high1 = bigInt(String(num1).substring(0, len1-m2));
var low1 = bigInt(String(num1).substring(len1-m2, len1));
var high2 = bigInt(String(num2).substring(0, len2-m2));
var low2 = bigInt(String(num2).substring(len2-m2, len2));

Related

Certain number question being missed in regex

I have the following if statement that removes the first instances of a number followed by the period. However, I am noticing it is missing to catch some of them (ex. "16.", "23.", "24.", etc.) and not sure why.
Here is the function:
function quesCleanUp(ques){
//Checks the first instance of "." and removes it and the number
if(ques.match(/[0-9]\./g)?.length > 1){//(ques.match(/./g)?.length > 1){
var quesClean = ques.replace(/^[^\.]*\./, '').trim();
} else{
var quesClean = ques.trim();
}
return quesClean;
}
The following for loop extracts the question from the google form:
for (var i = 0; i < items.length; i++) {
var item = items[i];
switch(item.getType()) {
case FormApp.ItemType.MULTIPLE_CHOICE:
var question = item.asMultipleChoiceItem();
var ques = quesCleanUp(question.getTitle().trim());//replace(/\s/g, "");
var question_type = "Multiple Choice";
var optns = [];
var answr;
var answers = question.getChoices();
answer_val = false;
for (var j = 0; j < answers.length; j++) {
var clean = answers[j].getValue().trim();
optns.push(clean);
if(answers[j].isCorrectAnswer()){
answr = answers[j].getValue().trim();
for(var x = 0; x < optns.length; x++){
if(answr == optns[x]){
answer_val = true;
break;
}
}
}
}
var multiJSON = makeJSON(ques, question_type, optns, answr);
console.log("JSON1: " + JSON.stringify(multiJSON));
constructedJSON[i+1] = multiJSON;
break;
case FormApp.ItemType.CHECKBOX:
var question = item.asCheckboxItem();
//var ques = question.getTitle().trim();//.replace(/\s/g, "");
var ques = quesCleanUp(question.getTitle().trim());//replace(/\s/g, "");
var question_type = "CheckBox";
var optns = [];
var answr = [];
var answers = question.getChoices();
for (var j = 0; j < answers.length; j++) {
var clean = answers[j].getValue().trim();//replace(/\s/g, "");
optns.push(clean);
if(answers[j].isCorrectAnswer()){
answr.push(answers[j].getValue().trim());
}
}
var checkJSON = makeJSON(ques, question_type, optns, answr);
console.log("JSON2: " + JSON.stringify(checkJSON));
constructedJSON[i+1] = checkJSON;
break;
case FormApp.ItemType.PARAGRAPH_TEXT:
var question = item.asParagraphTextItem();
//var ques = question.getTitle().trim();//.replace(/\s/g, "");
var ques = quesCleanUp(question.getTitle().trim());//replace(/\s/g, "");
var question_type = "free response";
var optns = [];
var answr;
var paraJSON = makeJSON(ques, question_type, optns, answr);
console.log("JSON3: " + JSON.stringify(paraJSON));
constructedJSON[i+1] = paraJSON;
break;
case FormApp.ItemType.TEXT:
var question = item.asTextItem();
//var ques = question.getTitle().trim();
var question_type = "free response";
var ques = quesCleanUp(question.getTitle().trim());//replace(/\s/g, "");
var optns = "";
var answr = "";
var textJSON = makeJSON(ques, question_type, optns, answr);
console.log("JSON4: " + JSON.stringify(textJSON));
constructedJSON[i+1] = textJSON;
break;
}
The following example is the type of question 16. What is the meaning of life?
And the expected output: What is the meaning of life?
Try using /[0-9]+./g to catch more than one digit
As a quick fix, in the function quesCleanUp() try to change the line:
if(ques.match(/[0-9]\./g)?.length > 1){//(ques.match(/./g)?.length > 1){
With:
if (ques.match(/^[0-9]+\./g).length > 0) {
I suspect you got the downvotes because you posted the code with glared typos. It looks like you didn't even try to debug it first. And as the icing on the cake you accepted a wrong answer.
And probably the function can be boiled down to just one line:
const quesCleanUp = q => q.replace(/^\d+\./,'').trim();
Here is how it works:
var questions = ['1. aaa', '16. What', '23. That', 'No nums'];
const quesCleanUp = q => q.replace(/^\d+\./,'').trim();
questions.forEach(q => console.log(quesCleanUp(q)));
Expected output:
aaa
What
That
No nums

How to use the result of an IF statement as a variable

I have a code as follows:
function DetailFacture2() {
var ss = SpreadsheetApp.getActive();
var DetailDEVIS = SpreadsheetApp.setActiveSheet(ss.getSheetByName('DetailDEVIS'));
var FACTUREDevis = SpreadsheetApp.setActiveSheet(ss.getSheetByName('FACTUREDevis'));
var DetailFactureDevis = SpreadsheetApp.setActiveSheet(ss.getSheetByName('DetailFactureDevis'));
var lastrowpaste = FACTUREDevis.getLastRow();
var numrow = FACTUREDevis.getRange(lastrowpaste,13).getValue()
var lastrowpaste2 = DetailFactureDevis.getLastRow() - numrow +2;
var data = DetailDEVIS.getDataRange().getValues();
var DetailD = FACTUREDevis.getRange(lastrowpaste,2).getValue();
for(var i = 0; i<data.length;i++){
if(data[i][1] == DetailD){ //[1] because column B
var firstrowcopy = i+1;
Logger.log(firstrowcopy)
return (firstrowcopy)
}
}
};
It does return the correct value, but how do you use "firstrowcopy" as a fixed var?
I would like to use as follows:
function DetailFacture2() {
var ss = SpreadsheetApp.getActive();
var DetailDEVIS = SpreadsheetApp.setActiveSheet(ss.getSheetByName('DetailDEVIS'));
var FACTUREDevis = SpreadsheetApp.setActiveSheet(ss.getSheetByName('FACTUREDevis'));
var DetailFactureDevis = SpreadsheetApp.setActiveSheet(ss.getSheetByName('DetailFactureDevis'));
var lastrowpaste = FACTUREDevis.getLastRow();
var numrow = FACTUREDevis.getRange(lastrowpaste,13).getValue()
var lastrowpaste2 = DetailFactureDevis.getLastRow() - numrow +2;
var data = DetailDEVIS.getDataRange().getValues();
var DetailD = FACTUREDevis.getRange(lastrowpaste,2).getValue();
for(var i = 0; i<data.length;i++){
if(data[i][1] == DetailD){ //[1] because column B
var firstrowcopy = i+1;
var source = DetailDEVIS.getRange(firstrowcopy,1,numrow-1);
var destination = DetailFactureDevis.getRange(lastrowpaste2,3);
source.copyTo(destination);
}
}
};
But, as one would expect, it cannot work as it loops...
Not sure if I understand your question too. The code doesn't look well. Here is just my guess. Try to change the last lines this way:
// ...
var firstrowcopy = 0;
for (var i = 0; i < data.length; i++){
if(data[i][1] == DetailD){ //[1] because column B
firstrowcopy = i+1;
break;
}
}
var source = DetailDEVIS.getRange(firstrowcopy,1,numrow-1);
var destination = DetailFactureDevis.getRange(lastrowpaste2,3);
source.copyTo(destination);
}

I have a misunderstanding with localStorage

I'm currently beginning to learn how to use javascript, and I have a small problem.
I'm making a minigame of 'find the random number', and I'm trying to implement a localStorage savestate that let me keep my game as it was when I closed it, but without success. Here's the part of my JS
where I'm stuck.
let Rndm = Math.floor(Math.random() * 100) + 1;
var tentatives = document.querySelector('.tentatives');
var resultat = document.querySelector('.resultat');
var plusoumoins = document.querySelector('.plusoumoins');
var valider = document.querySelector('.valider');
var essai = document.querySelector('.essai');
var nmbrmax = 1000;
var nmbrtent = 1;
let j1 = document.getElementById("j1");
let j2 = document.getElementById("j2");
var joueur1 = document.getElementById("joueur1");
var joueur2 = document.getElementById("joueur2");
let nomsjoueurs = document.getElementById("nomsjoueurs");
let tour = document.getElementById("tour");
var playerTurn = 0;
const partiesauvee = []
function sauvegarder() {
partiesauvee.push(tentatives.textContent);
partiesauvee.push(resultat.textContent);
partiesauvee.push(plusoumoins.textContent);
partiesauvee.push(nmbrmax);
partiesauvee.push(nmbrtent);
partiesauvee.push(joueur1.value);
partiesauvee.push(joueur2.value);
localStorage.setItem('sauvegard', JSON.stringify(partiesauvee))
}
function refresh() {
const partiesauvee = JSON.parse(localStorage.getItem('sauvegard'));
var tentatives = JSON.parse(localStorage.getItem('sauvegard'));
var resultat = JSON.parse(localStorage.getItem('sauvegard'));
var plusoumoins = JSON.parse(localStorage.getItem('sauvegard'));
var nmbrmax = localStorage.getItem('sauvegard');
var nmbrtent = localStorage.getItem('sauvegard');
var joueur1 = JSON.parse(localStorage.getItem('sauvegard'));
var joueur2 = JSON.parse(localStorage.getItem('sauvegard'));
}
window.addEventListener('DOMContentLoaded', refresh);
When the sauvegarder function is activated, the console.log(localstorage) find all the values,
but I can't find a way to return them to their places. Someone have an idea? Thanks !
You're storing an array. You need to assign each array element to a different DOM element.
function refresh() {
const storage = localStorage.getItem('sauvegard');
if (!storage) { // nothing saved
return;
}
const partiesauvee = JSON.parse(storage);
tentatives.textContent = partiesauvee[0];
resultat.textContent = partiesauvee[1];
plusoumoins.textContent = partiesauvee[2];
nmbrmax.textContent = partiesauvee[3];
nmbrtent.textContent = partiesauvee[4];
joueur1.textContent = partiesauvee[5];
joueur2.textContent = partiesauvee[6];
}

Reading values from input fields created in an array with document.createElement()

I'm trying to build a table that the user can hit "new line" to create a new row of the table. I do this by foo.push(document.createElement("INPUT"));
function newLine() {
sArr.push(document.createElement("INPUT"));
sArr[sArr.length-1].setAttribute("type", "text");
document.body.appendChild(sArr[sArr.length-1]);
gArr.push(document.createElement("INPUT"));
gArr[gArr.length-1].setAttribute("type", "text");
document.body.appendChild(gArr[gArr.length-1]);
tArr.push(document.createElement("INPUT"));
tArr[tArr.length-1].setAttribute("type", "text");
document.body.appendChild(tArr[tArr.length-1]);
//alert(sArr.length+", "+gArr.length+", "+tArr.length);
var x = document.createElement("br");
document.body.appendChild(x);
}
function calc(){
var temp = 0;
var total = 0;
for(i = 0; i<sArr.length; i++){
total = total + calc2(i);
}
var o = document.getElementById("output");
o.value = total;
}
function calc2(i){
alert(i);
var s = document.getElementById(sArr[i]);
var g = document.getElementById(gArr[i]);
var t = document.getElementById(tArr[i]);
var VO2walkmin = 3.28;
var VO2rest = 3.05;
var C1 = 0.32;
var C2 = 0.19;
var C3 = 2.66;
var Cdecline = 0.73;
var s2 = s.value;
var g2 = g.value;
var t2 = t.value;
var negGrade = g.value;
if(g2 < 0){g2 = 0};
VO2move = ((C1 * g2)+VO2walkmin)+((1+(C2*g2))*(C3*(s2^2)));
VO2inc = VO2rest+(t2*VO2move);
VO2dec = VO2rest+(Cdecline*(t2*VO2move))
//var o = document.getElementById("output");
return VO2inc;
}
When run, I get the error:
Uncaught TypeError: Cannot read property 'value' of null
from line 66. Specifically, this line:
var s2 = s.value;
I'm struggling to find my mistake here... and all help is appreciated.
You create a new element, but it has no ID. And so you can't fetch it by ID. The result of document.getElementById(sArr[i]) will be null.
Check this answer to see how ID can be assigned to a newly created element:
Create element with ID
There's no need to use document.getElementById. sArr[i] is the input element itself, not its ID, so you can just read its value directly.
var s = sArr[i];
var g = gArr[i];
var t = tArr[i];

Prototype function no longer working, coming up as undefined

I have no idea what I did wrong. It worked before I uploaded to github.io so I'm suspicious I messed up some branches and am now stuck with an older file. I'm impossibly stuck and just need an outside perspective to figure it out.
It's a program to help order pizza (all in js/jquery), it's no longer adding up the variables and returning an order total. It says var total is undefined, and I'm not completely sure whether it's my equations or variables. I had it working fine before so I know it's possible with my code, I think I just made a mistake somewhere in the process of switching/adding branches that bungled it.
function order(sidesOrderedReduced, pizzaSauceReduced, beveragesOrderedReduced, dessertsOrderedReduced, pizzaToppingsReduced, zipcodeAddress, cityAddress, streetAddress, total){
this.sidesOrderedReduced = sidesOrderedReduced;
this.beveragesOrderedReduced = beveragesOrderedReduced;
this.dessertsOrderedReduced = dessertsOrderedReduced;
this.pizzaSauceReduced = pizzaSauceReduced;
this.pizzaToppingsReduced = pizzaToppingsReduced;
this.zipcodeAddress = zipcodeAddress;
this.cityAddress = cityAddress;
this.streetAddress = streetAddress;
this.total = total;
}
var sidesListed = [];
var sidesOrdered = [];
sidesOrderedReduced = sidesOrderedReduced || 0
var sidesOrderedReduced;
var beveragesListed= [];
var beveragesOrdered = [];
var beveragesOrderedReduced;
beveragesOrderedReduced = beveragesOrderedReduced || 0
var dessertsListed = [];
var dessertsOrdered = [];
var dessertsOrderedReduced;
dessertsOrderedReduced = dessertsOrderedReduced || 0
var pizzaSauceListed = [];
var pizzaSauce = [];
var pizzaSauceReduced = [];
pizzaSauceReduced = pizzaSauceReduced || 0
var pizzaToppingsListed = [];
var pizzaToppingsOrdered = [];
var pizzaToppingsReduced;
pizzaToppingsReduced = pizzaToppingsReduced || 0
var total;
var zipcodeAddress = $("input#zipcodeAddress").val();
var cityAddress = $("input#cityAddress").val();
var streetAddress = $("input#streetAddress").val();
var newOrder = new order(sidesOrderedReduced, beveragesOrderedReduced, dessertsOrderedReduced, pizzaSauceReduced, pizzaToppingsReduced, zipcodeAddress, cityAddress, streetAddress, total);
order.prototype.total = function(){
return this.beveragesOrderedReduced+this.sidesOrderedReduced+this.dessertsOrderedReduced+this.pizzaSauceReduced+this.pizzaToppingsReduced;
}
$("input:checkbox[value=sides]:checked").each(function(){
sidesListed.push($(this).attr("id"));
sidesOrdered.push(5);
sidesOrderedReduced = sidesOrdered.reduceRight(function(a,b){return a+b;});
return sidesOrderedReduced;
});
$("input:checkbox[value=pizzaSauce]:checked").each(function(){
pizzaSauceListed.push($(this).attr("id"));
pizzaSauce.push(10);
pizzaSauceReduced = pizzaSauce.reduceRight(function(a,b){return a+b;});
return pizzaSauceReduced;
});
$("input:checkbox[value=pizzaToppings]:checked").each(function(){
pizzaToppingsListed.push($(this).attr("id"));
pizzaToppingsOrdered.push(1);
pizzaToppingsReduced = pizzaToppingsOrdered.reduceRight(function(a,b){return a+b;});
return pizzaToppingsReduced;
});
$("input:checkbox[value=beverages]:checked").each(function(){
beveragesListed.push($(this).attr("id"));
beveragesOrdered.push(3);
beveragesOrderedReduced = beveragesOrdered.reduceRight(function(a,b){return a+b;});
return beveragesOrderedReduced;
});
$("input:checkbox[value=desserts]:checked").each(function(){
dessertsListed.push($(this).attr("id"));
dessertsOrdered.push(5);
dessertsOrderedReduced = dessertsOrdered.reduceRight(function(a,b){return a+b;});
return dessertsOrderedReduced;
});
$("ul#orders").append(
"<li><span class='orderInfo'>Order</span></li>");
$(".orderInfo").last().click(function(){
$("#show-info").show();
$(".sides").text(sidesListed);
$(".pizzaSauce").text(pizzaSauceListed);
$(".pizzaToppings").text(pizzaToppingsListed);
$(".beverages").text(beveragesListed);
$(".desserts").text(dessertsListed);
$(".zipcodeAddress").text(newOrder.zipcodeAddress);
$(".streetAddress").text(newOrder.streetAddress);
$(".cityAddress").text(newOrder.cityAddress);
$(".total").text(newOrder.total);
});
//$('input:checkbox').removeAttr('checked');
$("input#zipcodeAddress").val("");
$("input#cityAddress").val("");
$("input#streetAddress").val("");
});
});
Change
$(".total").text(newOrder.total);
to
$('.total').text(newOrder.total());
total is a method. You just used it as a property.

Categories

Resources