I made a fern using the algorithm described in

this wikipedia article
Here is the code

**Code:** ```
AxesOff:ClrDraw
```

DelVar XDelVar YDelVar A0

While 1

Pxl-On(int(26A+75),int(26Ans

Ans→Y

A→X

rand

If Ans<.01

Then

DelVar A.16Y

Else

If Ans<.86

Then

.85X+.04Y→A

.04X+.85Y+1.6

Else

If Ans<.93

Then

.2X-.26Y→A

.23X+.22Y+1.6

Else

.15X+.28Y→A

.26X+.24Y+.44

End:End:End:End

Here is the output after a while

Excellent mr womp womp !!!

That looks AWESOME!

Would you mind explaining how it works?

**jcgter777 wrote:**

That looks AWESOME!

Would you mind explaining how it works?

The Wikipedia article he linked gives a pretty good explanation. Essentially, you choose at random of one four functions to apply to a point, then repeat. The choice of functions and how often they occur is such that you end with a fractal structure that looks like, in this case, a fern. Tweaking the decimals you see in the equations for the four cases will make the fern look different, and there are examples of other constants on the Wikipedia page you can use to get ferns that resemble other species.
That's about it, the actual implementation really isn't hard.

mr womp womp did a great job of implementing Barnsley's Fern, but I thought I try optimizing the code a bit and making it more versatile. Here's what I've got:

**Code:** ```
PRGM:BARNSLEY
```

:AxesOff:ClrDraw

:DelvarA:75→C:0→D:0

:While 1

:Pxl-On(int(26A+C),int(26Ans+D),GREEN

:Ans→Y:A→X:rand→R

:For(L,1,dim(L₁

:If R<L₁(L:Then

:Matr►list([A],L,L₂:99→L

:XL₂(1)+YL₂(2)+L₂(5→A

:XL₂(3)+YL₂(4)+L₂(6

:End:End:End

The matrix [A] is 6x4 and contains the coefficients of the functions generating the fern. You essentially punch in the constants as they appear in the tables on the Wikipedia page, except vertically rather than horizontally (if you want it horizontal rather than vertical, just replace [A] with [A]^T in the Matr►list( command).

Meanwhile, L₁ contains the probabilities of the functions occurring as cumulative sums (effectively the "p" column of the Wikipedia table except cumSum('ed with a 1 as the final entry). C and D are offsets for drawing the fern so it stays within the graphable range.

Here's the original fern (but in GREEN), where C=75 and D=0:

And a variant (also in GREEN), where C=75 and D=30 (I was pressed for time, so its not fully generated):

Sorry if my descriptions of the function matrix and what not aren't sufficient; let me know if you have questions!
I like the way you generalized the code.

I actually did something like this at first to more closely resemble the underlying linear algebra, but I optimized it for speed because I think that's quite important in this case.

Just for fun, I decided to measure and compare the speeds of your program and mine. In a 2 minute time-span, yours drew 892 points while mine drew 1623

You also have a small mistake in your code:

**Code:** `:Pxl-On(int(26A+C),int(26A+D),GREEN`

should be

**Code:** `:Pxl-On(int(26A+C),int(26Ans+D),GREEN`

**mr womp womp wrote:**

I like the way you generalized the code.

I actually did something like this at first to more closely resemble the underlying linear algebra, but I optimized it for speed because I think that's quite important in this case.

Just for fun, I decided to measure and compare the speeds of your program and mine. In a 2 minute time-span, yours drew 892 points while mine drew 1623

You also have a small mistake in your code:

**Code:** `:Pxl-On(int(26A+C),int(26A+D),GREEN`

should be

**Code:** `:Pxl-On(int(26A+C),int(26Ans+D),GREEN`

Oh yeah; typo. I'll edit it. But yeah the Matr►list( does slow stuff down a bit.
Did someone say optimizing for speed?

* Using finance variables and

changing for example .85X+.04Y to X.85+Y.04 could save a few ms per cycle.

* The multiplications by 26 can be eliminated entirely by appropriate scaling.

* The conditional that occurs 85% of the time should come first.

* rand is expensive and generates ~10 decimal places of randomness each time, and you're only using 2 each loop iteration. Therefore uses of rand can be cut down by a factor of 5.

These are all very good suggestions! I never even thought about having the conditional that occurs most often first. I don't think the multiplication by 26 could be removed though because I don't want it to affect A and Ans. I actually thought about using [recursiven] instead of A, but I figured the time difference was negligible. I guess if I am going to be advocating for speed optimization, I should go all the way

I'll make the changes and measure the speed again tonight to see what kind of a difference it really makes.

These look amazing Love the Art, and I will love to see more of this.

I found the Barnsley's Fern post interesting. I have several programming calculators, but I kind of gotten away from programming on them. I currently enjoy coding on an iPad using Lua. I thought I’d convert the code here and run it on my iPad. Just to give you an idea of the speed difference, mr womp womp said his code ran 1623 plots in 2 minutes. On my iPad, I did 100,000 plots in less than 3 seconds. Here's a screen shot of the results I got.

The p1 thru p4 sliders allow me to vary the settings in the tables to get different plots when I press Redraw. This is 100,000 plots.

I put womp's code onto my CE and left it to run (with the wait states turned down) for about 20 minutes. It complete about 20500 iterations and made a pretty good fern!

I tried to make a version in ICE but I've spent 2 hours on this and it's refusing to work. Perhaps someone could see what I'm doing wrong?

I'm multiplying everything in womp's code by 100 (to account for the lack of decimals in ICE) then dividing by 100 at the point where it displays the points. I've also adjusted the probability numbers to account for ICE's weird rand function, and I stored the coordinates into S (x) and T (y) for debugging purposes.

**Code:** ```
FERNY
```

det(0

0→A

0→B

0→R

While getKey≠15

dbd(0

(2600*A+7500)/100→S

(2600*B)/100→T

det(6,S,T

B→Y

A→X

(rand/100000)→R

If R<2

0→A

16*Y→B

Else

If R<142

85*X+4*Y→A

4*X+85*Y+160→B

Else

If R<155

20*X-26*Y→A

23*X+22*Y+160→B

Else

15*X+28*Y→A

26*X+24*Y+44→B

End

End

End

End

det(1

I swapped the variables and constants around and used finance vars. I also swapped the order of the checks to make the .85 first, then the two .07 and then the .01. I can see how generating 14 digits of randomness and using only 2 is bad, but I can't really think of any way to improve the speed because adding pretty much any code at all makes it immediately slower, and randInt() is also slower.

These changes made it go from 1623 to 2060 (points drawn per 2 minutes).

Here is the updated code:

**Code:** ```
AxesOff:ClrDraw
```

0→I%:0→PV:0→Ś:0

While 1

Pxl-On(int(26PV+75),int(26Ans

Ans→Ś

PV→I%

rand

If Ans<.85

Then

I%.85+Ś.04→PV

I%.04+Ś.85+1.6

Else

If Ans<.92

Then

I%.2-Ś.26→PV

I%.23+Ś.22+1.6

Else

If Ans<.99

Then

I%.15+Ś.28→PV

I%.26+Ś.24+.44

Else

0→PV:.16→Ś

End:End:End:End

Just for fun, I reduced the wait states setting down to 6 to see how much I could push this. This actually got it up to 3003 points per 2 minutes. I think there isn't much left to do in pure basic. Any further improvements will probably have a minuscule impact on the overall speed.

The following code that store directly to the finance var instead of using Ans seems to be a bit faster, reaching 3111 with wait states set to 6.

**Code:** ```
AxesOff:ClrDraw
```

0→I%:0→PV:0→Ś:0

While 1

Pxl-On(int(26PV+75),int(26Ś

PV→I%

rand

If Ans<.85

Then

I%.85+Ś.04→PV

I%.04+Ś.85+1.6→Ś

Else

If Ans<.92

Then

I%.2-Ś.26→PV

I%.23+Ś.22+1.6→Ś

Else

If Ans<.99

Then

I%.15+Ś.28→PV

I%.26+Ś.24+.44→Ś

Else

0→PV:.16→Ś

End:End:End:End

Interesting finding though is that having the calculator plugged in makes it slower. running the same test with the calculator unplugged yields 3656.

I also let it run for way longer than I probably should have

I had an issue where I was getting absurdly low scores (around 2510) but here's what I did to fix it:

- Unplug the charger: I guess the calculator keeps trying to communicate with my laptop while running the program which affected its performance. I got around 65 points back from this.

- garbageCollect: this had the biggest impact, I hadn't garbageCollected in at least 3 months so cleaning all that up definitely helped, I got about 585 points back from this.

- disable hooks: I broke the hooks that Cesium and ICE used by activating the 'test mode' prompt. Although I can't say it's an impressive score increase, I still got 16 points back.

My final score after all this was 3166 which is still slower than womp's, but much better than last time!

EDIT: mateo ninja'd me, but here's what I got after probably a million iterations, I had CEmu unthrottled and left it for about an hour.

When I run the code, it says ERROR: DOMAIN. Am I in the wrong window?

**Code:** ```
```

AxesOff:ClrDraw

DelVar XDelVar YDelVar A0

While 1

Pxl-On(int(26A+75),int(26Ans

Ans->Y

A->X

rand

If Ans<.01

Then

DelVar A.16Y

Else

If Ans<.86

Then

.85X+.04Y->A

.04X+.85Y+1.6

Else

If Ans<.93

Then

.2X-.26Y->A

.23X+.22Y+1.6

Else

.15X+.28Y->A

.26X+.24Y+.44

End:End:End:End

Barnsley's Fern in C on the TI-84+CE with 2,000,000 iterations:

I put together a quick attempt (Z80 assembly), it looks like I messed up somewhere

**mr womp womp wrote:**

I think there isn't much left to do in pure basic. Any further improvements will probably have a minuscule impact on the overall speed.

The below pure BASIC code about doubles the speed again and has adjustable window dimensions.

EDIT: now works on either monochrome or color (use Pt-On(,,4 for color)

EDIT: Improved speed another 20%

**Code:** ```
startTmr->T
```

Repeat checkTmr(T:End

AxesOff:ClrDraw

~log(.85->PMT

~log(.93->A

~log(.99->B

0->Xmin

12->Xmax

~3->Ymin

3.3->Ymax

0

For(I,1,4600*.15 //expected to draw 4600 points

For([recursiven],~log(rand),PMT,~PMT

Pt-On(real(Ans),imag(Ans),4

Ans(.85+.04[i])+1.6

End

Pt-On(real(Ans),imag(Ans),4

If [recursiven]>A

Then

real(Ans)(.24+.28[i])+imag(Ans)(.26-.15[i])+.44

Else

If [recursiven]>B

Then

real(Ans)(.22-.26[i])+imag(Ans)(.23+.2[i])+.44

Else

real(Ans).16

End

End

End

checkTmr(T)-1

Register to Join the Conversation

Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

»

Go to Registration page

You **cannot** post new topics in this forum

You **cannot** reply to topics in this forum

You **cannot** edit your posts in this forum

You **cannot** delete your posts in this forum

You **cannot** vote in polls in this forum