Беззнаковое сравнение чисел в Clojure? - PullRequest
4 голосов
/ 22 декабря 2011

Я пытаюсь написать библиотеку обработки изображений в Clojure, но у меня возникла проблема при написании моих тестов.

Данные изображения хранятся в виде двумерного массива целых чисел, которые подписаны(Java и, соответственно, Clojure, не имеют целых чисел без знака).У меня есть функция, чтобы получить пиксель в данной паре координат.Мой тест этой функции выглядит примерно так:

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

То есть посмотрите, является ли пиксель в точке (0, ширина-1) красным.Проблема в том, что get-pixel возвращает int со знаком, но Clojure рассматривает 0xFFFF0000 как long.В этом случае get pixel возвращает -65536 (0xFFFF0000 в шестнадцатеричном формате), а Clojure проверяет, равно ли оно 4294901760.

Теперь у меня есть несколько вариантов.Я мог бы переписать тест, используя целочисленную интерпретацию шестнадцатеричного знака со знаком как десятичное число (-65536), но я думаю, что это делает цель теста менее ясной.Я мог бы написать функцию для преобразования отрицательного числа в положительное длинное, но это дополнительный уровень сложности.Самый простой способ, вероятно, состоит в том, чтобы просто сделать побитовое и между двумя числами и посмотреть, изменилось ли оно, но это все еще кажется более сложным, чем должно быть.

Есть ли какой-нибудь встроенный способ заставить 0xFFFF0000 бытьоценивать как целое число со знаком, а не как длинное, или делать побитовое сравнение двух произвольных чисел?Функция int не работает, так как число слишком велико, чтобы его можно было представить в виде int со знаком.

Спасибо!

Ответы [ 2 ]

4 голосов
/ 23 декабря 2011

В clojure 1.3 есть функция unchecked-int, которая просто берет нижние четыре байта и делает их целыми:

user> (unchecked-int 0xffff0000)
-65536

Немного грустно, что Clojure не позволяет вводить литеральные числаразных размеров - здесь мы делаем эквивалент Java (int)0xffff0000L.

0 голосов
/ 22 декабря 2011

Какую версию clojure вы используете? Примитивная обработка была немного изменена в версии 1.3. Я немного поэкспериментировал, и, похоже, я получаю результаты, отличные от тех, что вы описываете.

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}

Если вы используете 1.3, вы можете использовать функцию long. Вы также можете манипулировать вашими данными с помощью ByteBuffer и работать с байтами немного более напрямую, хотя вы никогда не получите тот уровень контроля, который был бы у вас с C.

...