Sum Big Integers - javascript

I'm currently stuck on a Codewars challenge that I can't get my head around:
Given a string representation of two integers, return the string representation of those integers, e.g. sumStrings('1','2') // => '3'
I've used the following code so far, but it fails on large number test cases as the number is converted into a scientific notation:
function sumStrings(a,b) {
var res = +a + +b;
return res.toString();
}
Any help would be much appreciated.
Edit:
Fiddle example: https://jsfiddle.net/ag1z4x7d/

function sumStrings(a, b) { // sum for any length
function carry(value, index) { // cash & carry
if (!value) { // no value no fun
return; // leave shop
}
this[index] = (this[index] || 0) + value; // add value
if (this[index] > 9) { // carry necessary?
carry.bind(this)(this[index] / 10 | 0, index + 1); // better know this & go on
this[index] %= 10; // remind me later
}
}
var array1 = a.split('').map(Number).reverse(), // split stuff and reverse
array2 = b.split('').map(Number).reverse(); // here as well
array1.forEach(carry, array2); // loop baby, shop every item
return array2.reverse().join(''); // return right ordered sum
}
document.write(sumStrings('999', '9') + '<br>');
document.write(sumStrings('9', '999') + '<br>');
document.write(sumStrings('1', '9999999999999999999999999999999999999999999999999999') + '<br>');

The problem is that in that specific kata (IIRC), the numbers stored in a and b are too large for a regular 32 bit integer, and floating point arithmetic isn't exact. Therefore, your version does not return the correct value:
sumStrings('100000000000000000000', '1')
// returns '100000000000000000000' instead of '100000000000000000001'
You have to make sure that this does not happen. One way is to do an good old-fashioned carry-based addition and stay in the digit/character based world throughout the whole computation:
function sumStrings(a, b) {
var digits_a = a.split('')
var digits_b = b.split('')
...
}

Related

how to truncate output values in Nerdamer

I am using nerdamer.solve to solve roots but the roots are long and not truncated. I wanted to get truncated values upto 4 decimal places. How can I achieve this?
I am using the following code to solve and display output in html:
var r = nerdamer.solve(`1 - ${a} * x^(${p}) + ${b}`, 'x');
document.getElementById("polesAns").innerHTML= r.toString();
The folllowing is output:
[(138655807/135201312)*i+49385501/48155102,(-138655807/135201312)*i+49385501/48155102,(58886197/57419096)*i-49385501/48155102,(-58886197/57419096)*i-49385501/48155102,-560373381/386371730,172668482/119053157,(145619303/100403024)*i-5753750945848186/10000000000000000000000000000000,(-560373381/386371730)*i-5753750945848186/10000000000000000000000000000000]
There is no division performed also.
I tried the solution posted here:
How to use .toFixed() (or any alternative) on Nerdamer.solve solutions?
But how can I do this with my code? I tried the following:
var value = `1 - ${a} * x^(${p}) + ${b}`;
var toFixed = function(value, n) {
var img = Number(nerdamer.imagpart(value).text()).toFixed(n);
var real = Number(nerdamer.realpart(value).text()).toFixed(n);
// Format the number assuming i denotes imaginary in your case
var formatted = '';
if(real !== '0.0000') {
formatted += real;
}
if(img !== '0.0000') {
// Put the plus sign betweent the real and imaginary
if(img.charAt(0) !== '-' && formatted) {
formatted += '+';
}
// Assuming you're using i and not j for instance
formatted += img+'i';
}
return formatted;
};
sol_raw = this.nerdamer.solve(value,'s');
xs = this.nerdamer(sol_raw.toString()).each(function(solution) {
roundedSolutions.push(toFixed(solution, 4));
});
this.setState({
solution: roundedSolution.join(''),
equation:value})
document.getElementById("polesAns").value = solution.toString();
I don't understand the this.setState() part , should i declare sol_raw and xs as var?
Also the substitution of variable is used in the my above root equation from advice here javascript Solving equation with subsitution of variable value
thank you

Operator gets lost when a expression is sent as argument Javascript

