Skip to content

Instantly share code, notes, and snippets.

@mfikes
Last active February 24, 2024 13:43
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mfikes/9fc981ed7a190b8e9b2912eee98fdd5e to your computer and use it in GitHub Desktop.
Save mfikes/9fc981ed7a190b8e9b2912eee98fdd5e to your computer and use it in GitHub Desktop.
Playing with BigInt in ClojureScript

Usage

Fire up a REPL using any of the following forms.

Node

clj -Srepro -Sdeps '{:deps {org.clojure/clojurescript {:git/url "https://github.com/mfikes/clojurescript" :sha "ed1e7373a9ecd8b52084dc438e6c21d23dba47ca"}}}' -m cljs.main -re node

Graal.JS

clj -Srepro -Sdeps '{:deps {org.clojure/clojurescript {:git/url "https://github.com/mfikes/clojurescript" :sha "ed1e7373a9ecd8b52084dc438e6c21d23dba47ca"}}}' -m cljs.main -re graaljs

Chrome Browser

clj -Srepro -Sdeps '{:deps {org.clojure/clojurescript {:git/url "https://github.com/mfikes/clojurescript" :sha "ed1e7373a9ecd8b52084dc438e6c21d23dba47ca"}}}' -m cljs.main -ro '{:launch-browser false}' -r

and point Chrome at http://localhost:9000 (Use Chrome 67 or later.)

Try Things

Then try some things with arbitrary-precision integers.

cljs.user=> (+ 9007199254740991 2)        ; (+ (.-MAX_SAFE_INTEGER js/Number) 2)
9007199254740992
cljs.user=> (+ 9007199254740991N 2N)
9007199254740993N

Comparing and sorting

cljs.user=> (< 1N 2)
true
cljs.user=> (sort [4N 6N -12N 10 4 0 0N])
(-12N 0 0N 4N 4 6N 10)
cljs.user=> (max 1N 7N 3)
7N

quot, mod and friends

cljs.user=> (quot 17N 3N)
5N
cljs.user=> (rem 17N 3N)
2N
cljs.user=> (mod 17N 3N)
2N
cljs.user=> (js-mod 17N 3N)
2N

bitwise operators

cljs.user=> (bit-shift-right 10N 1N)
5N
cljs.user=> (bit-or 3N 4N)
7N

You can't mix fixed-precision and arbitrary-precision integers like you can in Clojure:

cljs.user=> (+ 1 2N)
TypeError: Cannot mix BigInt and other types, use explicit conversions

but this works

cljs.user=> (+ (bigint 1) 2N)
3N

How Does This Work?

In this branch, ClojureScript has a few simple revisions:

  1. If the Clojure reader produces a clojure.lang.BigInt, ClojureScript is revised to emit that number with an n suffix, which means it is interpreted as a JavaScript BigInt.
  2. When printing JavaScript BigInt values it prints the number with an N suffix.
  3. An implementation of cljs.core/bigint is added, supporting coercion
  4. Support for BigInt in cljs.core/compare when comparing with JavaScript numbers.
  5. Add support for BigInt in interal fix implementation

More Info

@aiba
Copy link

aiba commented Mar 5, 2023

👀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment