Reduce wrongly returning infinity - javascript

when I try to use math power in reduce it's not working as expected and returns infinity
const array1 = [1,2,3,4];
const initialValue = 0;
const sumWithInitial = array1.reduce(
(a,b) => a + Math.pow(b, b + a),
0
);
console.log(sumWithInitial);
but if there's only 1-3 numbers in arr1 it works as intended

As others have explained, you get infinity due to going way above the limit. But if you want to get the actual result, you can use BigInt operations:
const array1 = [1n, 2n, 3n, 4n];
const initialValue = 0n;
const sumWithInitial = array1.reduce(
(a, b) => a + b**(b + a),
initialValue
);
console.log(sumWithInitial.toString());

As of the last iteration, you're exceeding the capacity of the JavaScript number type (which is an IEEE-754 double-precision binary floating point value). It has nothing to do with reduce, it's just that Math.pow(4, 4 + 531450) (the last value produced by your reduce loop) goes past the limit:
console.log(Math.pow(4, 4 + 531450));
You can see when pow will do that via the Number::exponentiate abstract operation in the specification (in the text, infinity is denoted by +∞𝔽, negative infinity by -∞𝔽). This is just a fact of trying to use a 64-bit value to try to represent a truly, truly, truly massive number.
If you need to deal with those kinds of magnitudes, and you only need integer values, you can use a BigInt as Keldan Chapman points out.

Related

what is the difference between .split(" ") and ...array

I am trying to get the max and min numbers from str = "8 3 -5 42 -1 0 0 -9 4 7 4 -4"
The first method gives the correct answer using .min(...arr) but the second method using .min(arr) returns NAN. I thought the spread operator and the split method both created an array that could be passed into Math. What is the difference between the two.
function highAndLow(str){
let arr = str.split(" ")
let min = Math.min(...arr)
let max = Math.max(...arr)
return max + " " + min
}
function highAndLow2(str){
let arr = str.split(" ")
let min = Math.min(arr)
let max = Math.max(arr)
return max + " " + min
}
The Math.min/max functions accept a number as an argument. You can see in the documentation that:
The static function Math.min() returns the lowest-valued number passed into it, or NaN if any parameter isn't a number and can't be converted into one.
That is why, when you don't use the spread operator, you are passing in the array and you are getting NaN as a return value.
The Split operator:
takes a pattern and divides a String into an ordered list of substrings by searching for the pattern, puts these substrings into an array, and returns the array.
It does something completely different than the Spread operator and is used for other purposes.
I would advise you read more about the Spread operator here.
Math.min does not accept an array,
you need to destructure your array like so :
function highAndLow2(str){
let arr = str.split(" ")
let min = Math.min(...arr)
let max = Math.max(...arr)
return max + " " + min
}
which gives a result of '42 -9'
Math.min() or Math.max() does not accept an array, it is accepted as arguments. The spread operator (...arr) actually expands collected elements such as arrays into separate elements. split(" ") actually converts a string to array. If you want to get min or max value from an array then you have to use apply() like Math.min.apply(null, arr) or Math.max.apply(null, arr)

Convert whole number to one decimal in JavaScript

I got this issue.
I want to convert integer 71 (type number) to one decimal, meaning 71.0
but I need it to stay of type number.
Searched and the only solution I found was to use toFixed(1) and then parseFloat on
the result, and that does returns a number but 71, without the decimal.
const float = (num) => {
let fixed = (num).toFixed(1)
let float = parseFloat(fixed)
return float
}
float(71)
How should I do it?
This makes no sense, because an integer (whole number) will almost always equal its floating-point equivalent, unless there is a some odd precision behavior.
71 === 71.0
71 === 71.00
...
71 !== 71.000000001
Did you want to truncate a floating number using precision?
const truncateFloat = (n, p = 0) => parseFloat(n.toFixed(p));
// Truncate an irrational number (PI)
console.log(truncateFloat(Math.PI, 2) === 3.14) // true
Remove the parseFloat(fixed) and keep it as below
const float = (num) => {
let fixed = (num).toFixed(2)
//let float = parseFloat(fixed)
return float
}
float(71)
use toFixed(n) where n is the number of 10th places after the decimal.
You have stated that you need to keep it as number at the end but the thing is, if the decimals are 0, it will always round up to a whole number. So you may want to rather consider adding the toFixed(n) at the point of printing to the screen so they always print with that extra.
========= UPDATE
I just found a cleaner solution. consider the below with a link to the solution
const float = (num) => {
tmp = '0.00';
tmp = (+tmp + num).toFixed(2);
return tmp
}
float(71)
reference: how to get a float using parseFloat(0.00)

Find out the maximum number of decimal places within a string of numbers