I have a simple JS function
let a = 0.33, c=13.89;
var res = calcRound(c*2+calcRound(a*2,1,1),1,1);
console.log(res);
function calcRound(value, figure, padding) {
let val = value;
let result = parseFloat(val);
result = result.toFixed(figure);
return result;
}
It returns a 27.8. But the answer should be 28.5
I have debugged the code. At first, it calculates this and it is correct
calcRound(a*2,1,1) = 0.7
Second time the '+' operator between c*2 and calcRound(a*2,1,1) gets lost.
it becomes like this 27.780.7 which should be like this 27.78+0.7
I know JS first evaluates the expression before sending it as an argument. My question is why the '+' operator is getting omitted?
+ is the concatenator operator in JS, it thinks the result from calcRound() is a string and behaves accordingly.
As mentioned by Andy in the comments, you can see in the
documentation for toFixed()
Return value: A string representing the given number using fixed-point
notation.
Change the return of your function to (to make sure it returns a number):
return Number( result );
let a = 0.33,
c = 13.89;
var res = calcRound(c * 2 + calcRound(a * 2, 1, 1), 1, 1);
console.log(res);
function calcRound(value, figure, padding) {
let val = value;
let result = parseFloat(val);
result = result.toFixed(figure);
return Number(result);
}
It's not getting omitted, JavaScript is treating them like strings and adding 27.78+0.7 as strings, you want to surround them in Number() or parseFloat() statements so that they are treated as numbers.
Like so:
calcRound(parseFloat(c*2) + parseFloat(calcRound(a*2,1,1)),1,1)

Method implementation that takes 3 parameters and returns a binary number

