Из журнала 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, а
порядок их следования друг за другом не
должен повторяться и иметь какую-либо тен-
денцию (например бывают процедуры, в кото-
рых следующее число обычно больше предыду-
щего).