Я это и имел в виду.
Вид для печати
Думаю это принципиальный момент. В контексте данного алгоритма DAD H и RAL это не умножение на 2/сдвиг влево AHL, это деление на 2/сдвиг вправо C относительно AHL. Все относительно, вручную мы привыкли сдвигать делитель вправо относительно делимого, а здесь двигают делимое влево относительно делителя (так делают в большинстве процедур деления для 8080, т.к. команды сдвига влево есть только для A). Но результат одинаковый. И в качестве бонуса такой сдвиг обнуляет младший бит L.
К сожалению, это не продвинуло меня ни на шаг к разгадке. Наверное у меня не хватает мозгов(
Нет, чисто машинально я понимаю ЧТО здесь происходит, скажем так - в пределах каждой строчки в отдельности. Но какова цель всех этих действий, мне не понятно.
Общего алгоритма я не понимаю((
Грубо говоря, то же банальное деление подсчётом кол-ва вычитаний делителя - ясно и прозрачно, мне понятен общий принцип и каким образом каждый шаг ведёт к результату. Аналогично при делении в столбик: на каждом шаге понятно что происходит и зачем это всё делается.
Здесь же, я вижу что выполняются некие действия непонятного назначения, на промежуточных этапах в регистрах получаются совершенно непонятные значения...
Я подробно прокрутил уже много примеров через этот алгоритм, но никакой логики увидеть не смог.
Возможно имеет смысл действительно рассматривать происходящее не в 16-ричном виде, а в двоичном. Или попробовать разобраться и написать с нуля алгоритм деления в классический столбик, может тогда придёт понимание.
- - - Добавлено - - -
С этим как раз у меня проблем нет. Очень часто пользуюсь сдвигами при программировании, и всегда оптимизирую - кручу в ту сторону, в какую ближе, а уж "перекинуть" байты местами для получения обратной картины не вопрос.
В данном случае мне глобально не понятен смысл всех этих действий, каким образом они ведут к результату.
Общий алгоритм - деление в столбик.
Что делаем? Сносим 0, делим на 7, получаем 0 в результате, 0 в остатке. Сносим второй 0, делим на 7... Сносим 1, делим на 7... Сносим 5...Код:00115 | 7
0 |----
0 | 00016
=
00
00
==
001
000
===
0011
0007
====
45
42
=====
3
Это понятно?
Смотрим на это под другим углом.
Есть у нас три части (именно в таком порядке): "снесённая" часть (она же остаток), делимое, и частное (результат).
Не сносим, а сдвигаем (смотри на деление в столбик).
Было 00115, стало 0 и 0115, и в ответе 0.
Потом стало 00, 115, 00.
Потом 001, 15, 000.
0011, 5, 0001. (11-7*1=4)
00045, пусто, 00016. (45-7*6=3)
Это понятно?
Первая часть в аккумуляторе, а делимое и частное записаны вместе:
Понятно? Или расписать ещё в двоичном виде?Код:00115|
0115|0
115|00
15|000
5|0001
|00016
- - - Добавлено - - -
Да, именно в двоичном. Не в шестнадцатеричном, и тем более не в десятичном, там действительно будет выглядеть как магия.
Действительно, нужно было посмотреть на "столбик" под другим углом (не как учили в школе, а более "компьютерно"), обобщить его до регистров фиксированной длины с незначащими нулями и "холостыми" итерациями, а также в двоичной плоскости, и тогда понимание снизошло :)
Три момента, которые видимо не давали мне ключ к пониманию:
1) Сдвиг это действительно сдвиг, а не умножение/деление на два!
2) В школьном варианте мы сдвигаем сразу всю цифру (десятичную) целиком, а тут мы это делаем по одному биту (грубо говоря, тупо ждём, когда протащится вся цифра);
3) Пожалуй, принципиальный момент, который скрывал логику: поскольку мы работаем в двоичной с/с, то на каждой итерации нам не нужно делать реальное деление цифры на делитель, как это делается в школьном столбике, а достаточно лишь понять делится оно или нет, точнее - результат ноль или больше, и так как за одну двоичную итерацию у нас не может ничего произойти с результатом больше, чем на единицу, то достаточно либо оставлять "халявный" автоматический "0" или добавлять "1".
Я бы до такого не додумался сам! Я бы стал подгонять алгоритм под известный школьный столбик, т.е. сдвигать байт сразу на тетраду и честно делить вычитаниями. Тут какой-то двоичный переворот сознания %)
Всем спасибо! Теперь можно спать спокойно :)
Поделим в двоичном виде "0011000000111001" на "1010". (должно получиться 0000010011010010, и остаток 101).
Итерация №1
сдвигаем на 1 разряд, получаем 0 и 011000000111001?
0 меньше 1010, значит в результат задвигаем 0, получаем ???????????????0
Итерация №2
сдвигаем на 1 разряд...
Скрытый текст
... получаем 00 и 11000000111001??
00 меньше 1010, значит в результат задвигаем 0, получаем ??????????????00
Итерация №3
сдвигаем на 1 разряд, получаем 001 и 1000000111001???
001 меньше 1010, значит в результат задвигаем 0, получаем ?????????????000
Итерация №4
сдвигаем на 1 разряд, получаем 0011 и 000000111001????
0011 меньше 1010, значит в результат задвигаем 0, получаем ????????????0000
Итерация №5
сдвигаем на 1 разряд, получаем 00110 и 00000111001?????
00110 меньше 1010, значит в результат задвигаем 0, получаем ???????????00000
Итерация №6
сдвигаем на 1 разряд, получаем 001100 и 0000111001??????
001100 больше 1010, значит вычитаем и в результат задвигаем 1, получаем ??????????000001
(остаток 000010)
Итерация №7
сдвигаем на 1 разряд, получаем 0000100 и 000111001???????
0000100 меньше 1010, в результат задвигаем 0, получаем ?????????0000010
Итерация №8
сдвигаем на 1 разряд, получаем 00001000 и 00111001????????
00001000 меньше 1010, в результат задвигаем 0, получаем ????????00000100
Итерация №9
сдвигаем на 1 разряд, получаем 000010000 и 0111001?????????
000010000 больше 1010, вычитаем, в результат задвигаем 1, получаем ???????000001001
(остаток 110, нули отбросим для удобства)
Итерация №10
сдвигаем на 1 разряд, получаем 1100 и 111001??????????
1100 больше 1010, вычитаем, в результат задвигаем 1, получаем ??????0000010011
(остаток 0010)
и т.д.
[свернуть]
Количество оставшихся разрядов в делимом уменьшается, на их место можно записать частное.
Код:0011000000111001 (0x3039)
011000000111001 0 (0x6072)
11000000111001 00 (0xC0E4)
1000000111001 000 (0x81C8)
000000111001 0000 (0x0390)
00000111001 00000 (0x0720)
0000111001 000001 (0x0E41)
000111001 0000010 (0x1C82)
00111001 00000100 (0x3904)
0111001 000001001 (0x7209)
111001 0000010011 (0xE413)
11001 00000100110 (0xC826)
1001 000001001101 (0x904D)
001 0000010011010 (0x209A)
01 00000100110100 (0x4134)
1 000001001101001 (0x8269)
0000010011010010 (0x04D2 = 1234)
Убрал про дальшейшее увеличение разрядности делимого больше 7FFFF. В общем случае там надо еще команды добавлять, а это уже не так интересно.
- - - Добавлено - - -
Сообразил компромиссный вариант, можно увеличить делимое до 3FFFFF без добавления команд если 1) убрать XRA A; 2) Заменить LXI B,100Ah на LXI B,1350h. Но если честно, то команды все же придется добавить для разделения остатка и старших бит частного, т.к. остаток будет в 5(4) старших битах A, и 3 старших бита частного будут в 3х младших битах A.
Я уже как-то спрашивал. Постоянно пробегают небольшие удобные кусочки кода разного назначения.
Никто так и не взялся собирать их в одно место, не приводит в порядок?
Если нет - давайте, я займусь. Но буду дёргать, и приставать с вопросами, как работает, чтобы документировать.
ivagor, в источнике оригинала есть варианты для 24-битного и 32-битного делимого:
http://z80-heaven.wikidot.com/math#toc22
http://z80-heaven.wikidot.com/math#toc23
В последнем красивый замут с "удлинением" регистра до 32-битного с помощью переворота XCHG.
- - - Добавлено - - -
Дело хорошее и полезное!
Отправной точкой как раз может послужить этот ресурс - http://z80-heaven.wikidot.com/math
П.С. для Ориона я по-возможности оформляю полезные подпрограммы в виде библиотек
z80-heaven ресурс хороший, но там бывают неточности, например. В описании E_div_10 не упомянули, что деление приближенное. Все надо проверять.