I found a method that converts 1 number to a binary number.
function dec2bin(dec){
return (dec >>> 0).toString(2);
}
How to implement a method that takes 3 parameters (or more if possible) and turns them into one binary number.
for example:
Encrypt user with parameters
Age (up to 255-> 11111111)
Number of vacations (up to 15-> 1111)
On vacation or not (1 or 0)
create(30, 13, 1);
Expected to get 3 stacked together (00011110) (1101) (1): 0001111011011
According to your requirement Encrypt user with parameters age (up to 255-> 11111111), Number of vacations (up to 15-> 1111), On vacation or not (1 or 0)
const create = (age, noOfVacations, onVacation) => {
return (
age.toString(2).padStart(8, '0') +
noOfVacations.toString(2).padStart(4, '0') +
onVacation.toString(2).padStart(1, '0')
);
};
const ret = create(30, 13, 1);
console.log(ret);
By the way, you can refactor the above code to make it more reusable by making a separated binary to decimal with zero padding function.
const binToDecWithZeroPad = (param, n) => param.toString(2).padStart(n, '0');
const create = (age, noOfVacations, onVacation) =>
binToDecWithZeroPad(age, 8) +
binToDecWithZeroPad(noOfVacations, 4) +
binToDecWithZeroPad(onVacation, 1);
const ret = create(30, 13, 1);
console.log(ret);
If parameter number is unknown you can use rest parameter. Rest parameter syntax allows us to represent an indefinite number of arguments as an array. So you can use any number of parameter.
const create = (...params) => {
let str = '';
params.forEach((x) => (str += x.toString(2)));
return str;
};
const ret = create(30, 13, 1);
console.log(ret);
Update:
I have not to checked if the parameter is a non numeric, decimal or negative in my code because if you need to check it you can easily add it by using simple if condition and as for adding zero dynamically you cannot use more than one rest parameter because this is the limitation that only one rest parameter is allowed in the function declaration. Although, you can solve it by using one rest parameter(think about it if you have time). By the way, you can also use object, single or multiple array whatever you want as a parameter to make it dynamic.
This should work:
function dec2bin(dec){
return (dec >>> 0).toString(2);
}
function create(age, vacationNumber, vacation) {
var a = dec2bin(age).padStart(8, "0"); // padEnd adds zeros to match size
var b = dec2bin(vacationNumber).padStart(4, "0");
var c = vacation==true||vacation==1 ? 1 : 0;
return a + b + c;
}
console.log(create(15, 20, 1))
Here is a function encrypt that works on an array of any number of arguments, as long as you provide long enough encript digits array, and inputs are non-negative integers - if any of the conditions are not met, undefined is returned:
function dec2bin(dec, digits) {
if(typeof(dec)=="number" && dec%1==0 && dec>=0 && dec<Math.pow(2, digits))
return dec.toString(2).padStart(digits, "0");
return undefined;
}
function encrypt(userDetailsArray, encriptDigitsArray) {
if(userDetailsArray.length<=encriptDigitsArray.length) {
var result=(
userDetailsArray.map(
(detail, index) => dec2bin(detail, encriptDigitsArray[index])
)
);
if(result.includes(undefined))
return undefined;
else
return result.join("");
}
return undefined;
}
console.log(encrypt([30,13,1],[8,4,1])); /* your example */
console.log(encrypt([30,13],[8,4,1])); /* less input */
console.log(encrypt([30],[8,4,1])); /* even less input */
console.log(encrypt([30,13,1,100,5],[8,4,1,7,4])); /* more input and encript digits */
console.log(encrypt([999,13,1],[8,4,1])); /* bad input */
console.log(encrypt([30,13,1],[8,4])); /* not enough encript digits */
Decrypt (without testing validity of arguments):
function decrypt(bin, encriptDigitsArray) {
var result=[];
while(bin!="" && encriptDigitsArray.length) {
result.push(parseInt(bin.slice(0,encriptDigitsArray[0]), 2));
bin=bin.slice(encriptDigitsArray[0]);
encriptDigitsArray.shift();
}
return result;
}
console.log(decrypt("0001111011011",[8,4,1]));
console.log(decrypt("000111101101",[8,4,1]));
console.log(decrypt("00011110",[8,4,1]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

javascript toFixed not working in my calculations

Hi guys I have bytes say 007458415820874584158208042423283712.I want to convert this into GB, so tried to divide it by 1048576 i am getting a result of 7.112899609446129e+27. I want only the two numbers after the decimal point, so I have used .toFixed like below. It doesn't work, I am getting the same response as if I have not used the toFixed function. I just want the result to be just 7.1. help me out on this.
console.log((007458415820874584158208042423283712/1048576).toFixed(2));
You can use this prototype function for your solution.
Number.prototype.toFixedSpecial = function(n) {
var str = this.toFixed(n);
if (str.indexOf('e+') === -1)
return str;
// if number is in scientific notation, pick (b)ase and (p)ower
str = str.replace('.', '').split('e+').reduce(function(p, b) {
return p + Array(b - p.length + 2).join(0);
});
if (n > 0)
str += '.' + Array(n + 1).join(0);
return str;
};
var val = (007458415820874584158208042423283712/1048576);
console.log(val);
console.log(val.toFixedSpecial(2)) //"7112899609446129000000000000.00"
console.log( 1e21.toFixedSpecial(2) ); // "1000000000000000000000.00"
console.log( 2.1e24.toFixedSpecial(0) ); // "2100000000000000000000000"
console.log( 1234567..toFixedSpecial(1) ); // "1234567.0"
console.log( 1234567.89.toFixedSpecial(3) ); // "1234567.890"
Your problem is that this is scientific notation and toFixed() supports 20 decimal places. Your number is 7.112899609446129e+27 which technically (most likely) has decimal places but they are not visible due to scientific notation.
The solution would be to use toExponential() like so:
parseFloat((7458415820874584158208042423283712/1048576.0).toExponential(2))
Output:
7.11e+27
A more correct way is shown here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toExponential
But this gives "7.11e+27" (a string)
If you just want 7.11 then you can use slice(0,3) as follows:
var result_str = (7458415820874584158208042423283712/1048576).toExponential(2);
console.log(parseFloat(result_str.slice(0,3)));
Result: 7.1

Javascript : function checking if the answer to score as a percentage has more than 2 decimal places

I want to create a dynamic worksheet for my students, so every time they do it they see different questions. The question that I am trying to create ie, calculate the percentage if I scored X out of a total of Y.
Here are the 3 functions which work together, the first generates some numbers, calls the second, which in turn calls the third to check if it more than 2 decimal places, then if it is, the second creates a new SCORE number which repeats until it finds an answer which is 2 decimal places or less, then returns the SCORE number which works to the first, which outputs it.
I keep getting one of three outputs : undefined where the SCORE should be, no output at all, or a working question.
I cannot understand how it works sometimes, throws undefined sometimes and gives completely nothing at other times.
Any ideas.
function scorePercent()
{
var output="";
var total = Math.floor((Math.random()*99)+1);
var score = Math.floor((Math.random()*(total-1))+1);
output = output + "<div>A score of " + chkScore(score,total) + " out of " + total + ".</div></br>";
document.getElementById("qOut").innerHTML=output;
}
function chkScore(n1,n2)
{
var answ = (n1/n2)*100;
if(dps(answ)>2)
{
var scoreNew = Math.floor((Math.random()*(n2-1))+1);
chkScore(scoreNew, n2);
}
else
{
return n1;
}
}
function dps(num)
{
var match = (''+num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
if (!match) { return 0; }
return Math.max(
0,
// Number of digits right of decimal point.
(match[1] ? match[1].length : 0)
// Adjust for scientific notation.
- (match[2] ? +match[2] : 0));
}
You have a recursive function in your chkScore, but you're not return-ing the results from the "deeper" iterations.
Try this:
function chkScore(n1,n2){
var answ = (n1/n2)*100;
if(dps(answ)>2) {
var scoreNew = Math.floor((Math.random()*(n2-1))+1);
return chkScore(scoreNew, n2); // <-- return that.
} else {
return n1;
}
}
The missing return there, resulted in the function sometimes not returning anything.
The "deeper" iterations will return their value only 1 "level" up, so that "level" will have to pass it through, if you know what I mean.

Categories

Resources