JS Regex says Number contains a '.' but there is none - javascript

On this page, https://emperorbob7.github.io/JSheets/, I have a function called TYPE, syntax for it is linked on the page, the RegEx used for the decimal detection function is located in codeblock below*
Once I put in too many numbers however, the TYPE says the cell contains a decimal despite none being there. Is this an automatic function that adds a . whenever a number exceeds a certain limit?
Example case: 3123123123123123123122312312312
Output: Decimal
Edit:
function TYPE() {
const regex = /\.[0-9]/;
if(arguments[0] == "true" || arguments[0] == "false")
return "Boolean";
if(isNaN(arguments[0]))
return "String";
else if(regex.test(arguments[0]))
return "Decimal";
else
return "Integer";
}
Code^ Sorry for not posting it before, will keep it in mind for the future.
Sorry for the badly worded question, thanks in advance

You have an integer that is larger than the Number object can handle (see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER), so when it's converted to a string for the regex it becomes an exponential value.
Try console.log(3123123123123123123122312312312); and you will get 3.123123123123123e+30
Or
let val = 3123123123123123123122312312312;
val.toString();
"3.123123123123123e+30"
You can also test your value with Number.isSafeInteger(3123123123123123123122312312312);, which returns false.
The solution is to use Number.isInteger(); as your test instead of a regex. It correctly returns true for your large number.
See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger

Javascript can only store integers up to 9007199254740991 safely. Beyond that, javascript may convert the number to power notation (i.e., 5000000000000000000000 becomes 5e+21) or start converting digits into zeros for storage.
var n = 3123123123123123123122312312312;
console.log(n);
/* Output: 3.123123123123123e+30 */
You can use Number.isSafeInteger() to test whether the number is within the safe range, and then apply your original code to it in that case. If not, you can perform a different test (such as a test against /\d\.\d+e\+\d+ ) to see whether the decimal included is due to exponent notation.
Also be aware that a number in exponent notation will test true using Number.isInteger(), even if it was a floating point to begin with, as that information will be lost.
var x_int = 3123123123123123123122312312312;
var x_flt = 3123123123123123123122312312312.333333333;
console.log( x_int === x_flt);
/* Output: true */
console.log(Number.isInteger(x_flt));
/* Output: true */

Related

Why does converting a negative string into a number ( +"-2.333" ) return NaN, only when the string came from d3.format function?

I am using d3-format's format function to round some numbers (yes, I know this isn't necessary).
When I format negative numbers, I get a string of a negative number, as expected. However, when I convert it back into a number using the + shorthand, it returns NaN. This is not what should happen. I should get back a regular negative number.
import {format} from "d3-format"; //version 3.1.0
let numberFormatter = d3.format(".3f");
let neg = -2.333;
let negString = "-2.333";
let d3negString = numberFormatter(neg);
//the strings look the same
console.log(d3negString) // "-2.333"
console.log(negString) // "-2.333"
//both strings have the same type of 'string'
console.log(typeof negString === typeof d3negString); // true
//but they are not equal
console.log(negString === d3negString); // false
//normal strings work as expected
console.log(isNaN(+negString)); // false
//but strings from d3-format function returns NaN
console.log(isNaN(+d3negString)); // true
It says that both strings have the same type 'string', however their values are not equal?? Even though the text is equal?
What is the true type of d3-formatted number strings? They can't just be normal strings, right? Why is it returning NaN? Is this a bug?
MacOS Big Sur
Chrome 96.0.4664.110
d3-format#3.1.0
The change log of d3, shows that in version 2.0.0 the following was changed:
Change the default minus sign to the minus sign (−) instead of hyphen-minus (-).
In this thread on D3's github are some interesting comments:
D3 did use the minus sign originally, but people complained about that, too (e.g., #595), primarily because there was an expectation that d3.format would use the same symbol as JavaScript’s number.toString. The minus sign was thus replaced with hyphen-minus in 2.10.0 (da3131c, #756).
And:
This is now available as an opt-in by specifying the locale’s minus property. And I’m considering making the minus sign the default (again) in the next major version.
The reason this doesn't work is because the 'minus' characters, despite appearing identical, are different unicode symbols.
Luckily, d3 provides a way to change the default minus character to whatever you choose using the formatLocale function.]
'HYPHEN-MINUS' U+002D unicode character is recognized as a 'negative sign'.
// import {format} from 'd3-format' //do not directly import format with default settings
import { formatLocale} from "d3-format"
const format = formatLocale({ minus: "\u002D"}).format
let numberFormatter = d3.format(".3f");
let neg = -2.333;
let negString = "-2.333";
let d3negString = numberFormatter(neg);
console.log(d3negString) // "-2.333"
console.log(negString) // "-2.333"
console.log(typeof negString === typeof d3negString); // true
console.log(negString === d3negString); // true
console.log(isNaN(+negString)); // false
console.log(isNaN(+d3negString)); // false
The larger moral of the story is that d3-format's goal is NOT to round numbers - it is to make number look nice as text. To prevent problems, use Math.round() or "-2.3333".toFixed(3) // => -2.333 to round numbers in javascript.

Determine precision of number, including trailing zeros

