On Fri, Mar 4, 2011 at 6:43 AM, Joost <jo...@zeekat.nl> wrote:
> On Mar 2, 2:05 am, Jason Wolfe <ja...@w01fe.com> wrote:
>> > But I don't know what the plan is if you really do want truncating
>> > arithmetic on longs.
>>
>> On 1.3 alpha 4:
>>
>> user=> (+ Long/MAX_VALUE Long/MAX_VALUE)
>> ArithmeticException integer overflow
>> clojure.lang.Numbers.throwIntOverflow (Numbers.java:1581)
>>
>> user=> (set! *unchecked-math* true)
>> true
>>
>> user=> (+ Long/MAX_VALUE Long/MAX_VALUE)
>> -2
>
> Looks good, only it doesn't seem to work for division:
>
> (set! *warn-on-reflection* true)
> (set! *unchecked-math* true)
> (/ 1 2)
>
> Reflection warning, NO_SOURCE_FILE:1 - call to divide can't be
> resolved.
> 1/2
>
> What I want in this particular program is a truncating, unchecked
> division on longs, but there doesn't seem to be any way of getting
> that using these constructs. Even for ints you need to explicitly call
> unchecked-divide-int:
>
> (/ (int 1) (int 2))
> Reflection warning, NO_SOURCE_FILE:1 - call to divide can't be
> resolved.
> 1/2
>
> (unchecked-divide-int (int 1) (int 2))
> 0
>
> I'm guessing the problem here is that compared to the other unchecked*
> functions, unchecked-divide-int does two additional things: it gets
> rid of the fractional results and it truncates the result to int. I
> can't find any way to do that with longs.
>
> ps: I realize that in these examples, I could use a bit-shift.

Is the quot function unchecked if you (set! *unchecked-math* true)?

Also, I have a (new!) performance concern. If all the math operators
check the current binding of *unchecked-math* at run-time that's going
to be very slow. Is this checked instead at compile time? Because then
it will work at the REPL as expected, but e.g.

(defn foo [a b]
  (binding [*unchecked-math* true]
    (+ a b)))

won't behave as expected, as the compile-time value of
*unchecked-math* won't be affected.

I'd think the best design here (other than what we have in 1.2 where
we can just call unchecked-add etc. when we want unchecked math!)
would be to have the value have its effect at *macroexpansion time* --
+ and other affected functions are inline, so their expansion code
should run at macroexpansion time and can check the current binding
and expand into unchecked or checked code, depending. The trouble is
how do you set the value at macroexpansion time? It seems you'd have
to wrap whole defns, like

(binding [*unchecked-math* true]
  (defn foo [a b]
    (+ a b)))

This prevents mixing checked and unchecked in a single function, and
it's somewhat ugly (and may confuse some IDE tools) to have the def
form not at top level anymore.

Ideally, there'd be an "unchecked" macro you could wrap around an
expression to make it compile using unchecked math:

(defn foo [a b]
  (unchecked
    (+ a b)))

but this presents its own difficulties.

(defmacro unchecked [& body]
  (binding [*unchecked-math* true]
    body))

obviously isn't going to work (the binding reverts before the macro's
return value is subjected to further expansion). We'd need a
macroexpand-all in core and

(defmacro unchecked [& body]
  (binding [*unchecked-math* true]
    (macroexpand-all body)))

or else something along those lines.

I think this a real mess compared to the situation we have in 1.2...

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to