Побитовые операции в APL?

Нам нужно создать программу, которая имитирует деление чисел с плавающей запятой IEEE для моего класса архитектуры компьютера. Я в значительной степени сделал это, но я подумал, что было бы интересно посмотреть, как программа будет выглядеть в APL, но, насколько я могу судить, нет (простого) способа выполнять побитовые операции в APL (побитовое и / или, сдвиг и т.д...). Какой самый простой способ сделать это в APL, если это возможно?

2 ответа

Решение

Чистый (= способ, которым вы хотите использовать) способ сделать это в APL:

  1. преобразовать число (числа) в битовый вектор (или битовую матрицу или значение APL более высокой размерности),
  2. выполнить операцию сдвига, поворота и т. д. для битового вектора и
  3. преобразовать обратно в числа

Шаги 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-дополнительным дополнением, которое затем можно преобразовать, как описано выше.

Как только вы преобразовали свои числа в битовый вектор, все остальное просто:

  1. Индексирование ([]) для доступа к отдельным битам
  2. Взять (↑) и отбросить (↓) для сдвига битов
  3. Поворот (⊖ или ⌽) для вращающихся бит
  4. Булевы функции И / Или / Нанд / Нор / Не (⍱ ∨ ⍲ ⍱ и ∼) для бинарных операций.

В зависимости от вашей системы 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 после экспериментов.

Другие вопросы по тегам