Из журнала Deja Vu #06, Кемерово, 01.10.98



(C) Max/Cyberax Software/BD
__________________________________________

          Фрактальный папоротник
          ----------------------

   Первый  раз я увидел  его на pC - попа-
лась  небольшая  программка на  Q.BASIC'е.
Вскоре  я  сделал  ее аналог на спековском
бейсике, а сейчас предлагаю асмовую реали-
зацию.
   Принцип  построения  довольно  простой.
Имеем следующие рекуррентные формулы:

 XNEW=XOLD*A+YOLD*B+C
 YNEW=XOLD*D+YOLD*E+F

Здесь A,B,C,D,E и F - коэффициенты.


   Насколько я понял, данные  формулы зак-
лючают  в  себе  преобразования  поворота,
масштабирования  и переноса  координат од-
новременно.
   Коэффициентов у нас будет 4  набора  и,
соответствено, 4 варианта формул:

    +-----+-----+-----+-----+-----+-----+
    |  A  |  B  |  C  |  D  |  E  |  F  |
+---+-----+-----+-----+-----+-----+-----+
| 1 |  0  |  0  |  0  |  0  | .16 |  0  |
| 2 | .85 | .4  |  0  |-.04 | .85 | 1.6 |
| 3 | .2  |-.26 |  0  | .23 | .23 | 1.6 |
| 4 |-.15 | .28 |  0  | .26 | .24 | .44 |
+---+-----+-----+-----+-----+-----+-----+

   Для построения  фрактала  нужно  задать
начальные значения координат X и Y.
   Затем  закручиваем  бесконечный цикл. В
цикле для получения последующих X, Y через
предыдущие, применяем одну из 4-х формул с
вероятностью:

 1% (1-я), 85% (2-я), 7% (3-я), 7% (4-я).

(Где-то я читал,  что эти вероятности про-
порциональны площадям листьев папоротника)
   Выбор формул производится просто: берем
(где-нибудь...) RND-число от 0 до 1, затем
смотрим, в какой диапазон попало число.

R = [0.00, 0.01] - 1-й набор коэф-тов
R = (0.01, 0.86] - 2-й
R = (0.86, 0.93] - 3-й
R = (0.93, 1.00] - 4-й


Вышеприведённые значения коэффициентов и
вероятностей взяты из pC-программки.

Цикл  можно оборвать после  достаточного
количества итераций. Результатом  работы
будет примерно такая картинка.
Для реализации всей  этой ахинеи,  я ис-
пользовал fixed point calculations  8.8,
с учетом знака (8 битов до запятой и 8 -
после).

Теперь, собственно, листинг:

        ORG   #6000
        ENT
;Written by Max/CBX/BD
;XAS Assembler v7.447, 15.08.98.

DOT     EQU   #C0;   Килобайтная табличка.
X_SCALE EQU   #1800; Коэф-ты растяжения по
Y_SCALE EQU   #1200; X и по Y.

        DI
        CALL  INIT
        LD    IX,0
FRACTAL LD    HL,CONST1
        LD    DE,12
        LD    A,R
        ADD   A,#AA
        RLCA
RN      XOR   0
        XOR   (IX)
        INC   IX
        LD    (RN+1),A; A - RND-число.
        CP    3
        JR    C,OK
        ADD   HL,DE
        CP    220
        JR    C,OK
        ADD   HL,DE
        CP    238
        JR    C,OK
        ADD   HL,DE
OK      LD    A,HX; Выбрали нужный набор
        AND   #3F;  коэффициентов.
        LD    HX,A
        PUSH  HL
        LD    DE,(X)
        CALL  MUL_NM1
        LD    (TMP1+1),HL
        POP   HL
        INC   L
        INC   L
        PUSH  HL
        LD    DE,(Y)
        CALL  MUL_NM1
TMP1    LD    DE,0
        ADD   HL,DE
        EX    DE,HL
        POP   HL
        INC   L
        INC   L
        LD    C,(HL)
        INC   L
        LD    B,(HL)
        INC   L
        EX    DE,HL
        ADD   HL,BC
        PUSH  HL
        EX    DE,HL
        PUSH  HL
;XNEW вычислили.
        LD    DE,(X)
        CALL  MUL_NM1
        LD    (TMP2+1),HL
        POP   HL
        INC   L
        INC   L
        PUSH  HL
        LD    DE,(Y)
        CALL  MUL_NM1
TMP2    LD    DE,0
        ADD   HL,DE
        EX    DE,HL
        POP   HL
        INC   L
        INC   L
        LD    C,(HL)
        INC   L
        LD    B,(HL)
        EX    DE,HL
        ADD   HL,BC
        LD    (Y),HL
