Javascript array join does not work correctly [duplicate] - javascript

This question already has answers here:
Issue with combining large array of numbers into one single number
(3 answers)
Closed 1 year ago.
I have the following array and I want to join it into a number
const arr = [6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,3]
const digits = arr.join("") //6145390195186705543
const digitsToNumber = +arr.join("") //6145390195186705000
console.log(digits);
console.log(digitsToNumber);
You can see that the join function works. However, when I try to convert it into a number, it shows a weird value. Do you guys know why it happened that way?

As stated in the comments, the value is too large for JavaScript and is truncated.
We can use BigInt to prevent this. Use with caution!
const arr = [6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,3]
const digits = arr.join('');
const digitsToNumber = +arr.join("");
const bigDigitsToNumber = BigInt(arr.join(''));
console.log(digits); // 6145390195186705543
console.log(digitsToNumber); // 6145390195186705000
console.log(bigDigitsToNumber.toString()); // 6145390195186705543

They will log different results because you are exceeding Number.MAX_SAFE_INTEGER - the highest value JS can safely compare and represent numbers.
One method to check if you are ever exceeding the limit (besides remembering the value) is Number.isSafeInteger()
Number.isSafeInteger(digitsToNumber); //false
From the docs: For larger integers, consider using the BigInt type.

To convert your concatenated string into a number you could use parseInt("123") method.
const number= parseInt(digitsToNumber)
However because of your number is too big or could be bigger, Javascript can not handle that numbers which contains more than 16 digit. If you also have a problem like that you can use some external big number libraries like BigNumber.Js.
Edit: According to Teemu's comment, you could also use link native big integer handling library.

Related

Adding two big numbers in javascript [duplicate]

