4

I'm attempting to write an image processing library in Clojure, but I've run into a problem while writing my tests.

The image data is stored as a 2D array of integers, which are signed (Java, and by extension Clojure, doesn't have unsigned integers). I have a function to get a pixel at a given pair of coordinates. My test of that function looks something like this:

(is (= (get-pixel image 0 (dec width)) 0xFFFF0000))

That is, see if the pixel at (0, width-1) is red. The problem is, get-pixel returns a signed int, but Clojure treats 0xFFFF0000 as a long. In this case, get pixel is returning -65536 (0xFFFF0000 in hex), and Clojure is checking if it's equal to 4294901760.

Now, I have a few options. I could rewrite the test using the signed integer interpretation of the hex as a decimal (-65536), but I think that makes the intent of the test less clear. I could write a function to convert the negative number into a positive long, but that's an added layer of complexity. The simplest way is probably just to do a bitwise and between the two numbers and see if it's changed, but that still seems more complicated than it should be.

Is there any built-in way to force 0xFFFF0000 to be evaluated as a signed integer rather than a long, or to do a bitwise comparison of two arbitrary numbers? The int function doesn't work, as the number is too large to be represented as a signed int.

Thanks!

Joel
  • 1,437
  • 2
  • 18
  • 28

2 Answers2

4

In clojure 1.3, there's an unchecked-int function, which just takes the bottom four bytes and makes them an int:

user> (unchecked-int 0xffff0000)
-65536

It's a bit sad that Clojure doesn't let you enter literal numbers of different sizes - here we're doing the equivalent of the Java (int)0xffff0000L.

amalloy
  • 89,153
  • 8
  • 140
  • 205
  • This function is pretty much what I was looking for - looks like it hasn't appeared on the cheat sheet on the Clojure website yet. – Joel Dec 23 '11 at 03:51
  • Fun fact - unchecked-int returns a long. – Joel Dec 23 '11 at 15:01
  • 2
    @Joel That is funy. The word Integer is kond of offerused. We (all CS) should us int16, int32 .... and Integer for growing types. The whole numberstuff is confusing. The same goes for float. – nickik Dec 23 '11 at 21:04
  • @Joel Fun fact - that's not true. It returns an int, which (in Clojure 1.3 only, I believe) is upcast to a boxed Long if you treat it as an object instead of as a primitive. – amalloy Dec 23 '11 at 23:45
  • @amalloy Huh. How can I keep it from being considered an object?(type (unchecked-int 0xFFFF0000)) shows long, which is somewhat counter-intuitive. – Joel Dec 24 '11 at 20:29
  • My main problem is that I want to set an item in an int array, but using (int (unchecked-int 0xFFFF0000)) is giving an argument type mismatch. – Joel Dec 24 '11 at 20:36
  • Ohhhhh, now I get what's going on. The discussion here clarified things: http://groups.google.com/group/clojure-dev/browse_thread/thread/5b86859057b35b68 – Joel Dec 24 '11 at 20:55
0

What clojure version are you using? The primitive handling was changed quite a bit in version 1.3. I did a little bit of experimenting, and I seem to get different results than you describe.

user=> (int 0xFFFF0000)
IllegalArgumentException Value out of range for int: 4294901760  clojure.lang.RT.intCast (RT.java:1093)
user=> (long 0xFFFF0000)
4294901760
user=> *clojure-version*
{:major 1, :minor 3, :incremental 0, :qualifier nil}

If you're using 1.3 you could use the long function. You could also manipulate your data with a ByteBuffer and deal with the bytes a bit more directly, although you'll never get the level of control you would with C.

BillRobertson42
  • 12,602
  • 4
  • 40
  • 57
  • No, that's about the same as what I'm seeing. I have attempted to store the image data as longs instead of ints, but I'm obtaining the data by using getColors() (I think) from the bufferedImage class, which returns an int array. Even if I cast each element in the array to a long, some would still be negative. – Joel Dec 22 '11 at 14:47