Побитовые операции в APL?
Нам нужно создать программу, которая имитирует деление чисел с плавающей запятой IEEE для моего класса архитектуры компьютера. Я в значительной степени сделал это, но я подумал, что было бы интересно посмотреть, как программа будет выглядеть в APL, но, насколько я могу судить, нет (простого) способа выполнять побитовые операции в APL (побитовое и / или, сдвиг и т.д...). Какой самый простой способ сделать это в APL, если это возможно?
2 ответа
Чистый (= способ, которым вы хотите использовать) способ сделать это в APL:
- преобразовать число (числа) в битовый вектор (или битовую матрицу или значение APL более высокой размерности),
- выполнить операцию сдвига, поворота и т. д. для битового вектора и
- преобразовать обратно в числа
Шаги 1 и 3 довольно просты: в APL есть два оператора преобразования: кодировать (⊤) и декодировать (⊥), которые это делают. Битовые векторы являются лишь частным случаем; операторы работают с произвольными базами (в том числе с шестнадцатеричными).
Примеры:
⍝ convert 13 to 4-bit vector. The number of 2s is the result length
2 2 2 2 ⊥ 13
1 1 0 1
2 ⊥ 1 1 0 1 ⍝ convert back
13
Программист APL не будет писать 2 2 2 2, чтобы указать желаемую длину вектора результата, а вместо этого (4⍴2). Это потому, что для более длинных аргументов of (например, 64 в вашем случае) код гораздо более читабелен.
Отрицательные целые числа немного сложнее, потому что существуют разные форматы, такие как 1-дополнение или 2-дополнение. ⊤ и ⊥ работают, но вы должны позаботиться.
Есть несколько классных вещей, которые ⊤ и ⊥ предоставляют. Прежде всего вы можете конвертировать несколько чисел за один раз:
2 2 2 2 ⊤ 1 2 3
0 0 0
0 0 0
0 1 1
1 0 1
Далее, как уже было сказано, они работают для других баз, например 16, для шестнадцатеричных результатов:
16 16 16 16 ⊤ 50000
12 3 5 0
Результат числовой, поэтому вы можете преобразовать его в символы:
'0123456789ABCDEF'[⎕IO+16 16 16 16⊤50000]
C350
Наиболее сложный случай - числа с плавающей точкой (и, следовательно, также сложные).
Большинство интерпретаторов APL имеют для этого системные функции, например, ⎕DR в APL68000 или 27 ⎕CR в GNU APL. ⎕DR возвращает двоичный вектор напрямую, в то время как 27 inCR в GNU APL преобразует 64-разрядное число с плавающей запятой IEEE в 64-разрядное целое число с 2-дополнительным дополнением, которое затем можно преобразовать, как описано выше.
Как только вы преобразовали свои числа в битовый вектор, все остальное просто:
- Индексирование ([]) для доступа к отдельным битам
- Взять (↑) и отбросить (↓) для сдвига битов
- Поворот (⊖ или ⌽) для вращающихся бит
- Булевы функции И / Или / Нанд / Нор / Не (⍱ ∨ ⍲ ⍱ и ∼) для бинарных операций.
В зависимости от вашей системы APL, вот грязный способ сделать это. Некоторые системы APL имеют системную функцию []DR, которая позволяет быстро и свободно преобразовывать содержимое переменных из одного типа данных в другой. Если у вас есть Dyalog APL (возможно, это будет работать в APL2000), попробуйте это:
)CLEAR
[]IO := 0 // sorry, no APL chars
[]PP := 16
a := 11 []DR 7.42 // 11 means "type number 1, boolean, 1 bit"
a
1 0 1 0 1 1 1 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 0 1 0 1 1 1 1 0 1 0 0 0 0 1 0 1 0 0 1 0 1 0 1 1 1 0 0 0 0 1 1 1 0 1 0 1 0 0 0 0 0 0
a[42]
1
a[42] := 0
645 []DR a // 645 means "type number 5, double, 64 bit"
7.388750000000003
)CLEAR
Здесь []DR выполняет сложную часть преобразования числа с плавающей запятой в вектор битов, а затем обратно. (Это может быть именно то, что вам нужно выучить на уроке архитектуры вашего компьютера, но это не плохой способ проверить ваш ответ)
Внимание: с помощью этой техники вы можете создавать значения, которые не являются допустимыми числами с плавающей запятой. Это может привести к неприятным последствиям сбоя интерпретатора, системы или оставления чего-то, что может вызвать проблемы позже. Обязательно )CLEAR
после экспериментов.