Operator gets lost when a expression is sent as argument Javascript - 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)

Related

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; }

Integer and string Javascript

i do a simple exercise "Write a JavaScript program to compute the sum of the two given integers. If the two values are same, then returns triple their sum".
InnerHTML is ok but it seems that my variables are string and not numbers (if i use parseFloat however it doesn't work).
Example : p161 = 10; p162 = 5; => ris = 105 and not 15
let p16 = document.getElementById("p16");
document.getElementById("button16").addEventListener("click", es);
function es(){
let p161 = document.getElementById("input161").value;
let p162 = document.getElementById("input162").value;
let ris = 0;
if (p161 == p162){
ris = (p161 + p162)*3;
return p16.innerHTML = ris;
} else {
ris = p161 + p162;
return p16.innerHTML = ris;
}
}
You are concatenating strings so what you see makes sense. Since you are looking for the sum of integers I dont see why you need to parseFloat. If you want numbers you should just do
let p161 = +document.getElementById("input161").value;
let p162 = +document.getElementById("input162").value;
Plus sign in this case is the unary operator that will convert value to Number type according to ECMA spec

Sum of toFixed not working correctly

I have the following code that calculates and shows the sum of two values.
var oldprice_formated = parseFloat(oldprice).toFixed(2);
var extraPrice = parseFloat(3).toFixed(2);
if(initials != '') {
var new_price = oldprice_formated + extraPrice;
$('.product-detail .woocommerce-Price-amount.amount').html('<span>€</span>'+new_price);
} else {
$('.product-detail .woocommerce-Price amount.amount').html('<span>€</span>'+oldprice_formated);
}
For example:
oldprice_formated = parseFloat(49.99).toFixed(2);
extraPrice = parseFloat(3.00).toFixed(2)
The expected result: Sum is 52.99
Actual result: Sum is 49.003.00
What am I doing wrong? I assume it's with the number parsing, but not sure what I should change to make it work correctly. Thanks!
.toFixed() returns a string, not a number with only two decimal places.
oldprice_formated = parseFloat(49.99).toFixed(2); // "49.99"
extraPrice = parseFloat(3.00).toFixed(2); // "3.00"
When adding those two variables, instead of a number sum, you're concatenating two strings:
"49.99" + "3.00"; // "49.993.00"
I believe this is what you'll want to do:
var new_price = parseFloat(oldprice_formated) + parseFloat(extraPrice);
Or simply run .toFixed() after you sum those values which were already parsed to floats.
Because toFixed() returns a string, the + operator acts as a string concatenator. If you want it to operate as an addition operator, you must typecast your values as numbers:
let oldprice = 49.99;
let oldprice_formatted = parseFloat(oldprice).toFixed(2);
let extraPrice = parseFloat(3).toFixed(2);
console.log(`string concatenation: ${oldprice_formatted + extraPrice}`)
console.log(`type conversion: ${+oldprice_formatted + +extraPrice}`)

Sum Big Integers

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('')
...
}

Enable a Rational class to handle math operators

I have this Rational class that has a method for each operation (add,mult etc)
function Rational(nominator, denominator){
this.nominator = nominator;
this.denominator = denominator || 1;
}
Rational.prototype = {
mult: function(that) {
return new Rational(
this.nominator * that.nominator,
this.denominator * that.denominator
);
},
print: function() {
return this.nominator + '/' + this.denominator;
}
};
var a = new Rational(1,2),
b = new Rational(3);
console.log( a.mult(b).print() ); // 3/2
Can I make it more "natural" e.g. to enable console.log( a * b ) ?
You can't overload operators (read similar questions).
Moreover, a dedicated method like mult can be treated as a sign of good design (not only in Javascript), since changing the original operator behavior can confuse users (well, a rational number actually a good candidate for overloading).
You can change print to toString as user thg435 has suggested.
Going even further:
Rational.prototype = {
mult : ... ,
toString: ... ,
valueOf: function() { return this.nominator / this.denominator; }
};
this will enable the a * b syntax (note: you don't operate on Rationals any more, but rather on primitives).
The closest you can get is some sort of operator aliasing, such as this:
/* Accepts a symbolic or string operator, returns a function which accepts numbers */
function operator(node)
{
//Mapping between string and symbol operators
var map = {"mod": "%", "mult": "*", "div": "/", "plus": "+", "minus": "-"}
//Return a function which applies the string or symbol operator to two numbers
return Function("x,y", "return x" + (map[node] || node) + "y");
}
// pass "*" to operator; pass 5,7 to returned function
var foo = operator("*")(5,7);
// pass "plus" to operator; pass 3,2 to returned function
var bar = operator("plus")(3,2);
// pass "mod" to operator; pass 1,0 to returned function
var baz = operator("mod")(1,0);
console.log(["foo",foo,"bar",bar,"baz",baz]); //["foo", 35, "bar", 5, "baz", NaN]
References
Can I define custom operator overloads in Javascript?
As an idea, you can try to write a parser yourself so you write some thing like this:
console.log(R("a * b"));
Where R is the function that converts a * b to a.mult(b) and then eval's this.

Categories

Resources