Unexpected behaviour in unchecked-multiply when using vars as arguments

348 views
Skip to first unread message

Linus Ericsson

unread,
Dec 4, 2011, 5:14:21 PM12/4/11
to clo...@googlegroups.com
I try to do multiplication where overflowing is expected and the result should be handled "modulo" ie the multiplication results in a truncated long.

user> (unchecked-multiply (Long/MAX_VALUE) (Long/MAX_VALUE))
1 ;;is ok and expected

also

classificator.fnvhash> (unchecked-multiply Long/MAX_VALUE Long/MAX_VALUE)
1

(side note: what is different between Long/MAX_VALUE and the function call (Long/MAX_VALUE)?)

BUT:

user> (def max1 Long/MAX_VALUE)
#'user/max1
user> (def max2 Long/MAX_VALUE)
#'user/max2
user> (unchecked-multiply max1 max2)

results in a "integer overflow". I have tried to type hinting and what not. It seems like unchecked-multiply doesn't like vars, but thats surprising. What am I doing wrong here?

I'm using Clojure 1.3.0.

/Linus

Stuart Sierra

unread,
Dec 5, 2011, 10:22:18 AM12/5/11
to clo...@googlegroups.com
>  (side note: what is different between Long/MAX_VALUE and the
> function call (Long/MAX_VALUE)?

None. Both are syntax sugar for (. Long MAX_VALUE)

-S

Stuart Sierra

unread,
Dec 5, 2011, 10:25:00 AM12/5/11
to clo...@googlegroups.com
>  (side note: what is different between Long/MAX_VALUE and the
> function call (Long/MAX_VALUE)?

None. Both are syntax sugar for (. Long MAX_VALUE)

> It seems like unchecked-multiply doesn't like vars, but thats surprising.
> What am I doing wrong here?

unchecked-multiply only does unchecked arithmetic when the arguments are primitive. Vars cannot have primitive values, they must be boxed as java.lang.Long. So it reverts to normal Clojure arithmetic.

The unchecked-* functions are intended as a performance optimization when doing operations with primitives.

-S

Linus Ericsson

unread,
Dec 5, 2011, 12:16:34 PM12/5/11
to clo...@googlegroups.com


2011/12/5 Stuart Sierra <the.stua...@gmail.com>
OK, then the problem seems to be to refer to primitives with symbols with unchecked-* functions. How do I do that?

The loop where high performance is required is

hash = -3750763034362895579
for each byte b in array-of-bytes-to-be-hashed do :
    hash = hash * 1099511628211 (without caring about overflowing)
    hash = hash ^ byte
return hash

and I really cannot see how to do this without using something that hold values somehow, but how do I bypass the numeric stack in clojure?

I have tried with the following approach (just for the first step):

fnv> (def hash (Long. -3750763034362895579))
#'fnv/hash
fnv> (def hash2 (Long. (unchecked-multiply hash 1099511628211)))
; Evaluation aborted. (because of integer overflow)

How should I do to get it working correctly? There simply must be a way to store primitives, but I'm apparently have gotten something wrong here.

(the hash in question is the quite quick FNV-hash, which is in public domain, nice and everything)

/Linus

David Nolen

unread,
Dec 5, 2011, 12:24:57 PM12/5/11
to clo...@googlegroups.com
You can't store primitives in vars. But you can cast their contents to primitives with (long ...) (int ...) etc

David

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@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+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Linus Ericsson

unread,
Dec 5, 2011, 12:29:25 PM12/5/11
to clo...@googlegroups.com
David and Stu to the rescue. Of course that's the way to do it.

Thank you both,

/Linus

2011/12/5 David Nolen <dnolen...@gmail.com>

David Powell

unread,
Dec 5, 2011, 12:38:26 PM12/5/11
to clo...@googlegroups.com
On Mon, Dec 5, 2011 at 5:29 PM, Linus Ericsson <oscarlinu...@gmail.com> wrote:
David and Stu to the rescue. Of course that's the way to do it.

Not sure if this is what you want, but Clojure 1.3 introduced ^:const.  This lets you store a primitive constant value:

  (def ^:const hash -3750763034362895579)

Then you can use hash anywhere as if you'd inlined the value.  hash will be stored as a primitive, and will work with unchecked-multiply.

-- 
Dave

Linus Ericsson

unread,
Dec 5, 2011, 4:03:00 PM12/5/11
to clo...@googlegroups.com

Thats a great feature as well! It is very good not to clutter the code with magic constants, but to be able to name them in a sane way.

Thank you all again,

/Linus

Reply all
Reply to author
Forward
0 new messages