The string looks like this like something along the lines of 3*2.2or 6+3.1*3.21 or (1+2)*3,1+(1.22+3) or 0.1+1+2.2423+2.1 it can vary a bit. I have to find the amount of decimal places in the number inside the string with the most decimal places.
Im totally helpless on how to do it
You can use a regular expression to find all numbers that have decimal places and then use Array.prototype.reduce to find the highest amount of decimal places.
const input = '0.1+1+2.2423+2.1';
const maxNumberOfDecimalPlaces = input
.match(/((?<=\.)\d+)/g)
?.reduce((acc, el) =>
acc >= el.length ?
acc :
el.length, 0) ?? 0;
console.log(maxNumberOfDecimalPlaces);
Note that this will return 0 when no numbers with decimal places are found in the string.
You may do the following:
Array.prototype.split() your input string by RegExp /\[^\d.\]+/ to extract numbers
traverse resulting array of numbers with Array.prototype.map() and split those by decimal separator into whole and fractional parts, returning the length of the fractional part or 0 (for integers)
use Math.max() to find the maximum length
Above method seems to be more robust as it does not involve certain not well supported features:
RegExp lookbehinds assertions (/(?<=)/) which may not be supported by certain popular browsers like Safari or Firefox (below current version)
latest features, like conditional chaining (.?) or nulish coalescing (??)
const src = ['3*2.2', '6+3.1*3.21', '(1+2)*3' , '1+(1.22+3)', '0.1+1+2.2423+2.1'],
maxDecimals = s =>
Math.max(
...s
.split(/[^\d.]+/)
.map(n => {
const [whole, fract] = n.split('.')
return fract ? fract.length : 0
})
)
src.forEach(s => console.log(`Input: ${s}, result: ${maxDecimals(s)}`))
.as-console-wrapper{min-height:100%;}
You could use regex pattern
var str="6+3.1*3.21"
d=str.match(/(?<=\d)[.]\d{1,}/g)
d!=null ? res=d.map((n,i) => ({["number" + (i+1) ] : n.length - 1}))
: res = 0
console.log(res)

Sum Strings as Numbers

I am trying to solve a kata that seems to be simple on codewars but i seem to not be getting it right.
The instruction for this is as simple as below
Given the string representations of two integers, return the string representation of the sum of those integers.
For example:
sumStrings('1','2') // => '3'
A string representation of an integer will contain no characters besides the ten numerals "0" to "9".
And this is what i have tried
function sumStrings(a,b) {
return ((+a) + (+b)).toString();
}
But the results solves all except two and these are the errors i get
sumStrings('712569312664357328695151392', '8100824045303269669937') - Expected: '712577413488402631964821329', instead got: '7.125774134884027e+26'
sumStrings('50095301248058391139327916261', '81055900096023504197206408605') - Expected: '131151201344081895336534324866', instead got: '1.3115120134408189e+29'
I don't seem to understand where the issues is from. Any help would help thanks.
The value you entered is bigger than the int type max value. You can try changing your code to:
function sumStrings(a,b) {
return ((BigInt(a)) + BigInt(b)).toString();
}
This way it should return the right value
You could pop the digits and collect with a carry over for the next digit.
function add(a, b) {
var aa = Array.from(a, Number),
bb = Array.from(b, Number),
result = [],
carry = 0,
i = Math.max(a.length, b.length);
while (i--) {
carry += (aa.pop() || 0) + (bb.pop() || 0);
result.unshift(carry % 10);
carry = Math.floor(carry / 10);
}
while (carry) {
result.unshift(carry % 10);
carry = Math.floor(carry / 10);
}
return result.join('');
}
console.log(add('712569312664357328695151392', '8100824045303269669937'));
console.log(add('50095301248058391139327916261', '81055900096023504197206408605'));
The problem is that regular javascript integers are not having enough space to store that much big number, So it uses the exponential notation to not lose its precision
what you can do is split each number into parts and add them separately,
one such example is here SO answer
My solution is:
function sumStrings(a,b) {
return BigInt(a) + BigInt(b) + ''
}
Converting from a string to a number or vice versa is not perfect in any language, they will be off by some digits. This doesn't seem to affect small numbers, but it affects big numbers a lot.
The function could go like this.
function sumStrings(a, b) {
return (BigInt(a) + BigInt(b)).toString() // or parseInt for both
}
However, it's still not perfect since if we try to do:
console.log((4213213124214211215421314213.0 + 124214321214213434213124211.0) === sumStrings('4213213124214211215421314213', '124214321214213434213124211'))
The output would be false.

How to convert array of decimal strings to array of integer strings without decimal and vice-versa

I want to achieve the following. How to get the desired output as below?
var arr=["1.00","-2.5","5.33333","8.984563"]
Desired output: arr=["1","-2","5","8"]
and vice-versa float to int.
You could save the sign, apply flooring to the absolute value, put the sign back and convert the result to a string. Map the whole stuff to a new array.
Vive versa does not work, because you loose information while using integer numbers.
var array = ["1.00", "-2.5", "5.33333", "8.984563"],
result = array.map(v => ((v >= 0 || -1) * Math.floor(Math.abs(v))).toString());
console.log(result);
var arr=["1.00","-2.5","5.33333","8.984563"]
arr.forEach(function (item, index, array) {
array[index] = parseInt(item)
})
var arr=["1.00","-2.5","5.33333","8.984563"]
var output = arr.map(n => Math[n < 0 ? "ceil":"floor"](n).toString() )
console.log( output )
Rounding to the closest value to zero using Math.ceil() for negative numbers and Math.floor() for positive numbers.

Categories

Resources