;YNEW тоже вычислили.
        EX    DE,HL
        LD    BC,Y_SCALE
        CALL  MUL_NM2; Масштабируем Y.
        EX    DE,HL
        LD    HL,#C000
        AND   A
        SBC   HL,DE
        LD    A,H
        EX    AF,AF
        POP   DE
        LD    (X),DE
        LD    BC,X_SCALE
        CALL  MUL_NM2; Масштабируем X.
        LD    DE,#8000
        ADD   HL,DE
        LD    B,H
        EX    AF,AF
        LD    H,DOT;  Ставим точку.
        LD    L,A
        LD    A,(HL)
        INC   H
        LD    D,(HL)
        INC   H
        LD    L,B
        OR    (HL)
        LD    E,A
        INC   H
        LD    A,(DE)
        OR    (HL)
        LD    (DE),A
        LD    A,#7F
        IN    A,(#FE); Опрос SPACE.
        RRCA
        JP    C,FRACTAL
        EI
        RET

MUL_NM1 LD    C,(HL)
        INC   L
        LD    B,(HL)
;Процедура  умножения  двух знаковых чисел
;формата 8.8 (регистры DE и BC):
MUL_NM2 LD    A,D
        AND   A
        JP    P,NONEG1
        CPL
        LD    D,A
        LD    A,E
        CPL
        LD    E,A
        INC   DE
;Чтобы  изменить  знак  числа, его (число)
;нужно инвертировать и увеличить на 1.
        LD    A,B
        AND   A
        JP    P,NONEG2
        CPL
        LD    B,A
        LD    A,C
        CPL
        LD    C,A
        INC   BC
NONEG3  XOR   A
        JP    ML2
NONEG2  LD    A,#FF
        JP    ML2
NONEG1  LD    A,B
        AND   A
        JP    P,NONEG3
        CPL
        LD    B,A
        LD    A,C
        CPL
        LD    C,A
        INC   BC
        LD    A,#FF
;В данный момент DE содержит модуль 1-го
;сомножителя, а BC - второго.
;В аккумуляторе - 0 или FF - знак рез-та.
ML2     LD    HL,0
        !ASSM 16
        RR    B
        RR    C
        JR    NC,$+3
        ADD   HL,DE
        RR    H
        RR    L
        !CONT
        RR    B
        RR    C
;В HLBC сейчас сидит число в формате 16.16
;(результат умножения 8.8 * 8.8).
;Далее, если число должно быть отрицатель-
;ным - меняем его знак.
;После всего этого бесцеремонно отбрасыва-
;ем по байту с начала и с конца и загоняем
;результат в HL.
        RRCA
        JR    NC,NONEG4
        LD    A,C
        CPL
        ADD   A,1
        LD    A,L
        CPL
        LD    H,A
        LD    A,B
        CPL
        LD    L,A
        RET   NC
        INC   HL
        RET
NONEG4  LD    H,L
        LD    L,B
        RET

;Инициализация.

INIT    XOR   A
        OUT   (#FE),A
        LD    HL,#4000
        PUSH  HL
        LD    DE,#4001
        LD    BC,#1800
        LD    (HL),L
        LDIR
        LD    BC,#2FF
        LD    (HL),68
        LDIR
        POP   DE
        LD    H,DOT
        LD    L,E
        LD    B,#C0
MK_ADTB LD    (HL),E
        INC   H
        LD    (HL),D
        DEC   H
        INC   L
        INC   D
        LD    A,D
        AND   7
        JP    NZ,C1
        LD    A,E
        ADD   A,32
        LD    E,A
        JR    C,C1
        LD    A,D
        SUB   8
        LD    D,A
C1      DJNZ  MK_ADTB
CL_LP   LD    (HL),B
        INC   H
        LD    (HL),B
        DEC   H
        INC   L
        JR    NZ,CL_LP
        INC   H
        INC   H
        LD    BC,#801F
MK_B_TB LD    A,L
        RRCA
        RRCA
        RRCA
        AND   C
        LD    (HL),A
        INC   H
        LD    (HL),B
        DEC   H
        RRC   B
        INC   L
        JR    NZ,MK_B_TB
        RET

        ORG   $/256+1*256

;Таблица констант с fixed point.
;Должна располагаться с /256 адреса.
;
;В формат 8.8 константы переводятся очень
;просто, особенно с калькулятором CITIZEN.
;
; Пример: имеется число 0.16.
; Умножаем его на 256, получаем 40.96.
; Округляем до 41.
; Переводим в HEX:  #0029.
;
; Если число <0, то до перевода в HEX к
; нему прибавляем 65536 (#10000).

CONST1  DW    #0000;   A=0
        DW    #0000;   B=0
        DW    #0000;   C=0
        DW    #0000;   D=0
        DW    #0029;   E=.16
        DW    #0000;   F=0

CONST2  DW    #00DA;   A=.85
        DW    #000A;   B=.04
        DW    #0000;   C=0
        DW    #FFF6;   D=-.04
        DW    #00DA;   E=.85
        DW    #019A;   F=1.6

CONST3  DW    #0033;   A=.2
        DW    #FFBD;   B=-.26
        DW    #0000;   C=0
        DW    #003B;   D=.23
        DW    #003B;   E=.23
        DW    #019A;   F=1.6

CONST4  DW    #FFDA;   A=-.15
        DW    #0048;   B=.28
        DW    #0000;   C=0
        DW    #0043;   D=.26
        DW    #003D;   E=.24
        DW    #0071;   F=.44

   Для прикола, в блоке CONST2 можете  1-е
число заменить на #00B0 - получите  нечто,
напоминающее елочку, или  на  #0060 - тоже
вроде елочку, но какую-то ободранную...

;Текущие координаты:
X       DW    #0000
Y       DW    #0000

P.S.  На этом фрактале неплохо тестировать
процедуру получения случайных чисел.  Если
генерируемые им значения часто повторяются
или все время  попадают в определенный ин-
тервал, лежащий внутри [0, 255],  то фрак-
тала не получится  (можете попробовать уб-
рать  ксорку с  (IX), указывающим на ПЗУ -
увидите что будет).
   В идеале все числа  должны быть  равно-
вероятными, попадать в диапазон 0 - 255, а
порядок  их следования  друг за  другом не
должен повторяться и иметь какую-либо тен-
денцию (например бывают процедуры, в кото-
рых следующее число обычно больше предыду-
щего).