8 ms·
BigInt: Arbitrary precision integers in JavaScript
- johnsonjo 8y agoSince this is stage 3 this means browsers are beggining to implement it. If you want to try it Chrome has had it since version 67 [1]. [1]: https://developers.google.com/web/updates/2018/05/bigint https://developers.google.com/web/updates/2018/05/bigint
- TeMPOraL 8y agoNot trying to be too snarky, but does that mean that JavaScript is going to be the first language that gets bigints before getting actual integers? How is that a reasonable sequence of steps in language evolution?
- matharmin 8y agoHow is a bigint not an actual integer? If you mean restricting it to a certain number of bits - there are many other languages avoid exposing the low-level system details like that. Python and Ruby are two easy examples, and I'm sure there are many more.
- TeMPOraL 8y agoHaving an abstraction that transparently switches between fixnums and bignums is fine. This is what Ruby or Python or Lisp languages do. And the abstraction is purposefully a thin one - no one is really hiding that there's fixed-bits integers underneath, because this distinction has huge performance implications.
- olliej 8y agoThat isn’t fair - JavaScript has numbers, that are already used on billions of sites, so that can’t be broken. An important part of evolving a language that is always transmitted as source code is that you can’t break the existing code. Python tried with python 3 - that attempted break now means all systems have python 2 and python 3 installed, and there are libraries that can’t be used together because they have different language versions. C and C++ can change the language in breaking (-ish) ways, because changing the language syntax or semantics doesn’t effect shipping (eg compiled) programs. It also has a full set of 32 bit operations - “64 bit” used to be “big int” and required software implementations. The choice to only support floating point numbers also makes sense - you have a dynamic language with no type annotations, so you can’t distinguish between 1(an int) and 1(not an int), and as a result you can’t determine whether a given arithmetic operation should be the integer version or the floating point one. So floating point makes the most sense, unless you want arbitrary precision floating point, which just isn’t feasible for performance or sanity reasons. Especially a few decades ago. So we get bigint- or more correctly arbitrary precision int. That has a distinctly different use case from regular arithmetic numbers, and so is always a distinct type. So yeah, going floating point, and then bigint is a perfectly reasonable evolution of the language. As an aside, I don’t think it’s first because I believe python uses arbitrary precision ints, or floating point. Haskell defaults to arbitrary precision as well (although it supports fixed precision ints as well).
- TeMPOraL 8y ago> JavaScript has numbers, that are already used on billions of sites, so that can’t be broken. For purposes of doing silly things in browsers, sure. But then someone wants to count money with it, and you suddenly have articles on HN about it, and half of their points can be summarized by "watch out for floating point errors". In the rest of industry, the rule of thumb is, "don't use floats for money". > The choice to only support floating point numbers also makes sense - you have a dynamic language with no type annotations, so you can’t distinguish between 1(an int) and 1(not an int), and as a result you can’t determine whether a given arithmetic operation should be the integer version or the floating point one. No, it doesn't (at least not for those reasons). Dynamic languages aren't untyped; in those languages, it's the values that have types. I may not know when reading the code whether x has a float value or string value, but I can query for that at runtime. The way to tell whether or not 1 is an int or a float should be by means of functions like is_int() or is_float(). Sane programming languages handle this fine (hint: writing 1 usually means you want an int, writing 1.0 suggests floating point). Hell, even PHP can handle this fine. At this point I hope that whoever implements bigints in JS realizes that "small" bigints like 123n can be implemented as actual machine integers for much performance gain, and this way we'll get fixnums through a back door.
- mschuetz 8y agoJavascript number type can be used like 32 bit integers for the most part, including bitwise operators and modulus. I agree that pure 32 and 64 bit integers would be nice, though. Especially since I have need for 64 bit bitwise integer math. Bigint surprisingly seems to be able to do that, I'm just not sure if the performance will be okay. But being able to use bigints with binary literals is awesome: 123n & 0b1111n => 11n
- ThrowMeDown01 8y ago> before getting actual integers Javascript has always had "actual integers". As long as you stay within Number.MIN_SAFE_INTEGER...Number.MAX_SAFE_INTEGER (-9007199254740991..9007199254740991) the internal representation is an integer representation. http://2ality.com/2013/10/safe-integers.html http://2ality.com/2013/10/safe-integers.html
- deleted 8y ago[deleted]
- plopz 8y agoTo get the operators to actually work correctly you need to use typed arrays however. For example let a = new Uint32Array(3); a[0] = 5; a[1] = 2; a[2] = a[0]/a[1]
- falcrist 8y agoShouldn't this be called either "arbitrary size integers" or "arbitrary precision integer arithmetic"? Integers by definition already have infinite precision...
- olliej 8y agoDomain terminology - integer on a computer means fixed precision. BigInt is for whatever reason the most common name used
- falcrist 8y agoInteger in all programming languages I've seen so far means infinite precision with limited range. Floating point numbers are used for values that have finite precision but typically much larger range. I guess I'm making a distinction between precision and range. I was pretty sure they couldn't be used interchangeably. Now I'm seeing "precision" being used to describe the size of the integer. I feel like that's a bit of a misnomer.
- rocqua 8y agoJavascript actually uses floats to describe integers, so with very large integers, you actually lose precision. This does 2 things. It allows for arbitrary size integers (whereas before, javascript had integers up to FLOAT.MAX), and it represents all these integers with perfect precison.
- falcrist 8y agoAs someone mostly stuck in the C, C++, C#, assembly, and BASIC, this is new to me. In those languages, an integer is actually infinite precision with limited range. A quick Google shows that the "number" primitive in JavaScript is a double. Are you telling me JavaScript has NO integer type? Maybe I haven't seen enough languages yet, but that seems pretty crazy to me.
- rocqua 8y agoI agree with you on all points. I don't think I've ever written more than 100 lines of javascript. And a lot more of the C like stuf. Yet, I do see the morbid sense in only using floats.
- coke12 8y agoWhat is the value of JSON.parse(JSON.stringify(BigInt(Number.MAX_SAFE_INTEGER) + 2n))? > Finally, BigInts cannot be serialized to JSON. Hmm, ok. I guess that's fine. But what about large numbers coming from over the network? Can we get a BigInt-aware JSON.parse() standardized ASAP?
- olliej 8y agono. This is not related to parsing, it’s related to the JSON format. JSON is a stable interchange format, and for that reason we’ve got a huge base of tooling that uses and emits it. It’s all interoperable because there is just that one syntax. So if you say “add JSON.parse() API”, you’re saying “I want to transmit non-Json strings but claim they’re json “. That breaks: * old browsers - not supporting bigints would mean they couldn’t parse any of your “json” data, even if you weren’t using the bigints. Eg feature detection wouldn’t work. * all shipped products that read json, because as with the browsers they could not parse any “json” that contained invalid data. [edit: Ok, let's try to do something about the endless downvotes: Say you do JSON.parse("9007199254740994") - 2^53+2 Should this parse to a BigInt or a Number? In JavaScript today it will parse as a Number, without losing precision, but it is beyond the range of exactly representable integers in JS. You can see this by doing console.log(9007199254740995) and see that the output is 9007199254740996. So what happens if I do that following: JSON.parse("[9007199254740992, 9007199254740993, 9007199254740994, 9007199254740995]")? the first and third are exactly representable as a double, the second and forth are not. So should this parse as Number, BigInt, Number, BigInt? Or BigInt, BigInt, BigInt, BigInt? What value should be the trigger for treating an integer as a BigInt vs. a Number? What if we're doing JSON.parse("[9007199254740992, 9007199254740993, 9007199254740994, 9007199254740995]").map(x=>x+2) If any of the values get interpreted as a BigInt this will throw. But in existing browsers it won't. ]
- deathanatos 8y ago> It’s all interoperable because there is just that one syntax. And that syntax and specification leaves open the possibility of arbitrary precision integers. From the JSON RFC[1]: > This specification allows implementations to set limits on the range and precision of numbers accepted. Those limits vary by implementation. The subsequent paragraphs warn, of course, that not all implementations support sending or receiving numbers outside of certain ranges, and explicitly calls out the contiguous integer range of an IEEE double as a good range for good interoperability. > “I want to transmit non-Json strings but claim they’re json “. Those strings are already JSON. There are serializers out there that support arbitrary precision integers. Python, for example, will happily serialize such integers: In [6]: json.dumps(2 ** 512) Out[6]: '13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096' (This will parse in today's browsers, too, but you'll get an imprecise result, as JavaScript's Number cannot represent that value exactly. Larger numbers result in Infinity.) [1]: https://tools.ietf.org/html/rfc8259#section-6 https://tools.ietf.org/html/rfc8259#section-6
- qwerty456127 8y agoWhat about BigDecimal?
- Aardwolf 8y agoI wonder the same. The readme says: "The / operator also work as expected with whole numbers. However, since these are BigInts and not BigDecimals, this operation will round towards 0, which is to say, it will not return any fractional digits." What BigDecimal are they referring to? I don't find any tc39 big decimals, only third party libraries
- thomasfoster96 8y agoThere isn’t a BigDecimal proposal anywhere, the authors are just making it clear that their proposal is limited to integers.
- qwerty456127 8y ago> There isn’t a BigDecimal proposal anywhere Why? I find it so weird there still is no BigDecimal in JavaScript.
- JeremyBanks 8y agoIt is relative common for software to need integers larger than 53 bits. It seems quite uncommon for software to require Decimal arithmetic. Do you have a motivating example?
- qwerty456127 8y agoAnything that deals with money. Every e-commerce or fintech app.
- thomasfoster96 8y agoI actually didn’t look hard enough: there is a proposal[0] for something that could be called ‘BigDecimal’ in ECMAScript, but it’s a stage 0 proposal[1]. As for why a decimal type hasn’t progressed further in ECMAScript you’ll want to read the notes [2] from the meeting where the latest proposal was discussed. [0] https://docs.google.com/presentation/d/1jPsw7EGsS6BW59_BDRu9o0o3UwSXQeUhi38QG55ZoPI/edit?pli=1 https://docs.google.com/presentation/d/1jPsw7EGsS6BW59_BDRu9... [1] https://github.com/tc39/proposals/blob/master/stage-0-proposals.md https://github.com/tc39/proposals/blob/master/stage-0-propos... [2] https://github.com/rwaldron/tc39-notes/blob/b8da60318b564f136cbe8385f17f42abc0666cdd/es8/2017-11/nov-29.md#9ivb-decimal-for-stage-0 https://github.com/rwaldron/tc39-notes/blob/b8da60318b564f13...
- Schampu 8y agoI use them in a Vulkan API for node.js to handle 64bit interopability when mapping Vulkan memory. Mapping Vulkan memory returns you a numeric address to the memory region. To handle the address I use BigInt, which can then be used to create an ArrayBuffer as a direct JS-side memory view where you can write e.g. your texture data into. See [0] how its used on node-side and [1] the C++ implementation using the V8 API [0] https://github.com/maierfelix/node-vulkan/blob/master/examples/cube/buffer.mjs#L1-#L7 https://github.com/maierfelix/node-vulkan/blob/master/exampl... [1] https://github.com/maierfelix/node-vulkan/blob/master/generated/1.1.85/src/index.cpp#L21-#L34 https://github.com/maierfelix/node-vulkan/blob/master/genera...
- gcbirzan 8y agoSo, you can add a string to a BigInt, but not a Number? Their 'explanation' for not allowing Number and BigInt to be mixed is that you could lose precision. Not if you return a BigInt.
- deleted 8y ago[deleted]
- maxxxxx 8y agoThat seems a pretty odd choice in both cases. Adding a number to BigInt should return a BigInt. I am also always wary of languages that allow mixing of strings and numbers. From my experience this can cause a lot of problems.
- gcbirzan 8y agoIt's hilarious, because: "1" + 1 === "11" "1" - 1 === 0 "1" + 1n === "11" "1" - 1n: Exception
- maxxxxx 8y agoOur testers write a lot scripts in PHP and I have spent countless hours debugging stuff like this. A special kind of fun is to figure out what expressions count as TRUE or FALSE. JavaScript seems to have the same, slightly different, problems.
- z3t4 8y agoHopefully JavaScript will get a new Number system before 2038, which is the new Y2k problem.