Assign -1 to BigInt, but BigInt return 18446744073709552000
See original GitHub issueHi, JSBI is a very good API for me, but I am confused in following case.
In offical web site say
Another thing to note is that the >>> operator, which performs an unsigned right shift, does not make sense for BigInts since they’re always signed. For this reason, >>> does not work for BigInts.
So, I assume the following code should have same result, why they are different?
let max = JSBI.BigInt("0xffffffffffffffff");
console.log(`${JSBI.toNumber(max)} ==? ${max.toString(16)}`);
let num_m1 = JSBI.BigInt("-1");
console.log(`${JSBI.toNumber(num_m1)} ==? ${max.toString(16)}`);
results:
[Log] 18446744073709552000 ==? ffffffffffffffff (main.chunk.js, line 1293)
[Log] -1 ==? ffffffffffffffff (main.chunk.js, line 1295)
Very thanks.
Issue Analytics
- State:
- Created 4 years ago
- Comments:7 (2 by maintainers)
Top Results From Across the Web
Why didn't scala design around Integer Overflow?
In particular it has a SafeLong type that handles arbitrary-precision integers but with much better performance than BigInt for values which ...
Read more >TypeError: can't convert x to BigInt - JavaScript - MDN Web Docs
The JavaScript exception "x can't be converted to BigInt" occurs when attempting to convert a Symbol, null, or undefined value to a BigInt, ......
Read more >PGRES_FATAL_ERROR:ERROR: bigint out of range ...
The current value returned is -1 but Zabbix is still trying to insert this as an unsigned integer (18446744073709552000) which is 20 digits...
Read more >[SOLVED] MySQL unsigned BIGINT issues [Archive]
I know that mixing of signed and unsigned values requires some attention from the programmers side. But in this case, the MySql server...
Read more >SQLite, 64-bit integers, and the impossible number
1 2 3, CREATE TABLE big_numbers (i INTEGER, r REAL, t TEXT, b BLOB); INSERT INTO big_numbers ... so let's see what types...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
I think this is all working as intended.
JSBI.toNumber(max)
performs a to-Number conversion (as the name implies). 0xFFFFFFFFFFFFFFFF cannot be represented as a JavaScript Number, because a 64-bit double doesn’t have enough mantissa bits. So the number you get out is rounded up to 0x10000000000000000. Since the default Number-to-String conversion (which is invoked here under the hood for printing) uses base-10, it shows up in your output as18446744073709552000
.In your second comparison, on the left side the JSBI representation of -1 gets converted to the Number representation of -1, and on the right side you again have the base-16 String representation of
max
.It looks like what you’re looking for is indeed
asIntN
:JSBI.asIntN(64, max).toString()
gives you-1
.Note that “
max
” is a misnomer: this is far from the maximum BigInt. “num_m1
” is also a misnomer because a JSBI instance (or native BigInt) is not a Number.FWIW, all of the above is exactly the same between JSBI and native BigInts:
In summary, there are two things to keep in mind:
asIntN
and the bitwise operations; and some implementations might choose to actually do it that way). FWIW, it also doesn’t apply to floating-point numbers, JavaScript is just really confusing there because it sometimes says that all Numbers are doubles and sometimes pretends that all Numbers are 32-bit signed integers.These functions do not exist; there are only the generic
asIntN
andasUintN
. You can call them asasIntN(64, ...)
orasIntN(65, ...)
orasIntN(13, ...)
, or any otherN
you want.JSBI supports BigInts with any number of bits (from 0 up to some huge maximum, depending on the JavaScript engine you run it on, typically millions or even billions).
In general, no bit in a BigInt is “the signed/unsigned flag”. You can assume that the sign is stored separately from the absolute value. (Whether that’s actually the case in an implementation is an irrelevant implementation detail; conceptually it is always the case.) Only the
asIntN(N, ...)
function pretends that theN
th bit is the sign bit. A library cannot know what you’re going to pass asN
.As the README says, JSBI implements the same functionality as native JavaScript BigInts. Since native BigInts have no unsigned right shift, neither does JSBI. See https://tc39.es/proposal-bigint/.
Unsigned right-shift, also known as zero-extending right shift, really only makes sense when you know that (1) the underlying representation has a fixed and well-known size, and (2) the system you’re running on uses two’s-complement representation for negative values. Neither is the case for BigInts.
Example: in C/C++ on common hardware,
int8_t x = -8
is represented with the bits11111000
. Doing a zero-extending right shift by 2 bits gives00111110
, which is 62 in decimal. If you started with the same value -8 but stored as a 16-bit valueint16_t y = -8
, you’d get1111111111111000b >> 2 == 0011111111111110b
, which is 16382 in decimal. The width of the variable matters. Now if you had a BigInt with value -8, what width would you assume? How many 1-bits should there be? There is no good answer to this, which means there is no good way to define what a “zero-extending right shift” should do for negative BigInts. (For positive BigInts it’s the same as sign-extending right shift anyway.)It is the name used in the BigInt proposal and other places; MDN calls it “sign-propagating right shift”. Just think of the
>>
operator. The key point is that negative values remain negative when they are right-shifted. This creates nice symmetry with positive values:(although do note that rounding is different:
5 >> 1 == 2
but-5 >> 1 == -3
). And this is exactly what both JSBI and native BigInts also do:-4n >> 1n === -2n
,JSBI.signedRightShift(JSBI.BigInt(-4), JSBI.BigInt(1)).toString() === "-2"