Let's say that I needed the user to enter a binary or hexadecimal value and the program would take it from there. Is there a way to differentiate whether the value they entered is binary or hexadecimal?
I thought I had it figured out by checking if the string contained letters or numbers above 1 but what about in the case of 101101 or other similar hex inputs? Is it even possible to know without any other context?
For the sake of including failed attempts I tried the following to check if the string contained letters which hexadecimal values could:
if (Number.isInteger(parseInt(input)))
but other than it not solving the above problem (since hex values don't always have letters), it also fails because it still returns true when letters are mixed into the input as it still parses an integer one way or another.
Is it even possible to know without any other context?
No, it's not. Programming languages often allow number literals in various numeral systems but they have to be marked accordingly. In JavaScript:
No prefix: decimal. Example: 12345
0b prefix: binary. Example: 0b10101
0o prefix: octal. Example: 0o123
0x prefix: hexadecimal. Example: 0x12345
You could require the same notation for the input, or you provide another control that allows the user to choose the system (you could still internal prefix the input correctly).
For completeness, here is a function that would convert any of these inputs to numbers:
const radixTable = {
'0b': 2,
'0o': 8,
'0x': 16,
};
function convert(str) {
let radix = 10;
if (radixTable.hasOwnProperty(str.slice(0, 2))) {
radix = radixTable[str.slice(0,2)];
str = str.slice(2);
}
return parseInt(str, radix);
}
['12', '0b1100', '0o14', '0xC'].forEach(
str => console.log(`${str}:`, convert(str))
);
I'm not aware of JavaScript having a lot of advanced math capabilities built in. If it was oriented toward that end, it would probably have more numeric variable types to give you larger numbers like a double or long. You might want to create an object that would have a property to set whether the number in the object is hex or decimal, and then the value.
let numberObj = {
numberSystem: 'decimal',
value: '4505'
}
Related
From MDN:
JavaScript's String type is used to represent textual data. It is a
set of "elements" of 16-bit unsigned integer values. Each element in
the String occupies a position in the String. The first element is at
index 0, the next at index 1, and so on. The length of a String is the
number of elements in it. You can create strings using string literals
or string objects.
What does it mean when you say the JavaScript String type is a set of "elements" of 16-bit unsigned integer values?
Please explain why it is a series of integer values.
The 16-bit unsigned integer values is a representation of specific characters and since it is a set of elements, you are able to grab specific characters within a string with [] notation as you would a list. Ex:
const string = 'john doe';
console.log(string[3]) // Will print 'n' as it is the 3rd index characters (starts at 0)
It just means that a string is an "array-like" object with each character available in a similar manner to an array element. Each of those characters are stored as a UTF-16 value.
// The following is one string literal:
let s = "ABCDEFG";
console.log(s);
// But it's also an array-like object in that it has a length and can be indexed
console.log("The length of the string is: ", s.length);
console.log("The 3rd character is: ", s[2]);
// And we can see that the characters are stored as separate UTF-16 values:
console.log(s.charCodeAt(2));
As I understood:
unsigned means not + or -.
16 bit means 2^16 number of elements/characters can represent.
set of Integers mean to represent a String use multiple integers (1 or more).
Therefore this means to represents a string, JavaScript uses a set of numbers (each number is one of 2^16 numbers, because no float numbers and no positive/negative representation).
Note: to understand more read about UTF-16
Reference: UTF-16 (IBM)
In Unicode, each symbol has an associated number. For example, "A" is 65, "a" is 97, etc. These numbers are called code points. Depending on the encoding we’re using (UTF-32, UTF-16, UTF-8, ASCII, etc.), we represent/encode these code points in different ways. The things we use to encode these code point numbers are called "code units", or as MDN calls them, "elements".
As we're using JavaScript, we're interested in the UTF-16 encoding of characters. This means that to represent a single code unit/"element", we use 16 bits (two bytes). For "A", the "element" representation is:
0000000001000001 // (16 bits, hence 0 padding)
There are a lot of characters that we need to represent (think emojis, Chinese, Japanese, Korean scripts, etc. that each have their own code points), so 16 bits to represent and encode all of these characters alone isn't enough. That's why sometimes some code points are encoded using two code units/elements. For example, 😂 has a code point of 128514 and in UTF-16 is encoded by two elements/code units:
1101100000111101 1101111000000010
So these two code units/elements 1101100000111101 (decimal 55357) and 1101111000000010 (decimal 56834) encode the code point/"character" of 128514 which represents 😂. Notice how both code units are both positive (unsigned), and are whole numbers (integers). UTF16 outlines the algorithm to take these elements from the element form to their code point form and vice-versa (see here for examples).
What are the implications of all this? Well it means that strings like "😂" will have a length of 2:
console.log("😂".length); // 2
And that when you access the indexes of the string, you will access the code units/"elements" of that string:
// "😂" in UTF16 is "1101100000111101 1101111000000010"
// So "😂"[0] gives 1101100000111101 (in decimal 55357)
// So "😂"[1] gives 1101111000000010 (in decimal 56834)
console.log("😂"[0], "😂".charCodeAt(0)); // 1101100000111101
console.log("😂"[1], "😂".charCodeAt(1)); // 1101111000000010
I want to define a BigInt number in JavaScript. But when I assign it, the wrong number is stored. In fact 1 is added to the number when storing.
let num = BigInt(0b0000111111111111111111111111111111111111111111111111111111111111)
console.log(num) // Output: 1152921504606846976n
console.log(num.toString(2)) // Output: 1000000000000000000000000000000000000000000000000000000000000
So the number stored is 1152921504606846976, but it should be 11529215046068469765. Why is that?
Converting a Number to a BigInt can't create bits that weren't there before.
0b1 (just like 1) is a Number literal, so it creates a Number.
0b1n (just like 1n) is a BigInt literal, so it creates a BigInt.
By writing BigInt(0b1), you're first creating a Number and then converting that to a BigInt. As long as the value is 1, that works just fine; once the value exceeds what you can losslessly store in a Number [1], you'll see that the value of the final BigInt won't match the literal you wrote down. Whether you use binary (0b...), decimal, or hex (0x...) literals doesn't change any of that.
(And just to be extra clear: there's no reason to write BigInt(123n), just like you wouldn't write Number(123). 123n already is a BigInt, so there's nothing to convert.)
A simple non-BigInt way to illustrate what's happening is to enter 12345678901234567890 into your favorite browser's DevTools console: you can specify Number literals of any length you want, but they'll be parsed into an IEEE754 64-bit "double", which has limited precision. Any extra digits in the literal simply can't be stored, though of course each digit's presence affects the magnitude of the number.
[1] Side note: this condition is more subtle than just saying that Number.MAX_SAFE_INTEGER is the threshold, though that constant is related to the situation: any integral number below MAX_SAFE_INTEGER can be stored losslessly, but there are plenty of numbers above MAX_SAFE_INTEGER that can also be represented exactly. Random example: 1e20.
I got a number 1267508826984464384 from json response. Here i print the number.
<script>
var num = 1267508826984464384;
console.log(num);
var num = "1267508826984464384";
console.log(num);
</script>
output is
In the first print the output is different from the original value. I need the same value as given.
Is it possible?
JavaScript uses floating point under the hood to store numbers. Floating point double precision, which is what JavaScript uses, can only store 64 bits of data. With the way numbers are represented in this manner, this means that there's a limit to how big a Number can normally be (2^53 - 1 for double precision floating point). Your number in the example has gone over this limit (overflow) and hence is being rounded by JavaScript.
You can use BigInt:
var num = BigInt(1267508826984464384);
console.log(num); // logs 1267508826984464384n, with n representing that it's a BigInt type
var num = "1267508826984464384";
console.log(num); // logs 1267508826984464384
May be helpful to read What Every Programmer Should Know About Floating-Point Arithmetic for more information on why this is the case.
They are different types (int and string, respectfully). What you are seeing in the top example is integer overflow (safely abstracted by JS). You can use a big integer to bypass this issue
const hugeString = BigInt("1267508826984464384")
console.log(hugeString + 1n) // 1267508826984464385n
The type of this is BitInt and it will safely allow you to represent your number as a integer. This type must be treated different and the additions must also be BigInt (as shown in the example above).
BigInt is a built-in object that provides a way to represent whole numbers larger than 253 - 1, which is the largest number JavaScript can reliably represent with the Number primitive and represented by the Number.MAX_SAFE_INTEGER constant. BigInt can be used for arbitrarily large integers.
From MDN. You can use it like so:
const theBiggestInt = 9007199254740991n
const alsoHuge = BigInt(9007199254740991)
// ↪ 9007199254740991n
const hugeString = BigInt("9007199254740991")
// ↪ 9007199254740991n
const hugeHex = BigInt("0x1fffffffffffff")
// ↪ 9007199254740991n
const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111")
// ↪ 9007199254740991n
RegEx for finding numbers and quoting them. Looks for prop value boundaries and a sequence of digits and optionally one period, and replaces inserting with quotes around the number value.
RegEx should be adjusted for maximum length or tolerances for numbers to be quoted as strings.
key or value prefix/suffix can be added, so that a JSON.parse reviver function can recognize them and parse to big.js or BigInt.
In most cases, you probably already know if you might receive a large number, and could probably just use a trivial RegEx replace on the specific property you need.
And, you should be coordinating with the server-side to give the data to you in another form that is safe to consume.
Parsing number strings using BigInt and big.js.
str = String.raw `{"j\"son":1234561251261262131231231231231231231231231232123123123,
"array":
[123123123124124214124124124124.111,
124124124124124124124124124,
124124124124124124124124
]}
`
str = str.replace(/((?:{|,|\[)\s*(?:"(?:[^"]|\\")+"\s*:\s*)?)(\d+\.?\d*)(\s*)(?=,|}|\])/g, `$1"$2"$3`)
// note: capture group $3 is just whitespace, which can normally be ignored; included to be "technically accurate"
console.log(
str,
(BigInt(JSON.parse(str)[`j"son`]) + 1n).toString(),
(Big(JSON.parse(str).array[0]).plus(0.0003)).toFixed()
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/big.js/5.2.2/big.min.js" integrity="sha256-gPNmhPlEOUlyAZomtrYRW/HSIjBOOl2LVxft3rsJpxI=" crossorigin="anonymous"></script>
My problem is really simple but I'm not sure if there's a "native" solution using JSON.parse.
I receive this string from an API :
{ "key" : -922271061845347495 }
When I'm using JSON.parse on this string, it turns into this object:
{ "key" : -922271061845347500 }
As you can see, the parsing stops when the number is too long (you can check this behavior here). It has only 15 exact digits, the last one is rounded and those after are set to 0. Is there a "native" solution to keep the exact value ? (it's an ID so I can't round it)
I know I can use regex to solve this problem but I'd prefer to use a "native" method if it exists.
Your assumption that the parsing stops after certain digits is incorrect.
It says here:
In JavaScript all numbers are floating-point numbers. JavaScript uses
the standard 8 byte IEEE floating-point numeric format, which means
the range is from:
±1.7976931348623157 x 10308 - very large, and ±5 x 10-324 - very small.
As JavaScript uses floating-point numbers the accuracy is only assured
for integers between: -9007199254740992 (-253) and 9007199254740992
(253)
You number lies outside the "accurate" range hence it is converted to the nearest representation of the JavaScript number. Any attempt to evaluate this number (using JSON.parse, eval, parseInt) will cause data loss. I therefore recommend that you pass the key as a string. If you do not control the API, file a feature request.
The number is too big to be parsed correctly.
One solution is:
Preprocessing your string from API to convert it into string before parsing.
Preform normal parsing
Optionally, you could convert it back into number for your own purpose.
Here is the RegExp to convert all numbers in your string (proceeded with :) into strings:
// convert all number fields into strings to maintain precision
// : 922271061845347495, => : "922271061845347495",
stringFromApi = stringFromApi.replace(/:\s*(-?\d+),/g, ': "$1",');
Regex explanation:
\s* any number of spaces
-? one or zero '-' symbols (negative number support)
\d+ one or more digits
(...) will be put in the $1 variable
I was wondering why do people have to convert numbers to string. What are the practical uses for that kind of conversion?
Similarly why do developers use parseInt or parseFloat to convert a string to a number.
thanks
The variable’s data type is the JavaScript scripting engine’s interpretation of the type of data that variable is currently holding. A string variable holds a string; a number variable holds a number value, and so on. However, unlike many other languages, in JavaScript, the same variable can hold different types of data, all within the same application. This is a concept known by the terms loose typing and dynamic typing, both of which mean that a JavaScript variable can hold different data types at different times depending on context.
With a loosely typed language, you don’t have to declare ahead of time that a variable will be a string or a number or a boolean, as the data type is actually determined while the application is being processed. If you start out with a string variable and then want to use it as a number, that’s perfectly fine, as long as the string actually contains something that resembles a number and not something such as an email address. If you later want to treat it as a string again, that’s fine, too.
The forgiving nature of loose typing can end up generating problems. If you try to add two numbers together, but the JavaScript engine interprets the variable holding one of them as a string data type, you end up with an odd string, rather than the sum you were expecting. Context is everything when it comes to variables and data types with JavaScript.
Using parseInt and parseFloat is important if you want to do arithmetic operations on a number which is in string form. For example
"42" + 1 === "421"
parseInt("42") + 1 === 43;
The reverse is true when you want to do string operations on values which are currently a number.
42 + 1 === 43
(42 + "") + 1 === 421
Why one would want to do the former or latter though is very scenario specific. I'd wager the case of converting strings to numbers for arithmetic operations is the more prominent case though.
An example of when converting numbers to strings is useful is when you want to format the number a certain way, perhaps like a currency (1234.56 -> $1,234.56).
The converse is useful when you want to do arithmetic on strings the represent numbers. Say you have a text box were you allow the user to input a number. The value of that text box will be a string, but you need it as a number to do some arithmetic with it, so you would use parseInt and parseFloat.
string -> number:
Think about simple number validation using JS. if you can convert a string into a number, then you can validate that number before posting to a number, or for use in an arithmetic operation.
number -> string:
String concatenation mainly and display purposes. The language will most often use implicit conversion to convert the number into a string anyway, such as:
1 + " new answer has been posted"
Do remember, Javascript is a loosely typed language. This can hide a lot of implicit type-casting that is occurring.