ClojureDart icon indicating copy to clipboard operation
ClojureDart copied to clipboard

Create cljd.math namespace

Open brandoncorrea opened this issue 8 months ago • 4 comments

  • Adds port of clojure.math as cljd.math
  • Adds cljd.core functions:
    • unsigned-bit-shift-right
    • NaN?
    • infinite?

test-clojure.numbers and test-clojure.predicates tests are also included for testing unsigned-bit-shift-right and NaN? / infinite? core functions, respectively.

brandoncorrea avatar Apr 24 '25 16:04 brandoncorrea

Thanks! Looks clean. I just need to think more about the semantics we want given Dart loose definition on an int

The default implementation of int is 64-bit two's complement integers with operations that wrap to that range on overflow. Note: When compiling to JavaScript, integers are restricted to values that can be represented exactly by double-precision floating point values. The available integer values include all integers between -2^53 and 2^53, and some integers with larger magnitude. That includes some integers larger than 2^63. The behavior of the operators and methods in the int class therefore sometimes differs between the Dart VM and Dart code compiled to JavaScript. For example, the bitwise operators truncate their operands to 32-bit integers when compiled to JavaScript.

If you have opinions on the matter, we're all ears!

cgrand avatar Apr 24 '25 16:04 cgrand

I noticed the loose integer behavior when working on this. I'm no expert in Dart, so it's very possible there are holes in some of these functions.

My approach with cljd.math was really to mimic the behavior of clojure.math as much as made sense for compatibility. So some of the implementations are naively built (expm1, log1p) and limited by my understanding on how the function is supposed to work (ulp, scalb) just to get something in place without getting too deep into it.

I'm happy to address and include any feedback you have on how some of these ought to work!

brandoncorrea avatar Apr 24 '25 17:04 brandoncorrea

I wonder if MIN and MAX ints should be sniffed. (= 0X20000000000000 0X20000000000001) is true in web/js (I think it would be wrong in web/wasm). AND we have to be sure that neither cljd not dart compilers optimize this out.

cgrand avatar Apr 25 '25 08:04 cgrand

You're right! Looking at the ClojureScript math ns, they use js/Number.MIN_SAFE_INTEGER and js/Number.MAX_SAFE_INTEGER.

I see Dart has js_interop and js_interop_unsafe. You think it's worth utilizing these to get that Number value, or would something hard-coded be better in this case (like the non-js platforms)?

(def ^:private ^int INT-MAX-VALUE
  (if io/Platform.isJS
    0x1FFFFFFFFFFFFF
    0x7FFFFFFFFFFFFFFF))

(def ^:private ^int INT-MIN-VALUE
  (if io/Platform.isJS
    -0x1FFFFFFFFFFFFF
    (- 0x8000000000000000)))

brandoncorrea avatar Apr 26 '25 19:04 brandoncorrea

@brandoncorrea there's no io/Platform.isJS because dart:io doesn't exist on the web target

cgrand avatar May 03 '25 08:05 cgrand

Interesting enough:

  (if some-test
    0x1FFFFFFFFFFFFF
    0x7FFFFFFFFFFFFFFF)

can't compile to web because 0x7FFFFFFFFFFFFFFF would still need to be embedded in the js.

We would need to do the work to leverage "configurable URIs" to be able to do that.

cgrand avatar May 03 '25 17:05 cgrand

@brandoncorrea thanks!

cgrand avatar May 04 '25 20:05 cgrand