I suspect that this isn't possible, but giving it a try:
Is it possible to determine the number of decimal points of a number, whether or not those decimal points are trailing zeros?
getPrecision(3) // 0
getPrecision(3.2) // 1
getPrecision(2.30) // 2
I've found a couple of solutions for the first two cases (including this: How do I get the decimal places of a floating point number in Javascript?) but nothing for the last case. Converting 3.20 to a string results in "3.2", which doesn't help, and I'm about out of ideas.
Yes, this is possible but only with a trick
First of all, as per your problem statement, if you ask javascript to split and count your float value into 2 integers then it won't include trailing 0s of it.
Let's satisfy our requirement here with a trick ;)
In the below function you need to pass a value in string format and it will do your work
function getPrecision(value){
a = value.toString()
console.log('a ->',a)
b = a.split('.')
console.log('b->',b)
return b[1].length
getPrecision('12.12340') // Call a function
For an example, run the below logic
value = '12.12340'
a = value.toString()
b = a.split('.')
console.log('count of trailing decimals->',b[1].length)
That's it! Just pass your float value in string format and you are done!
Thank you!

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.

Is there a way to distinguish integers from very near decimals in Javascript?

Look at those evaluations (actual dump from node 0.10.33)
> parseFloat(2.1e-17) === parseInt(2.1e-17)
false
> parseFloat(2.1e-17 + 2) === parseInt(2.1e-17 + 2)
true
> parseFloat(2.000000000000000000000000000000000009) === parseInt(2.00000000000000000000000000000000000009)
true
How can I tell integers from decimals very near to integers?
It seems that JS (or at least V8) doesn't care about digits smaller than 10^-16 when doing calculations, even if the 64bit representation used by the language (reference) should handle it.
Your examples are pretty much straight forward to explain. First thing to note is, that parseInt() and parseFloat() take a string as an input. So you inputs first get converted to string, before actually getting parsed.
The first is easy to see:
> parseFloat(2.1e-17) === parseInt(2.1e-17)
false
// look at the result of each side
parseFloat(2.1e-17) == 2.1e-17
parseInt(2.1e-17) == 2
When parsing the string "2.1e-17" as integer, the parse will stop at the dot as that is no valid digit and return everything it found until then, which is just 2.
> parseFloat(2.1e-17 + 2) === parseInt(2.1e-17 + 2)
true
// look at the result of each side
parseFloat(2.1e-17 + 2) == 2
parseInt(2.1e-17 + 2) == 2
Here the formula in the parameter will be evaluated first. Due to the limitations of floating point math (we just have 52bit for the mantissa and can't represent something like 2.000000000000000021), this will result in just 2. So both parseX() function get the same integer parameter, which will result in the same parsed number.
> parseFloat(2.000000000000000000000000000000000009) === parseInt(2.00000000000000000000000000000000000009)
true
Same argument as for the second case. The only difference is, that instead of a formula, that gets evaluated, this time it is the JavaScript parser, which converts your numbers just to 2.
So to sum up: From JavaScript's point of view, your numbers are just the same. If you need more precision, you will have to use some library for arbitrary precision.
This is something I learned from ReSharper
instead of using expressions like
if (2.00001 == 2) {}
try
if (Math.abs(2.00001 - 2) < tolerance) {}
where tolerance should be an aceptable value for you for example .001
so all values wich difference is less than .001 will be equals
Do you really need 10^-16 precision I mean that is why 1000 meter = 1 kilometer, just change the unit of the output so you dont have to work with all those decimals

Fastest way to check if a JS variable starts with a number

I am using an object as a hash table and I have stuffed both regular properties and integers as keys into it.
I am now interested in counting the number of keys in this object which are numbers, though obviously a for (x in obj) { if (typeof x === "number") { ... } } will not produce the result I want because all keys are strings.
Therefore I determined that it is sufficient for my purposes to assume that if a key's first character is a number then it must be a number so I am not concerned if key "3a" is "wrongly" determined to be a number.
Given this relaxation I think i can just check it like this
for (x in obj) {
var charCode = x.charCodeAt(0);
if (charCode < 58 && charCode > 47) { // ascii digits check
...
}
}
thereby avoiding a regex and parseInt and such.
Will this work? charCodeAt is JS 1.2 so this should be bullet-proof, yes?
Hint: I would love to see a jsperf comparing my function with what everyone comes up with. :) I'd do it myself but jsperf confuses me
Update: Thanks for starting up the JSPerf, it confirms my hope that the charCodeAt function would be executing a very quick piece of code reading out the int value of a character. The other approaches involve parsing.
parseInt(x, 10) will correctly parse a leading positive or negative number from a string, so try this:
function startsWithNumber(x) {
return !isNaN(parseInt(x, 10));
}
startsWithNumber('123abc'); // true
startsWithNumber('-123abc'); // true
startsWithNumber('123'); // true
startsWithNumber('-123'); // true
startsWithNumber(123); // true
startsWithNumber(-123); // true
startsWithNumber('abc'); // false
startsWithNumber('-abc'); // false
startsWithNumber('abc123'); // false
startsWithNumber('-abc123'); // false
Why speculate when you can measure. On Chrome, your method appears to be the fastest. The proposed alternatives all come at about 60% behind on my test runs.
The question is misleading because it is hard to tell this of a variable's name but in the example you're dealing with object properties (which are some kind of variables of course...). In this case, if you only need to know if it starts with a number, probably the best choice is parseInt. It will return NaN for any string that doesn't start with a number.
You could also use isNaN(x) or isFinite(x) - see this SO question

Categories

Resources