This question already has answers here:
How to deal with big numbers in javascript [duplicate]
(3 answers)
Closed 3 years ago.
I've been trying to add the following numbers using javascript;
76561197960265728 + 912447736
Sadly, because of rounding in javascript it will not get the correct number, I need the number as a string.
I've tried removing the last few digits using substr and then adding the two numbers together and then putting the two strings together, sadly this doesn't work if the first of the number is a 1.
function steamid(tradelink){
var numbers = parseInt(tradelink.split('?partner=')[1].split('&')[0]),
base = '76561197960265728';
var number = parseInt(base.substr(-(numbers.toString().length + 1))) + numbers;
steamid = //put back together
}
steamid('https://steamcommunity.com/tradeoffer/new/?partner=912447736&token=qJD0Oui2');
Expected:
76561198872713464
For doing operations with such big integers, you should use BigInt, it will correctly operate on integers bigger than 2ˆ53 (which is the largest size that normal Number can support on JS
const sum = BigInt(76561197960265728) + BigInt(912447736);
console.log(sum.toString());
Edit 2020: This API still not widely supported by some browsers, so you may need to have a polyfill, please check this library

How to check for exponential values in Javascript

I am streaming data from a CSV file and I am pushing certain values to an array. Some of these values are very large, and may be exported as exponential values (e.g. 5.02041E+12) and some may be normal values.
I'd like to have an if statement that checks to see if these values are exponential or not, and if they are I will pass them to a function that converts them into 'normal' numbers (e.g. 5020410000000). Is there a quick way to do this?
(These values are passed to an API call which is why they need to be converted to 'normal' values)
Example of what this may look like:
valueOne = 5.02041E+12;
valueTwo = 1234;
if (valueOne.isExponential) {
**pass to converting function**
}
//Output = 5020410000000
if (valueTwo.isExponential) {
**pass to converting function**
}
//Output = 1234 (unchanged)
I'd expect all values in the array to therefore be 'normal' values (i.e. NOT is exponential form)
Numbers are numbers, the values 5.02041E+12 and 5020410000000 do not differ internally:
// values in code:
var withe=5.02041E+12;
var withoute=5020410000000;
console.log(withe,"?=",withoute,withe===withoute);
// values parsed from strings:
var stringwithe="5.02041E+12";
var stringwithoute="5020410000000";
var a=parseFloat(stringwithe);
var b=parseFloat(stringwithoute);
console.log(a,"?=",b,a===b);
And you can also see that when you simply display a number, it will not use the scientific notation by default, actually you would have to ask for it via using toExponential()
One thing you can worry about is the internal precision of Number. It has a method isSafeInteger() and various fields, like MAX_SAFE_INTEGER. Surpassing that value can lead to unexpected results:
var a=Number.MAX_SAFE_INTEGER;
console.log("This is safe:",a,Number.isSafeInteger(a));
a++;
for(var i=0;i<5;i++)
console.log("These are not:",a++,Number.isSafeInteger(a));
So the loop can not increment a any further, because there is no such number as 9007199254740993 here. The next number which exists after 9007199254740992 is 9007199254740994. But these numbers are more than 1000x greater than the 5020410000000 in the question.
You can just use toPrecision on every number and ensure it converts
const valueOne = 5.02041E+12;
const valueTwo = 1234;
const precisionValueOne = valueOne.toPrecision(); // "5020410000000"
const precisionValue2 = valueTwo.toPrecision(); // "1234"
You can then, optionally convert it back to numbers:
sanitizedValueOne = Number(precisionValueOne); // 5020410000000
sanitizedValueTwo = Number(precisionValueTwo); // 1234
Do a RegExp match for E+ and probably for E-
The 'number' you are starting with must be text, but you should do a bit of sanity checking too.
Might be a good idea to check whether it is larger than MaxInt before you try any Math-based conversions.

Strange maths while filtering array by elements in another array [duplicate]

This question already has answers here:
How to deal with floating point number precision in JavaScript?
(47 answers)
Closed 4 years ago.
I was trying to remove ids from a new request that have already been requested. In the code below I was expecting for the ...56 id to be removed and only the ...81 id to remain. 56 was removed but to my surprise 81 had been decreased to 80.
const oldIds = [
10032789416531456
];
const newIds = [
10032789435529381,
10032789416531456
];
const result = newIds.filter(newId => !oldIds.some(oldId => oldId === newId));
console.log(result)
//Expected result is: [10032789435529381], instead I get [10032789435529380]
I was able to solve this problem by using strings for ids instead of numbers.
If you type 10032789435529381 in the js console, it returns 10032789435529380. You've exceeded the capacity of the javascript integer, causing it to be treated as a less precise floating point number.
This is part of the reason why using strings for IDs instead of numbers is typically recommended.

Why I can't convert string to number without losing precision in JS?

We all know that +, Number() and parseInt() can convert string to integer.
But in my case I have very weird result.
I need to convert string '6145390195186705543' to number.
let str = '6145390195186705543';
let number = +str; // 6145390195186705000, but should be: 6145390195186705543
Could someone explain why and how to solve it?
Your number is above the Number.MAX_SAFE_INTEGER (9,007,199,254,740,991), meaning js might have a problem to represent it well.
More information
You are outside the maximum range. Check in your console by typing Number.MAX_SAFE_INTEGER
If you want a number outside this range, take a look into BigInt that allows to define numbers beyond the safe range
https://developers.google.com/web/updates/2018/05/bigint
Read the documentation well before using it since the usage is different than usual
I am guessing this is to solve the plusOne problem in leetcode. As others have answered, you cannot store value higher than the max safe integer. However you can write logic to add values manually.
If you want to add one to the number represented in the array, you can use the below function. If you need to add a different value, you need to tweak the solution a bit.
var plusOne = function(digits) {
let n = digits.length, carry=0;
if(digits[n-1]<9){
digits[n-1] +=1;
} else{
digits[n-1] = 0;
carry=1;
for(let i=n-2;i>=0;i--){
if(digits[i]<9){
digits[i]+=1;
carry=0;
break;
}else{
digits[i]=0;
}
}
if(carry>0){
digits.unshift(carry);
}
}
return digits;
};
Short answer: Your string represents a number to large to fit into the JavaScript number container.
According to the javascript documentation the maximum safe number is 2^53 which is 9007199254740992 source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number
When you try and convert your number you're creating an overflow exception so you get weird results.

Working with string (array?) of bits of an unspecified length

I'm a javascript code monkey, so this is virgin territory for me.
I have two "strings" that are just zeros and ones:
var first = "00110101011101010010101110100101010101010101010";
var second = "11001010100010101101010001011010101010101010101";
I want to perform a bitwise & (which I've never before worked with) to determine if there's any index where 1 appears in both strings.
These could potentially be VERY long strings (in the thousands of characters). I thought about adding them together as numbers, then converting to strings and checking for a 2, but javascript can't hold precision in large intervals and I get back numbers as strings like "1.1111111118215729e+95", which doesn't really do me much good.
Can I take two strings of unspecified length (they may not be the same length either) and somehow use a bitwise & to compare them?
I've already built the loop-through-each-character solution, but 1001^0110 would strike me as a major performance upgrade. Please do not give the javascript looping solution as an answer, this question is about using bitwise operators.
As you already noticed yourself, javascript has limited capabilities if it's about integer values. You'll have to chop your strings into "edible" portions and work your way through them. Since the parseInt() function accepts a base, you could convert 64 characters to an 8 byte int (or 32 to a 4 byte int) and use an and-operator to test for set bits (if (a & b != 0))
var first = "00110101011101010010101110100101010101010101010010001001010001010100011111",
second = "10110101011101010010101110100101010101010101010010001001010001010100011100",
firstInt = parseInt(first, 2),
secondInt = parseInt(second, 2),
xorResult = firstInt ^ secondInt, //524288
xorString = xorResult.toString(2); //"10000000000000000000"

Categories

Resources