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