home *** CD-ROM | disk | FTP | other *** search
/ Hot Shareware 32 / hot34.iso / ficheros / DGRAF / FRAIN196.ZIP / FRMTUT.ZIP / FRMTUTOR.TXT < prev   
Text File  |  1995-02-24  |  115KB  |  2,389 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.                       *******************************
  9.                       *                             *
  10.                       *         FRMTUTOR.TXT        *
  11.                       *                             *
  12.                       *      AN INTRODUCTION TO     *
  13.                       * THE FRACTINT FORMULA PARSER *
  14.                       *                             *
  15.                       *******************************
  16.  
  17.  
  18.  
  19.  
  20.                                  Written by
  21.                               Bradley Beacham
  22.                            CompuServe: 74223,2745
  23.                                 Revision 1.0
  24.                               24 February 1995
  25.  
  26.  
  27.  
  28.  
  29.    =======
  30.    OUTLINE
  31.    =======
  32.  
  33.       1.0   Legal Stuff
  34.  
  35.       2.0   Acknowledgements
  36.  
  37.       3.0   Limitations
  38.  
  39.       4.0   Introduction
  40.             4.1   The Purpose Of This Document
  41.             4.2   My Assumptions
  42.             4.3   What Is The Formula Parser?
  43.             4.4   Formula Files
  44.  
  45.       5.0   A Quote From Fractint.doc
  46.  
  47.       6.0   Some Basics -- A Walk Through The Mandelbrot Set
  48.             6.1   Complex Numbers And The Complex Plane
  49.             6.2   The Mandelbrot Set
  50.  
  51.       7.0   Anatomy Of A Formula
  52.             7.1   A Formula Is A Program
  53.             7.2   Elements Of A Formula
  54.                   7.2.1   Formula Name
  55.                   7.2.2   Symmetry Declaration
  56.                   7.2.3   Braces
  57.                   7.2.4   Variables
  58.                   7.2.5   Functions
  59.                   7.2.6   Calculation Expressions
  60.                   7.2.7   Assignment Expressions
  61.                   7.2.8   Comparison Expressions
  62.                   7.2.9   Precedence And Parentheses
  63.                   7.2.10  The Comma
  64.                   7.2.11  The Semicolon And Comments
  65.                   7.2.12  The Colon
  66.             7.3   Structure Of A Formula
  67.                   7.3.1   The Name
  68.                   7.3.2   Symmetry
  69.                   7.3.3   Initializing
  70.                   7.3.4   The Iterated Loop
  71.                   7.3.5   The Bailout Test
  72.  
  73.       8.0   A Walk Through A Pair Of Examples
  74.  
  75.       9.0   Approaches To Writing Formulas
  76.             9.1   Using Mathematical Insights
  77.             9.2   Adapting An Existing Algorithm
  78.             9.3   Mutating An Existing Formula
  79.             9.4   The Monkey-At-The-Typewriter Approach
  80.  
  81.       10.0  Style
  82.  
  83.       11.0  Techniques
  84.             11.1  Speed-ups
  85.                   11.1.1  Avoid Exponentiation And Function Calls
  86.                   11.1.2  Avoid Unnecessary Calculations
  87.                   11.1.3  Avoid Unnecessary Iterations
  88.             11.2  Simulating The If..Then Construct
  89.                   11.2.1  How It Works
  90.                   11.2.2  Pitfalls
  91.             11.3  Setting Defaults
  92.             11.4  Using Values From Previous Iterations
  93.             11.5  Dissecting A Formula With Algebra
  94.             11.6  Using A Counter
  95.  
  96.       12.0  Problems
  97.             12.1  Potential Problems With Symmetry
  98.             12.2  Unparsable Expressions Ignored
  99.             12.3  Pathological Formulas
  100.             12.4  A Ghost Story
  101.  
  102.       13.0  Where To Go From Here
  103.             13.1  Learn More About Complex Numbers
  104.             13.2  Learn More About Programming
  105.             13.3  Learn More About Fractals
  106.             13.4  Find Other Fractal Enthusiasts
  107.  
  108.       14.0  Conclusion
  109.  
  110.  
  111.  
  112.    ================
  113.    1.0  LEGAL STUFF
  114.    ================
  115.  
  116.    This document is Copyright (c) 1995 by Bradley Beacham.  All rights
  117.    reserved.  I encourage you to copy and distribute it, so long as you
  118.    leave it unchanged.  It may NOT be used for commercial purposes without
  119.    my explicit prior permission.
  120.  
  121.    I welcome any comments, questions, additional information and
  122.    corrections.  My addresses are:
  123.  
  124.       CompuServe: 74223,2745
  125.  
  126.       Internet  : 74223.2745@compuserve.com
  127.  
  128.       Post      : Bradley Beacham
  129.                   1343 S. Tyler St.
  130.                   Salt Lake City, Utah  84105-2122
  131.                   U.S.A.
  132.  
  133.  
  134.    =====================
  135.    2.0  ACKNOWLEDGEMENTS
  136.    =====================
  137.  
  138.    Most importantly, thanks to Bert Tyler, the original creator of
  139.    Fractint, and to Timothy Wegner and the rest of the Stone Soup Group for
  140.    doing so much to improve it.  Special thanks also to Mark Peterson for
  141.    creating the original formula parser, and to Chuck Ebbert for making it
  142.    go so much faster.  A big thank you to all of the formula authors who
  143.    have taught me so much through their examples, particularly Jonathan
  144.    Osuch.
  145.  
  146.    A big thank-you to Ronald Black.  Ron's excellent questions and
  147.    thoughtful critiques have made this document much better than it would
  148.    have been otherwise.  Thanks also to Bob Carr, Jon Horner, Dan Parchman,
  149.    David Walter and Lee Skinner (and others already mentioned) for making
  150.    the effort to read preliminary versions of this document, and for
  151.    offering insights, suggestions and encouragement.
  152.  
  153.    And finally, an unsolicited plug: If you don't already have a copy of
  154.    FRACTAL CREATIONS by Timothy Wegner and Bert Tyler, get one. It covers
  155.    much of the same material as this document, with the advantage of being
  156.    written by the people most responsible for the development of Fractint.
  157.    It also includes *lots* of stuff that isn't covered here.  Several weeks
  158.    after completing the first drafts of this document, I reread the book
  159.    and realized that some parts of this tutorial are simply paraphrases of
  160.    passages from FRACTAL CREATIONS; although I wasn't consciously imitating
  161.    the book, the debt is obvious.  In this case, imitation really *is* the
  162.    sincerest form of flattery.
  163.  
  164.  
  165.    ================
  166.    3.0  LIMITATIONS
  167.    ================
  168.  
  169.    Except for quoted material, this document was not written by a Fractint
  170.    programmer.  I am a self-taught enthusiast, not a wizard.  Consequently,
  171.    you may find yourself disagreeing with my material, my conclusions, or
  172.    my approach to the subject.  If so, I look forward to hearing from you.
  173.    It may be that we will end up disagreeing, but I am certainly willing to
  174.    hear your critique.  If you think that something needs to be added or
  175.    corrected, please contact me and I'll attempt to fix the problems in a
  176.    future version.
  177.  
  178.    Speaking of versions, bear in mind that I am using Fractint for DOS,
  179.    version 19.0.  Other versions of Fractint may render some of this
  180.    material obsolete or inapplicable.
  181.  
  182.    Please don't be intimidated by the length of the document.  You don't
  183.    *need* to understand it all before you can get started and have a lot of
  184.    fun.  If you find it verbose, let me paraphrase Abraham Lincoln: "Sorry
  185.    it's so long.  If I had more time, it would have been much shorter."
  186.  
  187.    A word of warning for readers in the USA: I have adopted the European
  188.    convention of placing trailing punctuation *outside* a quote.  This
  189.    seems especially appropriate when dealing with literal strings processed
  190.    by the computer, but it also just makes more sense to me.  I hope it
  191.    doesn't bother you.
  192.  
  193.  
  194.    =================
  195.    4.0  INTRODUCTION
  196.    =================
  197.  
  198.    4.1  THE PURPOSE OF THIS DOCUMENT
  199.    ---------------------------------
  200.    I wrote this in an attempt to fill a perceived gap.  While much has been
  201.    written about the Fractint program, the formula parser is still
  202.    something of a mystery to some.  Many people use the parser to create
  203.    beautiful fractal images, but some (most?) have never even attempted to
  204.    write a formula of their own.
  205.  
  206.    There are many possible reasons for this, but I believe one of the most
  207.    pertinent is that the documentation on this subject in the standard
  208.    Fractint package is rather terse.  (This documentation is reproduced in
  209.    section 5.0.)  It provides important information, but it didn't exactly
  210.    leave me with the feeling that I knew what to do next.
  211.  
  212.    Luckily for me, I plunged in anyway, and discovered that I could create
  213.    my own formulas and have a wonderful time doing it.  Most of my time
  214.    spent with Fractint, by far, is devoted to fooling around with the
  215.    formula parser.  It's always exciting to create an interesting new
  216.    image, but it's at least twice as satisfying to me when I find a
  217.    beautiful image, full of wonderful complexity and chaos and order,
  218.    coming from a formula that I wrote.  And I do this despite the fact that
  219.    I am *not* a highly trained mathematician.
  220.  
  221.    You really don't need to be a math wizard to write a Fractint formula!
  222.    (Although if you are, so much the better.)  All you really need is
  223.    patience, persistence, and the willingness to learn.
  224.  
  225.    I learned a lot by reading FRACTAL CREATIONS.  I also learned by reading
  226.    files of formulas written by other people, trying to trace through the
  227.    logic of the formulas and understand what they were doing.  And some of
  228.    what I learned came from simple experimentation and trial-and-error.
  229.  
  230.    Now I will try to summarize the most important things that I have
  231.    learned so far.  I hope this information will help potential formula
  232.    authors get started.  If I am successful, you will be spared much of the
  233.    head-scratching that I endured along the way.
  234.  
  235.  
  236.    4.2  MY ASSUMPTIONS
  237.    -------------------
  238.    I am assuming that you have a copy of the Fractint program, and that you
  239.    have used it enough to know how to choose a formula from the menu
  240.    system.  I also assume that you want to try writing your own formulas.
  241.  
  242.  
  243.    4.3  WHAT IS THE FORMULA PARSER?
  244.    --------------------------------
  245.    It is a part of the excellent fractal-generating program, Fractint.
  246.    While Fractint has many different types of fractal formulas built into
  247.    it, the formula parser allows you to add new fractals without having to
  248.    change the program.  These formulas are stored in simple text files, and
  249.    may be viewed and edited by the user.  
  250.  
  251.  
  252.    4.4  FORMULA FILES
  253.    ------------------
  254.    The standard Fractint package supplies a file of formulas, FRACTINT.FRM,
  255.    but other formula files may be used.  For example, this document
  256.    discusses many sample formulas which are found in the accompanying file,
  257.    FRMTUTOR.FRM, and many other formula files (identified by the extension
  258.    ".frm") may be downloaded from online services or BBSs.
  259.  
  260.    If you have an additional formula file, you should put it in the same
  261.    directory that holds FRACTINT.FRM.  To access it, choose the FORMULA
  262.    type from the Fractint menu, and then hit the F6 key.  You'll be shown a
  263.    menu of available formula files; select the one you want and then you'll
  264.    be able to use its formulas.
  265.    
  266.    This document refers to a few other formula files: FRACT001.FRM,
  267.    BUILTN.FRM, FUBAR.FRM, OVERKILL.FRM and INANDOUT.FRM are available on
  268.    CompuServe and other online services and BBSs.  You won't need any of
  269.    those files to follow the discussion, however.
  270.  
  271.    In addition to using formula files by other people, of course, there is
  272.    another way to add new ones:  WRITE YOUR OWN!
  273.  
  274.    The "how" is simple:  All you need is a simple text-editor, such as the
  275.    Edit program that comes with MS-DOS or the Notepad program that comes
  276.    with Windows.  Just be sure that your editor saves the file as simple
  277.    unformatted ASCII text.  Then follow the basic rules outlined below.
  278.  
  279.    The "why" is even simpler:  Because it's fun.
  280.  
  281.  
  282.    ==============================
  283.    5.0  A QUOTE FROM FRACTINT.DOC
  284.    ==============================
  285.  
  286.    First, let's look at what Fractint.doc says about formulas:
  287.  
  288.    [BEGIN EXCERPT]
  289.     (type=formula)
  290.  
  291.     This is a "roll-your-own" fractal interpreter - you don't even need a
  292.     compiler!
  293.  
  294.     To run a "type=formula" fractal, you first need a text file containing
  295.     formulas (there's a sample file - FRACTINT.FRM - included with this
  296.     distribution).  When you select the "formula" fractal type, Fractint
  297.     scans the current formula file (default is FRACTINT.FRM) for formulas,
  298.     then prompts you for the formula name you wish to run.  After prompting
  299.     for any parameters, the formula is parsed for syntax errors and then
  300.     the fractal is generated. If you want to use a different formula file,
  301.     press <F6> when you are prompted to select a formula name.
  302.  
  303.     There are two command-line options that work with type=formula
  304.     ("formulafile=" and "formulaname="), useful when you are using this
  305.     fractal type in batch mode.
  306.  
  307.     The following documentation is supplied by Mark Peterson, who wrote the
  308.     formula interpreter:
  309.  
  310.     Formula fractals allow you to create your own fractal formulas.  The
  311.     general format is:
  312.  
  313.        Mandelbrot(XAXIS) { z = Pixel:  z = sqr(z) + pixel, |z| <= 4 }
  314.           |         |          |                |              |
  315.          Name     Symmetry    Initial         Iteration       Bailout
  316.                               Condition                       Criteria
  317.  
  318.     Initial conditions are set, then the iterations performed while the
  319.     bailout criteria remains true or until 'z' turns into a periodic loop.
  320.     All variables are created automatically by their usage and treated as
  321.     complex.  If you declare 'v = 2' then the variable 'v' is treated as a
  322.     complex with an imaginary value of zero.
  323.  
  324.               Predefined Variables (x, y)
  325.               --------------------------------------------
  326.               z          used for periodicity checking
  327.               p1         parameters 1 and 2
  328.               p2         parameters 3 and 4
  329.               p3         parameters 5 and 6
  330.               pixel      screen coordinates
  331.               LastSqr    Modulus from the last sqr() function
  332.               rand       Complex random number
  333.  
  334.               Precedence
  335.               --------------------------------------------
  336.               1          sin(), cos(), sinh(), cosh(), cosxx(), tan(),
  337.                          cotan(), tanh(), cotanh(), sqr(), log(), exp(),
  338.                          abs(), conj(), real(), imag(), flip(), fn1(),
  339.                          fn2(), fn3(), fn4(), srand(), asin(), asinh(),
  340.                          acos(), acosh(), atan(), atanh(), sqrt(), cabs()
  341.               2          - (negation), ^ (power)
  342.               3          * (multiplication), / (division)
  343.               4          + (addition), - (subtraction)
  344.               5          = (assignment)
  345.               6          < (less than), <= (less than or equal to)
  346.                          > (greater than), >= (greater than or equal to)
  347.                          == (equal to), != (not equal to)
  348.               7          && (logical AND), || (logical OR)
  349.  
  350.     Precedence may be overridden by use of parenthesis.  Note the modulus
  351.     squared operator |z| is also parenthetic and always sets the imaginary
  352.     component to zero.  This means 'c * |z - 4|' first subtracts 4 from z,
  353.     calculates the modulus squared then multiplies times 'c'.  Nested
  354.     modulus squared operators require overriding parenthesis: c * |z +
  355.     (|pixel|)|
  356.  
  357.     The functions fn1(...) to fn4(...) are variable functions - when used,
  358.     the user is prompted at run time (on the <Z> screen) to specify one of
  359.     sin, cos, sinh, cosh, exp, log, sqr, etc. for each required variable
  360.     function.
  361.  
  362.     Most of the functions have their conventional meaning, here are a few
  363.     notes on others that are not conventional. The function cosxx()
  364.     duplicates a bug in the version 16 cos() function. Then abs(x+iy) =
  365.     abs(x)+i*abs(y), flip(x+iy) = y+i*x, and |x+iy| = x*x+y*y.
  366.  
  367.     The formulas are performed using either integer or floating point
  368.     mathematics depending on the <F> floating point toggle.  If you do not
  369.     have an FPU then type MPC math is performed in lieu of traditional
  370.     floating point.
  371.  
  372.     The 'rand' predefined variable is changed with each iteration to a new
  373.     random number with the real and imaginary components containing a value
  374.     between zero and 1. Use the srand() function to initialize the random
  375.     numbers to a consistent random number sequence.  If a formula does not
  376.     contain the srand() function, then the formula compiler will use the
  377.     system time to initialize the sequence.  This could cause a different
  378.     fractal to be generated each time the formula is used depending on how
  379.     the formula is written.
  380.  
  381.     Remember that when using integer math there is a limited dynamic range,
  382.     so what you think may be a fractal could really be just a limitation of
  383.     the integer math range.  God may work with integers, but His dynamic
  384.     range is many orders of magnitude greater than our puny 32 bit
  385.     mathematics!  Always verify with the floating point <F> toggle.
  386.  
  387.     The possible values for symmetry are:
  388.  
  389.     XAXIS,  XAXIS_NOPARM
  390.     YAXIS,  YAXIS_NOPARM
  391.     XYAXIS, XYAXIS_NOPARM
  392.     ORIGIN, ORIGIN_NOPARM
  393.     PI_SYM, PI_SYM_NOPARM
  394.     XAXIS_NOREAL
  395.     XAXIS_NOIMAG
  396.  
  397.     These will force the symmetry even if no symmetry is actually present,
  398.     so try your formulas without symmetry before you use these.
  399.    [END EXCERPT]
  400.  
  401.  
  402.    =====================================================
  403.    6.0  SOME BASICS -- A WALK THROUGH THE MANDELBROT SET
  404.    =====================================================
  405.  
  406.    6.1  COMPLEX NUMBERS AND THE COMPLEX PLANE
  407.    ------------------------------------------
  408.    First, a disclaimer: This document is not intended to be a complete
  409.    course on complex math. If you want to learn more about complex numbers,
  410.    find a good algebra text.  FRACTAL CREATIONS also has a good summary of
  411.    the math involved here.  But even if you are unfamiliar with complex
  412.    numbers, read on.  Don't be intimidated by the word "complex"!
  413.  
  414.    Let's go over some of the fundamental concepts that you'll need to get
  415.    started.  Since you already have a copy of Fractint, you have
  416.    undoubtedly spent some time exploring the Mandelbrot set (M-set), easily
  417.    the most famous fractal.  By reviewing some of the details about how
  418.    this fractal is generated, you'll be better equipped to imagine new
  419.    varieties of fractal formulas.
  420.  
  421.    This fractal is called a "set" because it is a set of points on a
  422.    two-dimensional plane, somewhat like the graphs you probably had to draw
  423.    in your algebra classes.  The Mandelbrot set exists in the  "complex
  424.    plane", so-called because it is composed of complex numbers.
  425.  
  426.    You should know that a complex number has two parts: the real and the
  427.    imaginary.  Just as the real number system is the union of the rational
  428.    and the irrational number sets, so the complex number system is a union
  429.    of the real and the imaginary numbers.  An imaginary number is any real
  430.    number multiplied by the square root of -1.  This square root of -1 has
  431.    a special name: i. So a complex number which had a real component 8.5
  432.    and an imaginary component 3.2 could be written as 8.5 + 3.2i, or in
  433.    parser notation as (8.5,3.2).  And because the reals are a subset of
  434.    the complex numbers, any real number is also a complex number; that is,
  435.    2 = 2 + 0i or (2,0).
  436.  
  437.    You can perform arithmetic with complex numbers; addition, subtraction,
  438.    multiplication and division are all possible, and follow the rules of
  439.    basic algebra with 'i' being treated as a variable.  Fractint also
  440.    supports exponents (X^Y means X to the power of Y) and a variety of
  441.    functions that operate on complex numbers, such as sin(), tan(), etc.
  442.    I won't belabor this subject further for now, except to point out that
  443.    when a complex number is operated on mathematically, both the real and
  444.    the imaginary parts of the number may change; this concept is important
  445.    in the discussion that follows.  (A further discussion of complex
  446.    arithmetic can be found in section 11.5, "Dissecting A Formula With
  447.    Algebra", and functions are described in section 7.2.5, "Functions".)
  448.  
  449.    In the complex plane, the horizontal axis corresponds to the real number
  450.    line while the vertical axis corresponds to the imaginary number line.
  451.    Any particular complex number, therefore, can be plotted as a point on
  452.    the plane, and any point on the plane has a complex number that
  453.    corresponds to it.  The real part of the number determines the
  454.    horizontal placement of the point, and the imaginary number determines
  455.    the vertical.  The origin of the graph (the place where the axes cross)
  456.    is 0 + 0i.
  457.  
  458.  
  459.    6.2  THE MANDELBROT SET
  460.    -----------------------
  461.    As a prelude to examining formulas, let's look at the processes involved
  462.    in deciding whether a particular point on the complex plane belongs to
  463.    the M-set.  Since the concepts involved are somewhat abstract, we'll try
  464.    to create an analogy that is easier to visualize, and talk in very
  465.    general terms at first.
  466.  
  467.    Imagine a circle drawn on the ground, with a little ball sitting in the
  468.    center.  We'll pick a spot on the ground, somewhere within the circle,
  469.    and call that the "test point".  Now we will start moving the ball
  470.    in discrete steps according to a set of specific rules (which we won't
  471.    describe yet) and watch the path that the ball takes.
  472.  
  473.    The first step always moves the ball over to our test point.  The second
  474.    step moves it to a different location, and the third step to yet another
  475.    location.  We'll keep applying the rules of movement, over and over,
  476.    calculating a new position for the ball each time, and counting the
  477.    number of moves we make.
  478.  
  479.    If we try this process for several different test points, we will see
  480.    something very interesting.  For some test points, the ball seems to
  481.    settle into a fairly predictable path, something like the orbit of an
  482.    object in space -- it moves from spot to spot, but it never strays
  483.    outside of the circle drawn on the ground.  For other test points, the
  484.    ball may move around within the circle for a while and then exit.  And
  485.    for some test points, the ball leaves the circle after very few moves.
  486.  
  487.    Now let's try to categorize the different test points, according to the
  488.    behavior of the moving ball.  If the ball never leaves the circle, we'll
  489.    color the test point blue, but if the ball *does* leave the circle then
  490.    we'll give the test point a different color, based on the number of
  491.    steps required make the ball cross the boundary.  If you did this for
  492.    enough test points, an image of the Mandelbrot set would appear!
  493.  
  494.    Let's move beyond our analogy now and get more specific.  Instead of the
  495.    ground, visualize the complex plane, and instead of a ball, visualize a
  496.    moving point called 'Z'.  Now picture a circle on the plane, centered on
  497.    the origin, with a radius of 2.
  498.  
  499.    First, we'll choose a point to test; let's say 0.2 + 0.5i.  Next we must
  500.    define two complex variables, Z and C, such that Z = 0 + 0i and C = the
  501.    value of the test point, ie C = 0.2 + 0.5i.
  502.  
  503.    Then the following algorithm is iterated (repeated over and over):
  504.    Calculate the value of Z^2 + C, and then place the result in Z.  Since Z
  505.    has a new value, find the point on the complex plane that corresponds to
  506.    Z, and then check to see if the distance between Z and the origin
  507.    exceeds 2.  If the distance is greater than 2 (Z is outside of the
  508.    circle) then the test point is *not* in the Mandelbrot set, and you may
  509.    stop calculating values for Z. But if Z remains in the circle, we move
  510.    back to the top of the loop and calculate a new value for Z and check
  511.    it again.
  512.  
  513.    In our example, if we start with Z = 0 + 0i and C = 0.2 + 0.5i, after the
  514.    first time through the loop we now see that Z = 0.2 + 0.5i.  Since this
  515.    falls within the "bailout" circle we will calculate again, with the
  516.    result that now Z = -0.01 + 0.7i.  The next iteration ends with Z
  517.    holding the value -0.2899 + 0.486i.
  518.  
  519.    We could repeat this process over and over, noting that Z shifts its
  520.    position with each iteration and yet never exits the bailout circle.
  521.  
  522.    But because our time and patience have limits, we couldn't (and wouldn't
  523.    want to) repeat the experiment an infinite number of times!  This is
  524.    where the value for maximum iterations, set on Fractint's <X> menu,
  525.    comes in.  The default value for maximum iterations is 150.  This means
  526.    that if the program goes through the iterated loop 150 times, and Z has
  527.    never strayed outside the bailout circle, Fractint *assumes* that the
  528.    test point (C) is indeed part of the set, colors it accordingly, and
  529.    moves on to another test point.
  530.  
  531.    Now what if the test point had the value 1.5 - 1.2i?  After the first
  532.    iteration, Z = 1.5 - 1.2i, which is still barely within the bailout
  533.    circle.  After the second iteration, Z = 2.31 - 4.8i.  This time Z has
  534.    strayed out of the circle, so the test point is *not* part of the M-set.
  535.    Because the bailout condition has been met, Fractint stops iterating the
  536.    formula and colors the test point.  By default, Fractint chooses a color
  537.    based on the number of iterations required to make Z exit the bailout
  538.    circle, but this can be changed by various options on the Fractint
  539.    menus.
  540.  
  541.    I have mentioned two conditions that cause Fractint to stop looping
  542.    through the formula: 1) the bailout condition is met, and 2) the maximum
  543.    number of iterations has been reached.  There is one other condition
  544.    that can cause Fractint to stop iterating: periodicity.  If Fractint
  545.    detects that Z has fallen into a periodic loop, repeating the same
  546.    values over and over without leaving the bailout circle, it reasonably
  547.    assumes that Z will *never* exit the circle and stops iterating even
  548.    though the maximum number of iterations may not have been performed yet.
  549.    This is one of the reasons that Fractint is so much faster than other
  550.    fractal programs you may have tried.
  551.  
  552.    We're almost there, but before Fractint can create a picture of the
  553.    Mandelbrot set it must settle a couple of problems, both of which have
  554.    to do with infinity.
  555.  
  556.    First, you should see that in the complex plane there is an infinite
  557.    number of points.  Obviously Fractint can't test them all.  So, it
  558.    chooses a subset of the points, defined by the corners of your zoom box,
  559.    and only considers points within that box.
  560.  
  561.    But even within that box, there is an infinity of possible points to
  562.    test.  Here, the resolution of your computer display is used to resolve
  563.    the problem.  Remember that a picture on your screen is composed of
  564.    little dots called pixels.  Fractint chooses points on the plane that
  565.    correspond to the locations of the pixels, and only tests those points.
  566.    (It can create images at a higher resolution than your display via the
  567.    "disk-video" modes, but we won't go into that.)  One point per pixel is
  568.    enough.
  569.  
  570.    So now we have a finite number of points to test.  Fractint moves from
  571.    pixel to pixel, finding the value on the complex plane that corresponds
  572.    to each pixel and performing the test loop.  Pixels are colored dark
  573.    blue (by default) if they are deemed part of the M-set, and a different
  574.    color (normally based on number of iterations needed to exit the bailout
  575.    circle) if they are not.
  576.  
  577.    We can instruct Fractint to do all of this (and more) with the following
  578.    formula:
  579.  
  580.      Mandelbrot (xaxis) { ;The classic Mandelbrot set
  581.        z = 0, c = pixel:
  582.          z = z*z + c
  583.          |z| < 4
  584.      }
  585.  
  586.  
  587.    =========================
  588.    7.0  ANATOMY OF A FORMULA
  589.    =========================
  590.  
  591.    7.1  A FORMULA IS A PROGRAM
  592.    ---------------------------
  593.    Perhaps the most fundamental point I could make is that a Fractint
  594.    formula is actually a little computer program, not a set of mathematical
  595.    equations.  If you don't take this into account, you will end up very
  596.    confused!  For example, consider the following statement:
  597.  
  598.      z = z + 1
  599.  
  600.    Interpreted as an equation, that's nonsense.  Instead, it is a program
  601.    statement that means "Calculate the value of z + 1, and then set z to
  602.    equal that value."  Variables in a Fractint formula can, and often do,
  603.    change values from one iteration to the next.
  604.  
  605.  
  606.    7.2  ELEMENTS OF A FORMULA
  607.    --------------------------
  608.    Let's look at some formulas and see what parts they may have.  We'll
  609.    start with the following formulas:
  610.  
  611.      frm-A (xaxis) { ;Another formula for the Mandelbrot set
  612.        z = const = pixel:
  613.          z = z^2 + const
  614.          |z| < 4
  615.      }
  616.  
  617.      frm-B { ;A generalized Julia formula
  618.              ;For the traditional Julia algorithm, set FN1() to SQR,
  619.              ;and then try different values for P1
  620.        z = pixel:
  621.          z = fn1(z) + p1
  622.          |z| <= (4 + p2)
  623.      }
  624.  
  625.    [7.2.1  FORMULA NAME]  Each formula begins with a name, so that you can
  626.    select it from the Fractint formula menu.
  627.  
  628.    [7.2.2  SYMMETRY DECLARATION]  You should notice that frm-A contains a
  629.    declaration of symmetry: (xaxis).  This is an instruction to Fractint
  630.    that says, in effect, "The images created by this formula will be
  631.    symmetrical around the X axis, so use the appropriate symmetry-drawing
  632.    technique".  After being told this, Fractint will (when possible) use
  633.    the following shortcut:  It will only iterate the formula for pixels
  634.    that fall on one side of the X axis.  After testing a pixel and coloring
  635.    it, it will "mirror" the result by finding the corresponding pixel on
  636.    the opposite side of the X axis and giving it the same color.  So at the
  637.    default zoom, only *half* of the pixels need to be tested!  Judicious
  638.    use of this technique speeds up the program, but it can cause problems
  639.    if not used correctly.  I'll talk about this in more detail later.
  640.  
  641.    [7.2.3  BRACES]  The braces define where the body of the formula begins
  642.    and ends.  There should be just one opening brace ({) and one closing
  643.    brace (}) per formula.
  644.  
  645.    [7.2.4  VARIABLES]  Examples in these formulas include z, c, and pixel.
  646.    Variables in Fractint formulas are always of the complex number type.
  647.    You may give them any names you like, but there are a few predefined
  648.    variables:  pixel, p1, p2, p3, lastsqr, rand, and z.  Pixel, of course,
  649.    gets the complex value corresponding to the current pixel.  P1, p2 and
  650.    p3 (if used) can have their values set by the user at the <Z> menu.
  651.    Lastsqr was used in a speedup technique in the earlier days of the
  652.    parser, but is seldom used now.  Rand can be used if a random complex
  653.    number is desired.
  654.  
  655.    It doesn't matter whether you use upper or lower case; "pixel", "PIXEL"
  656.    and "Pixel" all refer to the same variable.
  657.  
  658.    Z is the name you should give to the primary variable; usually this is
  659.    the variable that is tested at the end of each iteration.  Naming it 'Z'
  660.    is not *required* but it is highly recommended, because Fractint's
  661.    periodicity testing is set up to look for patterns in the values of Z.
  662.  
  663.    You may wonder about the difference between Z and |Z|.  Those '|'
  664.    characters change the meaning completely.  While Z is just the name of a
  665.    variable, |Z| tells Fractint to determine the distance (the modulus)
  666.    between Z and the origin; this is why it is used in the bailout test.
  667.    In actuality, Fractint calculates the *square* of the distance, so the
  668.    '|' characters are sometimes called the "modulus squared" operator;
  669.    more on that in a moment.
  670.  
  671.    Let's use a concrete example.  Suppose Z has a value of (3,-4), or
  672.    3 - 4i.  We can use the Pythagorean theorem to determine the distance
  673.    between this point and (0,0).  If you were to find this point by first
  674.    drawing a horizontal line from (0,0) to (3,0), and then a vertical line
  675.    from (3,0) to (3,-4), you would have two legs of a right triangle, while
  676.    the line from (3,-4) to (0,0) would be the hypotenuse.  Draw this out on
  677.    a piece of graph paper if it isn't clear so far.  Now the Pythagorean
  678.    theorem states that the sum of the squares of the legs will equal the
  679.    square of the hypotenuse. This means the distance from the origin to Z
  680.    can be calculated as the square root of (3^2 + -4^2), which works out to
  681.    5.  Obviously, this Z has strayed outside the bailout circle!
  682.  
  683.    Fractint uses a small modification of the system I just described.
  684.    Instead of checking to see if square_root(x^2 + y^2) < 2, Fractint
  685.    checks if x^2 + y^2 < 2^2.  These two expressions are mathematically
  686.    equivalent.  The advantage of the second way is that Fractint can avoid
  687.    calculating the square root, which is much harder to do than calculating
  688.    a square!  This is another way that Fractint speeds up the calculation
  689.    process.  It also explains why the bailout tests in the Mandelbrot and
  690.    frm-A formulas are written "|z| < 4" rather than "|z| < 2".
  691.  
  692.    This "modulus squared" technique is a bit subtle, and can lead to some
  693.    confusion if not properly understood, but it has speed benefits that few
  694.    of us would want to give up!
  695.  
  696.    Although P1, P2 and P3 have predefined names, the values of these
  697.    variables can be chosen by the user when the formula is first selected
  698.    or via the <Z> menu.  For example, in the frm-B formula, P1 is used as a
  699.    user-determined constant that is added to Z each iteration, while P2
  700.    varies the bailout condition: the radius of the bailout circle will be
  701.    the square root of (4 + p2).
  702.  
  703.    You can add other variables with names of your choice.  If you'll
  704.    compare frm-A with the Mandelbrot formula, you'll see that (among other
  705.    differences) there is a variable called 'c' in Mandelbrot and a
  706.    corresponding variable called 'const' in frm-A.  These variables serve
  707.    exactly the same purpose -- they just have different names.  The
  708.    variable name 'c' is traditionally used in Mandelbrot formulas, but
  709.    Fractint does not require it.  All of this is just to illustrate that
  710.    you have the power to choose your own names for your variables.  It is
  711.    good practice to avoid confusion where possible; one way to help is by
  712.    using descriptive variable names.  But as I noted above, use the
  713.    variable name 'Z' for your "main" variable whenever possible.
  714.  
  715.    [7.2.5  FUNCTIONS]  Fractint has several functions built into it,
  716.    including sin(), cos(), and so on.  A list of them appears at the end of
  717.    this section.  A function is something like a little machine -- you give
  718.    it a number, it performs some operations on it, and then it gives you
  719.    back a (usually) different number.  Each function has a name, and is
  720.    immediately followed by a pair of parentheses.  Within these parentheses
  721.    you should put the variable or expression that should be "fed" to the
  722.    function. For example, "SQR(Z)" means "calculate the square of Z".
  723.    Functions can be nested, and the results of the inner function will
  724.    become the input for the outer function.  For example, "COS(SQR(Z))"
  725.    means "calculate the square of Z, and then find the cosine of the
  726.    result".
  727.  
  728.    You can explicitly write specific functions into your formulas.  For
  729.    example, a formula for the Mandelbrot set might include the expression
  730.    "z = sqr(z) + c".
  731.  
  732.    Another option is to include user-selectable functions, as in frm-B.
  733.    You may include up to four different ones, and they are designated
  734.    FN1() ... FN4().  They are given specific values on the same screen as
  735.    P1, P2 and P3; that is, the <Z> menu.  So the example from the previous
  736.    paragraph could also be written "z = fn1(z) + c".  Of course, this would
  737.    require the user to set FN1 to SQR in order to make the M-set; other
  738.    functions would give different results.  With Fractint version 19.0,
  739.    there are 26 functions available via the user-selectable functions!
  740.  
  741.    The user-selectable functions are a double-edged sword. On the one hand,
  742.    they allow for much more flexibility while exploring, because a formula
  743.    becomes capable of creating many different kinds of fractals.  Using
  744.    combinations of user-selectable functions multiplies the possibilities;
  745.    a formula that uses just two of them is the equivalent of 676 different
  746.    formulas with hard-coded (explicitly written) functions, while a formula
  747.    that uses all four is the equivalent of 456,976 hard-coded formulas!  In
  748.    this way, a formula really becomes a "formula template" and helps you
  749.    save space and time.
  750.  
  751.    On the other hand, this sort of formula can be confusing to use,
  752.    especially for the new or casual user.  Someone who just wants to
  753.    explore the Mandelbrot set may not appreciate being asked to know and
  754.    remember that they must set FN1 to SQR in order to get what they are
  755.    looking for.  There may be incredible images buried within such a
  756.    formula, but they require the user to do some digging to get to them!
  757.  
  758.    I must confess a tendency to go hog-wild with these user-selectable
  759.    functions, especially in my earlier efforts.  My more recent formulas
  760.    typically just use two of them.  In most cases two should be plenty, I
  761.    think, but of course that's entirely up to you.
  762.  
  763.    Now here's a list of the user-selectable functions.  Remember that we
  764.    are using the complex number system here, so many functions are
  765.    different from (but related to) the standard trigonometric functions
  766.    that you might know about; more information about these functions can be
  767.    found in the Fractint documentation.  Also note that some of the
  768.    comments use the word "argument" -- this is the number that is "fed" to
  769.    the function.
  770.  
  771.      abs() ---- Real and Imaginary Absolute Value.  Returns the argument
  772.                 after making sure both the real and imaginary parts are
  773.                 positive.  Abs(-3,-4) == (3,4).
  774.      acos() --- Arccosine.
  775.      acosh() -- Hyperbolic Arccosine.
  776.      asin() --- Arcsine.
  777.      asinh() -- Hyperbolic Arcsine.
  778.      atan() --- Arctangent.
  779.      atanh() -- Hyperbolic Arctangent.
  780.      cabs() --- Complex Absolute Value.  Returns the distance between
  781.                 the complex number and the origin.
  782.                 Cabs(-3,4) == 5.
  783.      conj() --- Complex Conjugate.  Returns the argument after reversing
  784.                 the numeric sign of the imaginary part.
  785.                 Conj(1,-3) == (1,3) and conj(1,3) == (1,-3).
  786.      cos() ---- Cosine.
  787.      cosh() --- Hyperbolic Cosine.
  788.      cosxx() -- When the cos() function was first added to Fractint, it had
  789.                 a programming bug.  After the bug was discovered, the
  790.                 corrected cos() was added, but the original function was
  791.                 retained under the name cosxx(), so that formulas and
  792.                 images made with the original function could be recreated.
  793.                 Cosxx() returns the same value as cos(), except that the
  794.                 sign of the imaginary part is reversed.
  795.                 Cosxx(z) == conj(cos(z)).
  796.      cotan() -- Cotangent.
  797.      cotanh() - Hyperbolic Cotangent.
  798.      exp() ---- Exponential.
  799.      flip() --- Returns the argument after swapping the values of the real
  800.                 and imaginary parts.  Flip(1,-3) == (-3,1).
  801.      ident() -- Identity.  Returns the argument unchanged.  Suppose a
  802.                 formula contains the expression "fn1(z*z) + c", but you
  803.                 just want to see the results of z*z + c.  You can do this
  804.                 without rewriting the formula by setting fn1() to ident().
  805.                 Ident(z) == z.
  806.      log() ---- Natural Log.
  807.      recip() -- Reciprocal.
  808.      sin() ---- Sine.
  809.      sinh() --- Hyperbolic Sine.
  810.      sqr() ---- Square.
  811.      sqrt() --- Square Root.
  812.      tan() ---- Tangent.
  813.      tanh() --- Hyperbolic Tangent.
  814.      zero() --- Returns 0.  This allows you to "turn off" an expression
  815.                 without rewriting the formula.  If you were using a
  816.                 Mandelbrot mutation with the iterated section
  817.                 "z = z*z + c + fn1(z)", you could see the normal Mandelbrot
  818.                 set by setting fn1() to zero().  Zero(1,-3) == (0,0).
  819.  
  820.    A few other functions can be hard-coded, but aren't available through
  821.    the user-selectable functions.
  822.  
  823.      imag() --- Returns the imaginary part of the argument as a real
  824.                 number. The imaginary part of the returned value is zero.
  825.                 Imag(1,3) == (3,0).
  826.      real() --- Returns the real part of the argument.  The imaginary part
  827.                 of the returned value is zero.  Real(1,3) == (1,0).
  828.      srand() -- Uses the argument to "seed" the random-number generator.
  829.  
  830.    [7.2.6  CALCULATION EXPRESSIONS]  It's hard to imagine a formula where
  831.    no calculations take place.  These calculations are defined in
  832.    expressions such as "z*z + c".  You can find a list of the allowed
  833.    mathematical operators in the Fractint documentation.
  834.  
  835.    [7.2.7  ASSIGNMENT EXPRESSIONS]  After you calculate something, you'll
  836.    often want to store the answer somewhere.  To do this you should use the
  837.    assignment operator: '='.  For example, the expression "A = B + C" means
  838.    "Find the value of B + C, and set A equal to that value."
  839.  
  840.    You can also "chain" assignments, as I did in frm-A.  The expression
  841.    "z = const = pixel" results in both 'z' and 'const' getting the value of
  842.    the variable 'pixel'.
  843.  
  844.    [7.2.8  COMPARISON EXPRESSIONS]  Often you'll want to compare one value
  845.    to another, to determine what should happen next.  The most common
  846.    example is the bailout test.  Comparison expressions take such forms as:
  847.    A < B  (is A less than B?), A >= B  (is A greater than or equal to B?),
  848.    or A == B (is A equal to B?).
  849.  
  850.    There are a couple of things you should know about the way Fractint
  851.    makes comparisons between complex numbers.
  852.  
  853.    First, be aware that only the *real* parts of complex numbers are
  854.    compared.  To Fractint, if A = (1,1000) and B = (2,1), then A < B.
  855.    Please note that we are comparing the *values* of complex numbers here,
  856.    not the *distance* of those numbers to the origin.  So for this case
  857.    A < B, but |A| > |B|.
  858.  
  859.    Second, you should know that comparisons will always evaluate to either
  860.    TRUE or FALSE.  This may seem like a simple-minded observation, but
  861.    we'll come back to it later.
  862.  
  863.    [7.2.9  PRECEDENCE AND PARENTHESES]  Precedence means that Fractint has a
  864.    preferred order for performing mathematical operations.  Multiplication
  865.    has a higher precedence than addition, for instance.  This means that
  866.    the expression "5 + 2 * 3" would evaluate to 30, not 21, because the
  867.    multiplication will take place before the addition.  But suppose 21 is
  868.    the answer that you really intended; now what?  The answer is to use
  869.    parentheses to override the "natural" precedence order, as in
  870.    "(5 + 2) * 3".  You'll find a table of the precedence order in the quote
  871.    from the Fractint documentation.
  872.  
  873.    Parentheses can also be used simply to make the meaning of a complicated
  874.    expression clearer to you and your readers.  Just remember that your
  875.    parentheses *must* come in matched sets.  For every '(' there must be
  876.    one ')'.
  877.  
  878.    [7.2.10  THE COMMA]  The comma (,) lets you put more than one expression
  879.    on a single line without confusing the parser.  These two formulas are
  880.    logically and functionally the same:
  881.  
  882.      frm-C1 {
  883.        z = 0
  884.        c = pixel:
  885.          z = sqr(z) + c
  886.          |z| < 4
  887.      }
  888.  
  889.      frm-C2 { z = 0, c = pixel: z = sqr(z) + c, |z| < 4 }
  890.  
  891.  
  892.    Although functionally the same, you may prefer the "style" of one over
  893.    the other.  We'll return to style in section 10.0.
  894.  
  895.    In some formula files, you may notice formulas in which almost every
  896.    line ends with a comma or semicolon.  (For examples, look at Cardioid
  897.    and CGNewtonSinExp.)  I have been told that an earlier version of the
  898.    parser required commas or semicolons to separate the lines, but this
  899.    requirement was subsequently removed.  The practice continues, though,
  900.    apparently spread by simple imitation.  (I say this with some confidence
  901.    because I did the same thing at first.)  While ending a line with a
  902.    comma or semicolon is not necessary, it shouldn't cause any harm either.
  903.    My preference is to use them only when needed.
  904.  
  905.    [7.2.11  THE SEMICOLON AND COMMENTS]  The semicolon (;) tells the
  906.    parser, in essence, "From this point to the end of the line, ignore
  907.    everything. It is not to be calculated."  This allows you to add
  908.    comments to your formulas.  Do it!  It makes your formulas easier for
  909.    someone else to understand, and it may help you understand your own
  910.    formulas later on, after they are not so fresh in your mind.
  911.  
  912.    [7.2.12  THE COLON]  The colon (:) has only one function in a Fractint
  913.    formula (so far as I know) and that is to mark the end of the
  914.    initialization section and the beginning of the iterated loop.  I'll
  915.    explain that in more detail in the section that follows.
  916.  
  917.  
  918.    7.3  STRUCTURE OF A FORMULA
  919.    ---------------------------
  920.    Now that we've looked at some of the parts we can use, let's talk about
  921.    how to put them together into a working formula.  In my opinion, any
  922.    formula can be divided into at least three sections and at most five, with
  923.    four being the most common arrangement.  The three required sections are
  924.    1) the name, 2) the initialization section, and 3) the body of the
  925.    iterated loop.  Also present in almost all formulas is 4) a bailout
  926.    test.  The section most often omitted is 5) the symmetry declaration.
  927.  
  928.    Our Mandelbrot formula has all five:
  929.  
  930.      Name       Symmetry
  931.        |          |
  932.        V          V
  933.      Mandelbrot (xaxis) {
  934.        z = 0, c = pixel:  <-- Initialization
  935.          z = z*z + c      <-- Body of loop
  936.          |z| < 4          <-- Bailout test
  937.      }
  938.  
  939.    [7.3.1  THE NAME]  Any formula must have a name, or else Fractint will
  940.    not be able to find it.  You have a lot of latitude in choosing a name
  941.    for your formula, but there are a few limitations.  The characters in a
  942.    formula name must be contiguous; if you tried to name a formula "my new
  943.    formula", it would appear on the formula menu as "my".  (Working
  944.    alternatives include "my_new_formula" or "MyNewFormula".)  Also, be sure
  945.    that you don't put two formulas with the same name into a formula file;
  946.    they'll both appear on the menu but only one of them will be available.
  947.    Finally, avoid using formula names longer than eighteen characters.  At
  948.    best, Fractint ignores the extra characters, but in my experiments I
  949.    have locked-up Fractint with too-long formula names.
  950.  
  951.    [7.3.2  SYMMETRY]  The parser reads this part of the formula, if present,
  952.    just *once per image*.  In it, you tell Fractint to assume that a
  953.    formula will produce fractals with a certain kind of symmetry and
  954.    Fractint will simply take your word for it, with the resulting images
  955.    being drawn more quickly.  There are dangers involved, though.  I'll
  956.    talk about them in section 12.1, "Potential Problems With Symmetry".
  957.  
  958.    [7.3.3  INITIALIZING]  The initialization process takes place just *once
  959.    per pixel*.  This is the part of the formula where the parser sets up
  960.    variables and gives them initial values.  Any uninitialized variables
  961.    start out with the value (0,0).  The initialization section begins after
  962.    the opening brace and extends to the colon.
  963.  
  964.    (Be careful to only use one colon per formula.  Depending on its
  965.    location, an extra colon may trigger error messages or cause the formula
  966.    to behave in unintended ways.  At best, the redundant colon is ignored.)
  967.  
  968.    In our Mandelbrot example, the following happens once per pixel:  Z is
  969.    set to 0 (since the imaginary part is unspecified, it is also set to 0)
  970.    and C is set to the value of PIXEL.  Recall that PIXEL gets its value
  971.    automatically from Fractint.
  972.  
  973.    [7.3.4  THE ITERATED LOOP]  This is where the real computational action
  974.    takes place.  The iterated loop begins immediately after the colon and
  975.    extends to the end of the formula.  The entire section is repeated over
  976.    and over until 1) the bailout condition is met, 2) the maximum number of
  977.    iterations have taken place, or 3) periodicity has been detected.
  978.  
  979.    If you are familiar with the DO/WHILE loop construct found in Pascal, C,
  980.    and other languages, then you will understand how a parser loop works.
  981.    The entire body of the loop is performed at least once, and then the
  982.    parser decides whether it is appropriate to loop again (that is, move
  983.    back to the colon) or to quit iterating.
  984.  
  985.    [7.3.5  THE BAILOUT TEST]  Although this is technically a part of the
  986.    iterated loop (because it is performed once per iteration) the bailout
  987.    test warrants further description.
  988.  
  989.    Look at the bailout test for the Mandelbrot formula: |z| < 4.  From our
  990.    previous discussion of how the Mandelbrot algorithm works, we can see
  991.    that Fractint interprets this to mean "If the modulus squared of z
  992.    is less than 4, then perform the loop again."  In other words, if the
  993.    answer to the bailout test is *false*, then it is time to bail out of
  994.    the loop.
  995.  
  996.    I should point out that it is possible to write a formula that has no
  997.    bailout test, but I don't recommend it.  I'll come back to this subject
  998.    in section 12.3, "Pathological Formulas".
  999.  
  1000.  
  1001.    ======================================
  1002.    8.0  A WALK THROUGH A PAIR OF EXAMPLES
  1003.    ======================================
  1004.  
  1005.    Now let's try to tie all of the parts together by looking at some
  1006.    examples in detail.  The next two formulas are taken from FRACT001.FRM,
  1007.    with some comments added.
  1008.  
  1009.      Cardioid { ;author not listed
  1010.        z = 0, x = real(pixel), y=imag(pixel),
  1011.        c=x*(cos(y)+x*sin(y)):
  1012.        z=sqr(z)+c,
  1013.        |z| < 4
  1014.      }
  1015.  
  1016.      CGNewtonSinExp (XAXIS) { ;by Chris Green
  1017.        ; Use floating point, and set P1 to some positive value.
  1018.        z=pixel:
  1019.        z1=exp(z),
  1020.        z2=sin(z)+z1-z,
  1021.        z=z-p1*z2/(cos(z)+z1),
  1022.        .0001 < |z2|
  1023.      }
  1024.  
  1025.    These two formulas have some similarities, but their differences are
  1026.    especially interesting.  Let's look at some of the differences, section
  1027.    by section.
  1028.  
  1029.    First, notice that CGNewtonSinExp declares XAXIS symmetry, while
  1030.    Cardioid has no symmetry declaration.  This part is always optional.
  1031.  
  1032.    Next, compare the initialization sections.  In CGNewtonSinExp, this
  1033.    section is very simple, but in Cardioid it is much more complicated.
  1034.  
  1035.    Let's trace through Cardioid's "per-pixel" section.  First, z is set to
  1036.    0.  Next, the "real" function is used.  This function takes a complex
  1037.    number as its argument and returns the value of the real part of the
  1038.    number.  So the real part of x is set to equal the real component of
  1039.    pixel.  Similarly, the real part of y is set to equal the imaginary part
  1040.    of pixel.  Finally, c gets a value based on a rather complicated looking
  1041.    expression that involves x and y and a pair of functions.
  1042.  
  1043.    Now think back to the discussion of the Mandelbrot set.  Remember that
  1044.    to complete an image, Fractint performs a set of computations (including
  1045.    the iterated loop) for each pixel of the image, moving from one
  1046.    pixel to another as the test point.  This means that each time the
  1047.    parser executes the initialization section of Cardioid, the variable
  1048.    "pixel" will have a different value.  This in turn means that the value
  1049.    of c will vary from one pixel to another.
  1050.  
  1051.    By contrast, the initialization section of CGNewtonSinExp is utter
  1052.    simplicity: z gets the value of pixel.
  1053.  
  1054.    Now look at the iterated sections of each formula, and remember that
  1055.    this section extends from the colon clear down to the end of the
  1056.    formula.  Here the tables are turned.  Cardioid has a very simple iterated
  1057.    section - just one line plus the bailout test.  CGNewtonSinExp requires
  1058.    three lines to complete a comparatively complicated set of calculations
  1059.    before performing the bailout test.  Four variables and three functions
  1060.    are involved, plus addition, subtraction, multiplication and division.
  1061.    
  1062.    Finally, let's look at the bailout tests.  Cardioid has the familiar test,
  1063.    "|z| < 4", which means "Stop iterating if the distance between z and the
  1064.    origin exceeds 2".  (Re-read the passage in section 7.2.4 describing the
  1065.    modulus-squared operator if this isn't clear.)  Broadly speaking, this
  1066.    sort of test says "Count how many times the formula must be iterated
  1067.    before z heads off in the direction of infinity."  And for points that
  1068.    are not part of the set, z tends to do just that: the different
  1069.    color-bands of the standard M-set image reflect how many iterations were
  1070.    required before z crossed the line.  Fractals based on this general
  1071.    algorithm are sometimes called "Escape-Time To Infinity" fractals,
  1072.    because membership in the set is based on whether or not z "escapes"
  1073.    from the bailout circle.
  1074.  
  1075.    By contrast, look at the bailout test for CGNewtonSinExp,
  1076.    ".0001 < |z2|".  Although the tests may look similar at first glance,
  1077.    there is something fundamentally different here.  In this formula, the
  1078.    parser is instructed to keep iterating as long as |z2| *exceeds* the
  1079.    value .0001; that is, as long as it is *outside* the bailout circle.
  1080.    This kind of formula is sometimes called "Escape-Time To A Finite
  1081.    Attractor", and is used in the various "Newton" and "Halley" fractal
  1082.    types found in Fractint.
  1083.  
  1084.    Let's recap by tracing through both formulas once more, looking for
  1085.    details that we may have missed the first time through.
  1086.  
  1087.    First, when Cardioid begins, Fractint notes the location of the corners
  1088.    of the zoom box, so the complex values that correspond to the pixels may
  1089.    be found.  (This is not specified by the formula.  Fractint does it
  1090.    automatically when the parser is used.)  Then for each pixel, the
  1091.    initialization section is performed just once; remember that this
  1092.    section extends from the opening brace down to the colon.  While this
  1093.    section of Cardioid is comparatively complicated, the fact that it is
  1094.    performed just once per pixel means it won't have a big impact on the
  1095.    speed of the formula.  Then, the iterated section is repeated over and
  1096.    over until 1) z escapes the bailout circle, 2) maximum number of
  1097.    iterations is reached, or 3) periodicity in the orbit of z is detected.
  1098.    In each iteration, a new value for z is found using the *current* value
  1099.    of z as one of the terms of the calculation, and this new value is then
  1100.    assigned to z.
  1101.  
  1102.    At the beginning of CGNewtonSinExp, Fractint is told to use the "xaxis"
  1103.    symmetry-drawing technique.  After the location of the zoom-box corners
  1104.    has been noted, the parser then reads the initialization section one
  1105.    time per pixel.  For this formula, that section is extremely simple.
  1106.    Now the parser moves to the iterated section.  It performs all of the
  1107.    specified calculations that follow the colon, and then performs the
  1108.    bailout test.  If the test evaluates to TRUE, and the other bailout
  1109.    conditions are not met, the parser loops back to the colon and starts
  1110.    calculating again.
  1111.  
  1112.    Since the bulk of the calculating takes place within the iterated loop,
  1113.    an iteration of CGNewtonSinExp will take longer than an iteration of
  1114.    Cardioid.  I don't see how that could be avoided in this case, but as
  1115.    I'll show you later, you can often speed up a formula by putting as much
  1116.    calculating as possible in the initialization section rather than in the
  1117.    iterated loop.
  1118.  
  1119.  
  1120.    ===================================
  1121.    9.0  APPROACHES TO WRITING FORMULAS
  1122.    ===================================
  1123.  
  1124.    At this point, we've covered the essentials you'll need to begin writing
  1125.    formulas.  You now know the elements most commonly used in formulas, and
  1126.    you know some basic rules that govern how those elements are combined.
  1127.  
  1128.    But even though you have been shown the parts, we haven't really
  1129.    discussed how to go about actually writing a formula.  Just what is the
  1130.    process?
  1131.  
  1132.    As you would probably guess, there are many different approaches
  1133.    available.  The approach you choose will depend on your temperament and
  1134.    your mathematical abilities.  The following list is certainly not
  1135.    exhaustive, but it may give you some ideas on how *you* might get
  1136.    started.
  1137.  
  1138.  
  1139.    9.1  USING MATHEMATICAL INSIGHTS
  1140.    --------------------------------
  1141.    Some people have so deep an understanding of the mathematics of fractals
  1142.    that they can use their insights to discover new fractals.  Benoit
  1143.    Mandelbrot, for instance, understood the mathematics of Julia sets well
  1144.    enough to envision a new fractal that would serve as a "catalog" of all
  1145.    Julias.  This new fractal is, of course, the Mandelbrot set.  Few of us
  1146.    have this sort of deep insight, unfortunately.
  1147.  
  1148.  
  1149.    9.2  ADAPTING AN EXISTING ALGORITHM
  1150.    -----------------------------------
  1151.    Some beautiful fractals were found by investigating mathematical
  1152.    procedures developed for other purposes.  For instance, in Fractint
  1153.    there are several built-in fractals and formulas for "Newton" fractals.
  1154.    These are based on a mathematical algorithm invented by Sir Isaac Newton
  1155.    for finding the roots of numbers. Surely he didn't have fractals in mind
  1156.    when he invented his method, but there they are!  The "Halley" types are
  1157.    based on adaptations of another method for finding roots.
  1158.  
  1159.    If you know of an interesting algorithm, you might want to try adapting
  1160.    it to the formula format to see if there are any fractals lurking
  1161.    within.  Later, in the discussion of "Using Values From Other
  1162.    Iterations", I'll give another example.
  1163.  
  1164.  
  1165.    9.3  MUTATING AN EXISTING FORMULA
  1166.    ---------------------------------
  1167.    This is probably the easiest way to get started and get good results
  1168.    quickly.  Look at the following formula:
  1169.  
  1170.      Mutantbrot { ;A mutation of the classic Mandelbrot set
  1171.        z = 0, c = pixel:      ;standard initialization section
  1172.          z = z*z + c + sin(z) ;mutated iterated section
  1173.          |z| < 4              ;standard bailout test
  1174.      }
  1175.  
  1176.    All I did was to take the classic Mandelbrot formula and add a new term
  1177.    to the iterated section:  "+ sin(z)".  I didn't have any particular
  1178.    insight that led me to do this, I just tried it to see what would
  1179.    happen.  The result is certainly different from the M-set, but
  1180.    interesting.
  1181.  
  1182.    One very good way to mutate a formula is to replace hard-coded functions
  1183.    with user-selectable functions.  This is called "generalizing" the
  1184.    formula. For example, if a formula uses the expression "c = sqr(pixel)",
  1185.    you could change it to read "c = fn1(pixel)", and then experiment with
  1186.    different functions.  Remember that just one generalized function will
  1187.    save you from the chore of typing dozens of hard-coded varients!
  1188.  
  1189.    You can also try enclosing key terms within functions. In a Mandelbrot
  1190.    formula, you could replace "z = z*z + c" with "z = fn1(z*z) + c".  Now
  1191.    you can see the normal Mandelbrot by setting fn1() to IDENT, but you can
  1192.    also get interesting results with other functions.
  1193.  
  1194.    More examples of formulas created with the "mutation" approach can be
  1195.    found in my file FUBAR.FRM.
  1196.  
  1197.  
  1198.    9.4  THE MONKEY-AT-THE-TYPEWRITER APPROACH
  1199.    ------------------------------------------
  1200.    This is a reference to the old claim that if you put an infinite number
  1201.    of monkeys in front of typewriters and let them pound on the keys for an
  1202.    infinite length of time, eventually one would produce one of
  1203.    Shakespeare's sonnets.  In this context, it means "just load your text
  1204.    editor and start typing". You know basically what a formula should look
  1205.    like, and you've seen lots of different "parts" used in other formulas,
  1206.    so play mad scientist.  (Dr. Fractalstein?)  Graft together different
  1207.    parts, add new ones of your own invention, and then see what happens.
  1208.    This approach is suitable for those of us (myself included) who are
  1209.    unencumbered by real math skills or insights but who want to play
  1210.    anyway!  It often takes a lot of patience to find something interesting,
  1211.    but when you do it can be very exciting.
  1212.  
  1213.    It's hard to describe the experience of writing a more-or-less random
  1214.    formula and seeing incredible order and complexity in the emerging
  1215.    image.  I find it both exhilarating and spooky.
  1216.  
  1217.  
  1218.    ===========
  1219.    10.0  STYLE
  1220.    ===========
  1221.  
  1222.    If you have a collection of formula files, look them over with your text
  1223.    editor.  You may notice that different authors can give their formulas
  1224.    very different appearances.  Often, these visual differences are simply
  1225.    differences in "style".  (The formulas in FRACTINT.FRM have been edited
  1226.    to have a consistent style, but other formulas vary.)
  1227.  
  1228.    Some authors like to put as much as possible on a single line, using
  1229.    commas to separate the different expressions, while other authors prefer
  1230.    to use a single expression per line.  Some formulas have explanatory
  1231.    comments, while other formulas have none.  Some authors use spaces
  1232.    between variables and operators, while other authors run them together.
  1233.    And some authors use indentation to make the different sections of their
  1234.    formulas more easily identifiable, while other authors do not.
  1235.  
  1236.    These differences demonstrate the personal preferences of the individual
  1237.    authors; the style that you use is entirely up to you.  However, I have
  1238.    a few biases of my own that I'd like to inflict upon you.
  1239.  
  1240.    First, pick a style that makes sense to you, and then try to be
  1241.    consistent with it.  This makes life easier for someone who is reading
  1242.    your formulas and trying to make sense of them.  If you don't care about
  1243.    the comfort of others, remember that this unfortunate reader may be you,
  1244.    later on!
  1245.  
  1246.    Second, strive for clarity.  This can be achieved in different ways:
  1247.    adding comments, using spaces wisely, indenting, choosing informative
  1248.    variable names, etc.  Often the addition of parentheses can help make
  1249.    the logical grouping of formula elements more visible, even when the
  1250.    parentheses are not strictly necessary.
  1251.  
  1252.  
  1253.    ================
  1254.    11.0  TECHNIQUES
  1255.    ================
  1256.  
  1257.    Okay, you know the basics.  You've written some formulas of your own,
  1258.    and the rules about formula structure are becoming second nature.  Now
  1259.    let's talk about techniques you can use to improve the performance of
  1260.    your formulas, or to make them do fancy new tricks.
  1261.  
  1262.    Warning: If you haven't already written several working formulas of your
  1263.    own, and aren't comfortable with the preceding information, you might
  1264.    want to come back to the rest of this document later.  From this point
  1265.    on, we are venturing into material that is more complicated and subtle.
  1266.  
  1267.  
  1268.    11.1  SPEED-UPS
  1269.    ---------------
  1270.    Here are some ways to make your formulas run a little faster.
  1271.  
  1272.    [11.1.1  AVOID EXPONENTIATION AND FUNCTION CALLS]  There is often more
  1273.    than one way to accomplish a goal.  If you'll compare the Mandelbrot,
  1274.    frm-A and frm-C1 formulas, you'll see that I used three different
  1275.    techniques to find the square of z:  z*z, z^2, and sqr(z). All give the
  1276.    same answer but the first method, multiplication, is the fastest.  As a
  1277.    rule, functions are slower than arithmetic operators, and exponents are
  1278.    typically slower than functions.  If you need a function *other* than
  1279.    sqr(), though, you usually won't have a simple alternative. And
  1280.    sometimes you simply can't avoid using an exponent, but you are smart to
  1281.    look for situations where you can.
  1282.  
  1283.    [11.1.2  AVOID UNNECESSARY CALCULATIONS]  Consider the following:
  1284.    
  1285.      speed-A { ;Demonstrates potential for speed-up
  1286.        z = 0:
  1287.          z = z*z + sin(pixel)
  1288.          |z| < 4
  1289.      }
  1290.  
  1291.  
  1292.      speed-B { ;variation of speed-A showing one speed-up technique
  1293.        z = 0, sinp = sin(pixel):
  1294.          z = z*z + sinp
  1295.          |z| < 4
  1296.      }
  1297.  
  1298.    Both formulas will result in exactly the same image being drawn, but
  1299.    speed-B is much faster.  Why?  In speed-A, the value of sin(pixel) must
  1300.    be calculated *once per iteration* while in speed-B it is only
  1301.    calculated *once per pixel*.  We can do this because the value of pixel
  1302.    doesn't change during the iterated section.  The value of z keeps
  1303.    changing from one iteration to the next, however, so we can't use the
  1304.    same trick with that variable.  On my home computer (and at my preferred
  1305.    resolution) I can generate the speed-A fractal in about 82 seconds,
  1306.    while speed-B takes only 38 seconds.  Speed-A may seem a little more
  1307.    straightforward, but your speed-hungry users will usually prefer using
  1308.    speed-B!
  1309.  
  1310.    [11.1.3  AVOID UNNECESSARY ITERATIONS]  Compare the initialization
  1311.    section of frm-A to those in Mandelbrot and frm-C1.  In the latter two,
  1312.    z is initialized with the value 0 (the traditional approach), while in
  1313.    frm-A it gets the value of pixel.  Why the difference?  Bert Tyler, the
  1314.    original Fractint programmer, recognized that the first iteration of the
  1315.    traditional Mandelbrot formula accomplishes nothing more than giving z
  1316.    the value of pixel -- step through the logic to see for yourself.  So
  1317.    when he wrote the code for type "Mandel", he decided to "save" that
  1318.    iteration by initializing z to pixel.  I have used the same trick in
  1319.    frm-A.  It is a small speed-up, to be sure, but you may find it
  1320.    irresistible!  If you carefully think your formulas through, you may
  1321.    find other speed-ups are possible.
  1322.  
  1323.  
  1324.    11.2  SIMULATING THE IF..THEN CONSTRUCT
  1325.    ---------------------------------------
  1326.    Here's an summary of what I've learned about including conditional logic
  1327.    in a formula, and some warnings about possible pitfalls.
  1328.  
  1329.    [11.2.1  HOW IT WORKS]  As I have mentioned, a formula is a program; the
  1330.    Fractint formula parser actually interprets a little programming
  1331.    language.  Users who are familiar with programming languages like BASIC,
  1332.    C, or Pascal may find themselves wishing for some of the features of
  1333.    those languages.  One of the most useful of those features is
  1334.    conditional logic, as used in the IF..THEN construct.  Luckily for us,
  1335.    it is possible to simulate this construct with the parser language, even
  1336.    though it isn't explicitly included.
  1337.  
  1338.    Let's look at an example.  Suppose you want to include the following
  1339.    logic in your formula:  if A is negative then it gets the value of X,
  1340.    otherwise it gets the value of Y.  In the C language, you could write
  1341.    this as:
  1342.  
  1343.      if (a < 0)
  1344.        a = x;
  1345.      else
  1346.        a = y;
  1347.  
  1348.    You could simulate this in a Fractint formula like this:
  1349.  
  1350.      neg = x * (a < 0)
  1351.      pos = y * (a >= 0)
  1352.      a = neg + pos
  1353.  
  1354.  
  1355.    or:
  1356.  
  1357.      a = (x * (a < 0)) + (y * (a >= 0))
  1358.  
  1359.    Now both of those parser versions are quite a bit more obscure than
  1360.    the C version, and C has a reputation as an obscure language!  But let's
  1361.    examine the first parser version and see how it works.
  1362.  
  1363.    It's time to return to the observation that a comparison will always
  1364.    evaluate to either TRUE or FALSE.  That seems glaringly obvious on one
  1365.    level, but it's the details under the surface that make this technique
  1366.    work.  The key detail is that Fractint appears to represent TRUE with a
  1367.    one, and FALSE with a zero.
  1368.  
  1369.    So suppose that a = (1.5,2) and let's see what happens with an
  1370.    expression like "neg = x * (a < 0)".  Since this is an assignment
  1371.    statement, the parser will first have to evaluate what is on the right
  1372.    side of the '=', so it will know what to put into neg.  When the parser
  1373.    comes to the comparison expression, it will give the answer FALSE,
  1374.    because the real part of a is 1.5.  Since the parser represents FALSE
  1375.    with a zero, the expression simplifies to "x * 0", therefore neg = 0.
  1376.  
  1377.    Using similar logic, you should be able to prove that pos will end up
  1378.    equalling y.
  1379.  
  1380.    Since any single comparison is either TRUE or FALSE but not both, and
  1381.    because of the way I set up those comparisons, you should see that when
  1382.    a is negative, a = x + 0, and that when it is zero or positive,
  1383.    a = 0 + y.
  1384.  
  1385.    The second parser version is simply a condensation of the above, without
  1386.    the intermediate variables neg and pos.
  1387.  
  1388.    Which parser version do you prefer?
  1389.    
  1390.    [11.2.2  PITFALLS]  For this technique to work properly there are some
  1391.    pitfalls to avoid, so I'll describe a few that can cause problems.  As
  1392.    you read this section, you'll learn how *not* to set up conditional
  1393.    logic, and you'll also get good practice in analyzing formulas to see
  1394.    how they work.
  1395.  
  1396.    PITFALL 1: The order of the expressions can make a difference.
  1397.    
  1398.    The order in which expressions are evaluated can be important in *any*
  1399.    part of a formula.  See section 7.2.10, for instance, for a discussion
  1400.    of how the rules of precedence affect the results of computations.  But
  1401.    in the context of conditional logic, this principle can take on extra
  1402.    subtlety.
  1403.  
  1404.    Chuck Ebbert is the fellow who wrote the fast new version of the parser
  1405.    that was introduced with version 18, so we may regard him as a real
  1406.    authority.  In his formula file BUILTN.FRM, Chuck suggested putting the
  1407.    comparison *after* the multiply when using the IF..THEN trick.  He
  1408.    advised doing it for speed gains, but it can also affect the images that
  1409.    some formulas produce.
  1410.  
  1411.    Here's one such situation.  Suppose you want to use the following
  1412.    algorithm in your iterated section:  If 'z' (or more precisely, the
  1413.    *real* part of 'z') is negative, then z = fn1(z) + c ; otherwise,
  1414.    z = fn2(z) + c.
  1415.  
  1416.    Don't be tempted to set things up like this:
  1417.  
  1418.      IfThen-A1 { ;Demonstrates that the order of expressions can make a
  1419.                  ;difference.  In this example, the assignment is performed
  1420.                  ;BEFORE the comparison.
  1421.        z = c = pixel:
  1422.          (z < 0) * (z = fn1(z) + c)
  1423.          (0 <= z) * (z = fn2(z) + c)
  1424.          |z| < 4 }
  1425.  
  1426.    The comparison expressions precede the assignment expressions as you
  1427.    read from left to right, but it appears that the parser actually
  1428.    evaluates the right-hand expression (the assignment) first.  You can
  1429.    confirm this by looking at the images produced by this formula:
  1430.  
  1431.      IfThen-A2 { ;Functional equivalent of IfThen-A1
  1432.        z = c = pixel:
  1433.          z = fn1(z) + c
  1434.          z = fn2(z) + c
  1435.          |z| < 4
  1436.      }
  1437.  
  1438.    Since both formulas produce the same images, I conclude that the
  1439.    comparisons are, in effect, being ignored.
  1440.  
  1441.    If you wish, you can further simplify the formula:
  1442.  
  1443.      IfThen-A3 { ;Another equivalent of IfThen-A1
  1444.        z = c = pixel:
  1445.          z = fn2(fn1(z) + c) + c
  1446.          |z| < 4
  1447.      }
  1448.  
  1449.    While the preceding three formulas were instructive, they didn't do what
  1450.    we set out to do.  Let's try again:
  1451.  
  1452.      IfThen-B1 { ;In this formula, the comparison is performed BEFORE the
  1453.                  ;assignment, but there's still a subtle flaw.
  1454.        z = c = pixel:
  1455.          (z = fn1(z) + c) * (z < 0)
  1456.          (z = fn2(z) + c) * (0 <= z)
  1457.          |z| < 4
  1458.      }
  1459.  
  1460.    This formula reverses the order of the comparison and assignment
  1461.    expressions.  If you'll compare its images to those of IfThen-A1, you'll
  1462.    see that rearranging the expressions also changes the images.
  1463.  
  1464.  
  1465.    PITFALL 2: Don't try to embed an assignment statement within a larger
  1466.    expression.
  1467.  
  1468.    Okay, we've reordered the expressions in IfThen-B1 so the comparison is
  1469.    evaluated first.  Because the assignment statements are within
  1470.    parentheses, it might seem reasonable to assume that an assignment will
  1471.    only occur if the comparison is TRUE.  Certainly, that is our intent.
  1472.    Unfortunately, it isn't so.  Look:
  1473.  
  1474.      IfThen-B2 { ;Functional equivalent of IfThen-B1
  1475.        z = c = pixel:
  1476.          z = (fn1(z) + c) * (z < 0)  ;line A
  1477.          z = (fn2(z) + c) * (0 <= z) ;line B
  1478.          |z| < 4
  1479.      }
  1480.  
  1481.    Since IfThen-B2 produces the same images as IfThen-B1, we may assume
  1482.    that they are functionally equivalent.  But in IfThen-B2 it is clear
  1483.    that *some* assignment always takes place, whether the comparison is
  1484.    TRUE or FALSE. This may well produce interesting results, but it isn't
  1485.    what we wanted. Remember that we wanted 'z' to get 'c' plus EITHER
  1486.    fn1(z) OR fn2(z). Putting the assignment within the parentheses didn't
  1487.    help us achieve conditional execution.
  1488.  
  1489.    In the Fractint parser language (as I understand it) there's no good
  1490.    reason to put an assignment statement *within* a larger expression, as
  1491.    we did in IfThen-A1 and IfThen-B1.  That sort of thing may be useful in
  1492.    C and other languages, but in a Fractint formula it is likely to mislead
  1493.    you and your readers as to what is really happening.
  1494.  
  1495.  
  1496.    PITFALL 3: If you are trying to create an EITHER/OR choice, construct
  1497.    your formula carefully to ensure that the choices are mutually
  1498.    exclusive.
  1499.  
  1500.    Let's walk through an example for IfThen-B2.  Suppose z < 0; then when
  1501.    line A is performed 'z' will get fn1(z) + c.  Depending on the function
  1502.    selected for fn1() and the value of 'c', this *new* value of 'z' could
  1503.    be either negative, positive or zero, and it will determine whether the
  1504.    comparison in line B is TRUE or FALSE.  In fact, for any particular
  1505.    iteration, the comparisons in lines A and B could be TRUE and TRUE,
  1506.    TRUE and FALSE, or FALSE and TRUE.  This is getting very complicated!
  1507.  
  1508.      Comparisons
  1509.      line A  line B     Equivalent Expression
  1510.      ---------------------------------------
  1511.      TRUE  / TRUE       z = fn2(fn1(z) + c) + c
  1512.      TRUE  / FALSE      z = 0
  1513.      FALSE / TRUE       z = fn2(0) + c
  1514.  
  1515.    (Why no "FALSE / FALSE"?  If line A is FALSE, then 'z' gets zero.
  1516.    Because of the way we wrote the comparison in line B, this would make
  1517.    line B necessarily TRUE...)
  1518.  
  1519.    Let's recap: In IfThen-A1 each comparison was ignored because the
  1520.    assignment had already been made before the comparison occurred.  In
  1521.    IfThen-B1 the comparisons are not ignored, but our flawed logic causes
  1522.    the value of 'z' to change between the first comparison and the second.
  1523.  
  1524.    Got a headache yet?  Try these on for size:
  1525.  
  1526.      IfThen-C1 { ;What we REALLY had in mind.
  1527.        z = c = pixel:
  1528.          neg = fn1(z) * (z < 0)
  1529.          pos = fn2(z) * (0 <= z)
  1530.          z = neg + pos + c
  1531.          |z| < 4
  1532.      }
  1533.  
  1534.  
  1535.      IfThen-C2 { ;An alternate version of IfThen-C1
  1536.        z = c = pixel:
  1537.          z = (fn1(z) * (z < 0)) + (fn2(z) * (0 <= z)) + c
  1538.          |z| < 4
  1539.      }
  1540.  
  1541.    Here we finally have the algorithm we intended to implement.  We made
  1542.    sure that the comparisons are evaluated before the assignments.  We also
  1543.    took care to make the comparisons independent of each other.
  1544.  
  1545.    The point of the whole ugly exercise is this: unless you are careful, you
  1546.    can write a formula that operates in ways that you didn't intend.
  1547.  
  1548.    Before I leave this subject, let me address a possible objection. It
  1549.    may appear that if you successfully avoid pitfall #2 (embedding an
  1550.    assignment within a larger expression) then pitfall #1 (order of
  1551.    expressions) is a non-issue.  I agree that in *most* cases it will not
  1552.    make a visible difference.  IfThen-C1 appears to give the same images
  1553.    whether we write "neg = fn1(z) * (z < 0)" or "neg = (z < 0) * fn1(z)",
  1554.    for example.  But putting the comparison after the multiply does seem to
  1555.    speed up many formulas, and as you'll see when you read section 12.4,
  1556.    "A Ghost Story", there *are* rare occasions when the order of the
  1557.    sub-expressions appears to affect the image, even though this may seem
  1558.    illogical.  You are free to do as you like, of course, but I plan to
  1559.    follow Chuck's advice until I see a good reason to ignore it.
  1560.  
  1561.  
  1562.    11.3  SETTING DEFAULTS
  1563.    ----------------------
  1564.    Suppose that you have written a formula, and now you need to provide a
  1565.    bailout test.  Even if you are just creating a normal escape-time
  1566.    formula, there are at least three different approaches to choose from.
  1567.    These different approaches are illustrated by the following three
  1568.    formulas.  Each of these techniques has advantages, and I have used them
  1569.    all at various times.
  1570.  
  1571.      bailout-A { ;Hard coded bailout value
  1572.        ;p1 = parameter (default 0,0)
  1573.        z = pixel, c = fn1(pixel):
  1574.          z = fn2(z*z) + c + p1
  1575.          |z| < 4
  1576.      }
  1577.  
  1578.      bailout-B { ;Variable default -- additive
  1579.        ;p1 = parameter (default 0,0)
  1580.        ;p2 = bailout adjustment value (default 0,0)
  1581.        test = (4 + p2)
  1582.        z = pixel, c = fn1(pixel):
  1583.          z = fn2(z*z) + c + p1
  1584.          |z| < test
  1585.      }
  1586.  
  1587.      bailout-C { ;Variable default -- conditional logic
  1588.        ;This formula requires floating-point
  1589.        ;p1 = parameter (default 0,0)
  1590.        ;p2 = bailout   (default 4,0)
  1591.        ;The following line sets test = 4 if real(p2) = 0, else test = p2
  1592.        test = (4 * (p2 <= 0)) + (p2 * (0 < p2))
  1593.        z = pixel, c = fn1(pixel):
  1594.          z = fn2(z*z) + c + p1
  1595.          |z| < test
  1596.      }
  1597.  
  1598.    Before we discuss the different approaches, examine the formula for a
  1599.    moment.  It is a hybrid of a Mandelbrot and a Julia formula, with a
  1600.    couple of user-selectable functions thrown in for fun.  P1 is used as a
  1601.    constant to be added with each iteration, and in the second and third
  1602.    formulas P2 is used to determine the bailout value.
  1603.  
  1604.    Now let's look at the bailout test in "bailout-A".  Hard coding a value,
  1605.    as in "|z| < 4", is easiest to code and easiest to understand.  It also
  1606.    will run the fastest.  But it doesn't allow the user to change the value
  1607.    without editing the formula.  Since I have added variable functions and
  1608.    a user parameter (p1), this value might not be the best choice for all
  1609.    situations.  (If the user wants to use the "biomorph" option, a variable
  1610.    bailout test will also be desirable because this option generally works
  1611.    best with a high bailout value.)
  1612.  
  1613.    In "bailout-B", I have addressed this potential problem.  Here, the
  1614.    value the user gives to P2 is added to 4 and stored in a variable called
  1615.    test. This variable is then referred to in the bailout test.  If you
  1616.    decide that 3 would be a better bailout value than 4, you can give the
  1617.    real part of P2 the value -1, for example.  As I noted in the section on
  1618.    speed-up techniques, putting the calculation of "4 + p2" in the
  1619.    initialization section will make the formula go faster than if the
  1620.    bailout test was written as "|z| < (4 + p2)".
  1621.  
  1622.    I didn't just set the bailout equal to p2, however, because then if the
  1623.    user left p2 at (0,0) the resulting image would be a blank screen.  It
  1624.    is likely that a beginner or casual user of your formula would do just
  1625.    that, and would probably decide that your formula is defective!  If you
  1626.    need to allow the user to vary some value, it is best (in my opinion) to
  1627.    be sure that the default values produce *some* image.
  1628.  
  1629.    This technique is still quite easy to implement.  It has the drawback of
  1630.    being more obscure than hard coding, however.  If you want the bailout
  1631.    value to be 16, for instance, you must understand the formula well
  1632.    enough to know that p2 must equal 12.
  1633.  
  1634.    The third technique is illustrated by "bailout-C".  I first saw this
  1635.    trick used in Chuck Ebbert's formula file that I referred to earlier. In
  1636.    this approach, conditional logic is used.  If the real part of p2 is
  1637.    left at zero (or is negative) then "test" is given the value 4.
  1638.    Otherwise, "test" gets the value of p2.
  1639.  
  1640.    In practice, this approach works more intuitively.  If you want the
  1641.    bailout test to be 16, you set p2 to 16.  There is a price to be paid
  1642.    for this intuitive operation, however: it's a little harder to write,
  1643.    and since it makes the formula more complicated, the formula will be a
  1644.    tiny bit slower.
  1645.  
  1646.  
  1647.    11.4  USING VALUES FROM PREVIOUS ITERATIONS
  1648.    -------------------------------------------
  1649.    In section 9.2 I talked about adapting an existing algorithm to the
  1650.    formula format.  Here's an example of what I meant.
  1651.  
  1652.    Do you recognize the following series of numbers?  What should the
  1653.    next number be?
  1654.  
  1655.       1, 1, 2, 3, 5, 8, 13, 21 ...
  1656.  
  1657.    This is called the Fibonacci series.  Each new number in the series is
  1658.    the sum of the previous two, so the next number should be 13 + 21, or
  1659.    34.  Let's see if we can make a formula out of this series.
  1660.  
  1661.    We might begin with the observation that in the Mandelbrot formula each
  1662.    new generation of 'z' is based on the previous generation.  Maybe we can
  1663.    adapt the Mandelbrot formula for our purpose, but we want to involve the
  1664.    previous *two* generations.  To do this, we'll need to be able to store
  1665.    old values for 'z'.
  1666.  
  1667.    Here's one way to do it:
  1668.  
  1669.      fibo-A { ;Derived from the Fibonacci series
  1670.        z = oldz = c = pixel:
  1671.        temp = z
  1672.        z = z * oldz + c
  1673.        oldz = temp
  1674.        |z| < 4
  1675.      }
  1676.  
  1677.    Let's step through it.  In the following discussion, I'm going to use
  1678.    the notation z(n) to refer to the value of z at the *end* of iteration
  1679.    number n, so z(3) would be the value of z at the end of the third
  1680.    iteration.
  1681.  
  1682.    First we initialize our variables including a new one, 'oldz', to the
  1683.    value of 'pixel'.  Since we haven't completed an iteration yet, let's
  1684.    say z is at generation zero.
  1685.  
  1686.    Then the first line of our iterated section introduces another new
  1687.    variable, 'temp', which gets the value of z(0).  Next we calculate a
  1688.    value for z(1): z(0) * oldz + c.  Then oldz gets the value of temp,
  1689.    which is z(0).
  1690.  
  1691.    When we started into the iterated section, z, oldz and c all had the
  1692.    same value. Now z almost certainly has a different value, while oldz and
  1693.    c still have the value 'pixel'.
  1694.  
  1695.    Let's assume that the bailout conditions have not been met, and loop
  1696.    back for another iteration.  Temp gets the value of z(1).  Then we
  1697.    calculate z(2), and oldz gets the value of z(1) from temp.
  1698.  
  1699.    Now until we stop iterating:
  1700.  
  1701.      z(n) = z(n-1) * z(n-2) + c
  1702.  
  1703.    What have we got here?  It's not quite the same as the Mandelbrot
  1704.    algorithm, and it's not quite the same as the Fibonacci algorithm
  1705.    either.  Instead, we have a hybrid of the two.
  1706.  
  1707.    The formula makes an interesting image, but doesn't allow the user any
  1708.    room to play, so let's add a variable function:
  1709.  
  1710.      fibo-B {
  1711.        z = oldz = c = pixel:
  1712.          temp = z
  1713.          z = fn1(z * oldz) + c
  1714.          oldz = temp
  1715.          |z| < 4
  1716.      }
  1717.  
  1718.    Now you can reproduce the fractal created by fibo-A by setting FN1 to
  1719.    IDENT, but you can also play with other functions.
  1720.  
  1721.    Keeping track of old values can be useful in other ways too.  Look at
  1722.    the following formula, an example of the "in-and-out" formulas found in
  1723.    my file INANDOUT.FRM:
  1724.  
  1725.      inandout01 { ;Bradley Beacham  [74223,2745]
  1726.        ;p1 = Parameter (default 0), real(p2) = Bailout (default 4)
  1727.        ;The next line sets test=4 if real(p2)<=0, else test=real(p2)
  1728.        test = (4 * (real(p2)<=0) + real(p2) * (0<p2))
  1729.        z = oldz = pixel, c1 = fn1(pixel), c2 = fn2(pixel):
  1730.          a = (|z| <= |oldz|) * (c1) ;IN
  1731.          b = (|oldz| < |z|)  * (c2) ;OUT
  1732.          oldz = z
  1733.          z = fn3(z*z) + a + b + p1
  1734.          |z| <= test
  1735.      }
  1736.  
  1737.    Here's the basic idea behind the "in-and-out" algorithm: Did the last
  1738.    iteration move z closer to the origin (0,0) or farther away from it?  If
  1739.    closer, use one value.  If farther away, use a different value.  Picture
  1740.    the complex plane with the bailout circle centered on the origin.  In my
  1741.    imagination this resembled a radar screen, with z moving about within
  1742.    the circle.  Is z getting closer to the center, or farther away?
  1743.  
  1744.    To answer that question, I kept track of the value of z from the
  1745.    previous iteration by storing it in a variable called oldz, and then
  1746.    compared the values of |z| and |oldz|.
  1747.  
  1748.    If you feel bewildered, hold on.  Let's look at the formula in detail,
  1749.    step by step, to illustrate how it works.  To make it a little easier, I
  1750.    annotated the formula with additional comments, and put spaces between
  1751.    different functional parts to make them easier to see.
  1752.  
  1753.      inandout01 { ;Bradley Beacham  [74223,2745]
  1754.        ;p1 = Parameter (default 0), real(p2) = Bailout (default 4)
  1755.  
  1756.        ;The next line sets test=4 if real(p2)<=0, else test=real(p2)
  1757.        test = (4 * (real(p2)<=0) + real(p2) * (0<p2))
  1758.  
  1759.        ;initialize other variables
  1760.        z = oldz = pixel, c1 = fn1(pixel), c2 = fn2(pixel):
  1761.  
  1762.          ;did previous iteration move z in or out?
  1763.          a = (|z| <= |oldz|) * (c1) ;IN
  1764.          b = (|oldz| < |z|)  * (c2) ;OUT
  1765.  
  1766.          ;save value of z before changing it
  1767.          oldz = z
  1768.  
  1769.          ;calculate new z
  1770.          z = fn3(z*z) + a + b + p1
  1771.  
  1772.          ;bailout test
  1773.          |z| <= test
  1774.      }
  1775.  
  1776.    First comes the formula name. Next is a comment that tells you how the
  1777.    user variables P1 and P2 are used.  Then we give the variable 'test' a
  1778.    value -- this will be used in the bailout test -- and we set up some
  1779.    other variables.  I call my main variable 'z', and set it equal to
  1780.    pixel. I also create a variable called 'oldz' and set it to the value of
  1781.    pixel.  Then I create two other variables called 'c1' and 'c2'.  Recall
  1782.    that the general algorithm is to use one value if z moves closer to the
  1783.    origin, and another value if z moves away.  To accomplish this, I opted
  1784.    to use two different versions of c: c1 gets fn1(pixel) and c2 gets
  1785.    fn2(pixel).
  1786.  
  1787.    Since we just found the colon, that's the end of the initialization
  1788.    section.  Let's proceed to the iterated section.  Remember that the main
  1789.    question is "did z move closer to the origin, or farther away?"  To
  1790.    answer this question, we compare |z| to |oldz|.  We have to account for
  1791.    the possibility that they are the same, so the first comparison is
  1792.    stated as "|z| <= |oldz|".  On the first iteration 'oldz' was
  1793.    initialized to equal 'z' so this will be the case, but on subsequent
  1794.    iterations, who knows?  At any rate, if this comparison is TRUE, the
  1795.    statement has the value of 1, so 'a' gets the value of 'c1'; if it is
  1796.    FALSE, 'a' gets the value 0.
  1797.  
  1798.    A similar comparison covers the opposite possibility.  If |oldz| is
  1799.    less than |z|, then 'b' gets the value 'c2'; otherwise it gets 0.
  1800.  
  1801.    Note that we made sure the possibilities are mutually exclusive.  In
  1802.    every case, if one comparison is TRUE then the other is FALSE, but the
  1803.    TRUE comparison may change from iteration to iteration.
  1804.  
  1805.    Then, we save the value of 'z' into 'oldz', just before we calculate a
  1806.    new value for 'z'.  After the first iteration it is likely that 'oldz'
  1807.    and 'z' will have different values, but 'oldz' will always have the
  1808.    value of 'z' from the previous iteration, as in the "fibo" formulas.
  1809.  
  1810.    To calculate the new 'z', we use "z = fn3(z*z) + a + b + p1".
  1811.    Because of the way we set up the comparisons, this will work out to mean
  1812.    either "z = fn3(z*z) + c1 + 0 + p1" or "z = fn3(z*z) + 0 + c2 + p1".
  1813.  
  1814.    (Speaking of the comparisons, you have probably noticed that I didn't
  1815.    follow my own advice about writing the comparison after the multiply.
  1816.    When I wrote that formula, I was unaware of the possible complications
  1817.    involved.  I'm still learning...)
  1818.  
  1819.    Finally, we come to the relatively simple bailout test.
  1820.  
  1821.    Whew, that was a bit of a workout!  So what's the cosmic significance of
  1822.    it all?  Beats me!  If it does nothing else, though, it should show you
  1823.    that it is possible to invent fairly elaborate algorithms for your
  1824.    formulas without any notions about their ultimate mathematical
  1825.    significance.  And if you're smart enough to see the significance of
  1826.    things like this, then you're in a great position to exploit that
  1827.    knowledge.
  1828.  
  1829.    It should also demonstrate that saving values from past iterations can
  1830.    be a useful technique!
  1831.  
  1832.  
  1833.    11.5  DISSECTING A FORMULA WITH ALGEBRA
  1834.    ---------------------------------------
  1835.    Fractint was designed to work with complex numbers.  It has all kinds of
  1836.    mathematical operators and functions available that were written with
  1837.    complex math in mind.
  1838.  
  1839.    But the fact that complex arithmetic works like algebra can be exploited
  1840.    for insight and for interesting results.  Let's take a closer look at
  1841.    how complex multiplication is performed.
  1842.  
  1843.    Remember that a complex number can be expressed as the combination of a
  1844.    real and an imaginary part.  The complex number x + yi, for example,
  1845.    has a real part of x and an imaginary part of y, while 'i' represents
  1846.    the square root of -1.
  1847.  
  1848.    To find the square of the number, we can treat the complex number as an
  1849.    ordinary algebra expression, with 'i' being a variable.  This means that
  1850.    (x + yi) * (x + yi) == (x^2 + 2xyi + yi^2).  Now if you remember that
  1851.    i^2 == -1, this can be simplified to ((x^2 - y^2) + 2xyi).
  1852.  
  1853.    We can write a formula that recreates this process, doing complex
  1854.    arithmetic the hard way.  For want of a better term, I call this
  1855.    "dissecting" the formula.
  1856.  
  1857.      dissected-A { ;A dissected Mandelbrot
  1858.        z = 0, c = pixel:
  1859.          x = real(z), y = imag(z)   ;isolate real and imaginary parts
  1860.          newx = x*x - y*y           ;calculate real part of z*z
  1861.          newy = 2*x*y               ;calculate imag part of z*z
  1862.          z =  newx + flip(newy) + c ;reassemble z
  1863.          |z| < 4
  1864.      }
  1865.  
  1866.    In this formula, I isolate the real and imaginary parts of z, and then
  1867.    perform the math described above.  Let's suppose for a moment that
  1868.    z = 2 + 3i, and step through the iterated section of the formula.
  1869.  
  1870.    First, the real part of z is extracted by using the "real" function.
  1871.    This result is put in a complex variable called 'x'.  Then the imaginary
  1872.    part of z is extracted using the "imag" function, and this is put into
  1873.    'y'.  Thus, x = (2,0) and y = (3,0).
  1874.  
  1875.    Now, values for the real and imaginary parts of z*z are calculated by
  1876.    emulating the algebraic analysis above.  That is, we find the value of
  1877.    x*x - y*y; that's the real part of z*z.  Then we find the value of
  1878.    2*x*y, which is the imaginary part of z*z.
  1879.  
  1880.    Now we "reassemble" z using these values.  Remember that when we used
  1881.    the "imag" function and put the result in 'y', it went into the *real*
  1882.    part of 'y'.  This means that we have to convert the value in 'newy'
  1883.    into an imaginary number.  We do this with the "flip" function.  The
  1884.    "flip" function, in effect, turns a complex number upside down by
  1885.    swapping the real and the imaginary values.  Thus, flip(x + yi) returns
  1886.    y + xi.  If x = (2,0) and y = (3,0), then newy = (12,0).  Therefore,
  1887.    flip(newy) = (0,12).  Finally we add c and perform the bailout test.
  1888.  
  1889.    If you'll run this formula, you'll see that it does indeed produce the
  1890.    Mandelbrot set.  But that's a lot more work than the standard Mandelbrot
  1891.    formula.  Why bother?
  1892.  
  1893.    The answer is that by "laying the parts out", so to speak, you can
  1894.    perform operations on them that would be difficult to do with a formula
  1895.    written in the normal way.  Consider the next formula:
  1896.  
  1897.      dissected-B { ;A mutation of "dissected-A"
  1898.        z = 0, c = pixel, k = 2 + p1:
  1899.          x = real(z), y = imag(z)
  1900.          newx = fn1(x*x) - fn2(y*y)
  1901.          newy = k*fn3(x*y)
  1902.          z =  newx + flip(newy) + c
  1903.          |z| < 4
  1904.      }
  1905.  
  1906.    By experimenting with various values for fn1(), fn2(), fn3() and p1, you
  1907.    can produce all sorts of interesting variants on the Mandelbrot set.  I
  1908.    suggest starting with all of the functions set at "ident" and p1 at 0,
  1909.    and then changing one of them at a time. 
  1910.  
  1911.    Practice your complex arithmetic so it becomes easier to do, and you'll
  1912.    find that it is possible to dissect many different formulas.  See my
  1913.    OVERKILL.FRM for some other examples.
  1914.  
  1915.  
  1916.    11.6  USING A COUNTER
  1917.    ---------------------
  1918.    Fractint has built-in mechanisms to count the iterations of our
  1919.    formulas.  Normally we just rely on the automatic counter, but sometimes
  1920.    it's more fun to be abnormal.  Here's a simple example of how you can
  1921.    manually track the iteration count, to produce fractals that are
  1922.    definitely out of the ordinary.
  1923.  
  1924.      shifter { ;Use a counter to shift algorithms
  1925.        z = c = pixel, iter = 1, shift = p1, test = 4 + p2:
  1926.          lo = (z*z) * (iter <= shift)
  1927.          hi = (z*z*z) * (shift < iter)
  1928.          iter = iter + 1
  1929.          z = lo + hi + c
  1930.          |z| < test
  1931.      }
  1932.  
  1933.    Let's first look at the mechanics of the formula.  Note that there is a
  1934.    variable called 'iter', which is used to keep a running count of the
  1935.    iterations.  For each pixel it is initialized with 1, and in each pass
  1936.    through the loop the value is incremented; so at the beginning of the
  1937.    first iteration 'iter' will equal 1, on the second iteration it will
  1938.    equal 2, etc.
  1939.  
  1940.    Also note that the formula uses conditional logic to select between two
  1941.    algorithms: do we calculate z*z or z*z*z?  The question is settled by
  1942.    comparing the iteration number to a variable called 'shift', which
  1943.    equals p1.  (I could have just used p1 in the formula, but I think using
  1944.    a variable called 'shift' makes the meaning a little clearer.)
  1945.  
  1946.    Suppose you set p1 to 75, and left the value for maximum iterations at
  1947.    150.  This means that for the first 75 iterations, the formula would
  1948.    calculate z = z*z + c, but from iteration 76 to 150, it would calculate
  1949.    z = z*z*z + c.  In other words, it is shifting mid-stream from the
  1950.    normal Mandelbrot algorithm to the "Cubic Mandelbrot" algorithm.
  1951.  
  1952.    Set p1 to equal 0, and you'll see a Cubic Mandelbrot.  Set it at 150 and
  1953.    you'll see the normal Mandelbrot.  But when you use a value in-between,
  1954.    you'll get something much stranger.  Usually it looks like a normal
  1955.    Mandelbrot with strange growths inside its lake area.  Weird!  (Note:
  1956.    this formula seems to work best with Fractint's periodicity logic turned
  1957.    off.  To do this, just hit the <G> key, and then enter "periodicity=0".)
  1958.  
  1959.    Now reflect that this is a very simple example.  Can you invent more
  1960.    elaborate and interesting formulas that use the iteration counter idea?
  1961.  
  1962.  
  1963.    ==============
  1964.    12.0  PROBLEMS
  1965.    ==============
  1966.  
  1967.    We've already looked at some of the possible pitfalls when you use the
  1968.    conditional logic (if..then) technique.  Now let's look at a few other
  1969.    tricky areas.
  1970.  
  1971.  
  1972.    12.1  POTENTIAL PROBLEMS WITH SYMMETRY
  1973.    --------------------------------------
  1974.    Fractint's symmetry-drawing techniques can be a big time saver if used
  1975.    correctly.  If you *know* that the fractals produced by a formula will
  1976.    always be symmetrical, then it is smart to declare the symmetry.  But
  1977.    what if you are wrong?  For better or worse, Fractint will attempt to
  1978.    follow your instructions anyway.  Let's look at an example.
  1979.  
  1980.      sym-A { ;Non-symmetrical fractal
  1981.        z = c = pixel, k = (2.5,0.5):
  1982.          z = z^k + c
  1983.          |z| < 4
  1984.      }
  1985.  
  1986.  
  1987.      sym-B (xaxis) { ;Sym-A with symmetry declared in error
  1988.        z = c = pixel, k = (2.5,0.5):
  1989.          z = z^k + c
  1990.          |z| < 4
  1991.      }
  1992.  
  1993.  
  1994.    To see what I'm talking about, first load the sym-A formula and look at
  1995.    the image it makes.  Clearly, the fractal is asymmetrical.  Now look at
  1996.    the image produced by sym-B.
  1997.  
  1998.    The only difference between the formulas is the symmetry declaration,
  1999.    which doesn't really change the nature of the mathematical object
  2000.    described by the formula.  We told Fractint to take a shortcut when
  2001.    drawing the image, so it did.  You may even prefer the symmetrical
  2002.    image, but the truth remains that it is just an illusion.  If you will
  2003.    rotate the zoom box slightly on sym-B, Fractint will stop trying to use
  2004.    the symmetry-drawing techniques, and the real fractal will come out.
  2005.  
  2006.    I pointed out earlier that the formula CGNewtonSinExp specifies xaxis
  2007.    symmetry.  This is unfortunate, in my opinion, because if the imaginary
  2008.    part of p1 is anything other than zero, that fractal appears to lose its
  2009.    symmetry.  Again, this can be demonstrated by rotating the zoom box.
  2010.  
  2011.    My point is this: Please be *sure* that your formula produces only
  2012.    symmetrical images before including a symmetry declaration.  Otherwise
  2013.    you are likely to provoke confusion in your less experienced users, and
  2014.    to trigger misguided complaints about "Fractint bugs".
  2015.  
  2016.    Luckily, there are some ways to test for symmetry problems.  First, make
  2017.    sure that the formula you are testing *does not* have a symmetry
  2018.    declaration.  Now load the formula into Fractint and try this:
  2019.  
  2020.    1) If you can enter values into the formula via the P1, P2 or P3
  2021.       variables, try using a non-zero value for the imaginary parts.
  2022.  
  2023.    2) If you can specify functions via FN1 ... FN4, try using FLIP as one
  2024.       or more of those functions.  Use various combinations if possible.
  2025.  
  2026.    If you do these things and *still* only get symmetrical images, you are
  2027.    probably home free.  But be sure you try a lot of different parameters
  2028.    before drawing your conclusions.
  2029.  
  2030.  
  2031.    12.2  UNPARSABLE EXPRESSIONS IGNORED
  2032.    ------------------------------------
  2033.    The formula parser will tell you about some kinds of errors when it
  2034.    finds them.  If you try to use the expression "z = (z*z + (c*z)", it
  2035.    will recognize that there is a mismatch in the number of parentheses,
  2036.    for example.
  2037.  
  2038.    A different type of error goes unreported, though.  Look at the
  2039.    following formulas:
  2040.  
  2041.      frm-D1 { ;Unparsable expression ignored
  2042.        z = c = pixel:
  2043.          z = z*z + sin z + c
  2044.          |z| < 4
  2045.      }
  2046.  
  2047.      frm-D2 { ;fixed version of frm-D1
  2048.        z = c = pixel:
  2049.          z = z*z + sin(z) + c
  2050.          |z| < 4
  2051.      }
  2052.  
  2053.    In frm-D1 there is an incorrectly written expression, "sin z".  Although
  2054.    the intent may be clear to you or me, the parser can't make proper sense
  2055.    of it.  (Computers tend to take things *very* literally.)  Since the
  2056.    formula produces a normal-looking Mandelbrot set, it appears to me that
  2057.    the parser is simply skipping over this part of the formula. 
  2058.  
  2059.    Frm-D2 is here to show you what the fractal would look like if frm-D1
  2060.    had been written correctly.
  2061.  
  2062.  
  2063.    12.3  PATHOLOGICAL FORMULAS
  2064.    ---------------------------
  2065.    Some formula writers ignore (or are unaware of) the conventions, and
  2066.    produce formulas that "work" for the wrong reasons.
  2067.  
  2068.    For instance, take another look at IfThen-A1.  This formula could be
  2069.    written with the best of intentions, and it may even produce an
  2070.    interesting fractal, but it is based on a misunderstanding.  If you were
  2071.    the author of IfThen-A1, and if you understood the previous discussion
  2072.    about this formula, then I believe you should either simplify it as in
  2073.    IfThen-A2 or IfThen-A3, or correct it as in IfThen-C1 or IfThen-C2.
  2074.  
  2075.    In general, I think we should try to write formulas that someone else
  2076.    could comprehend.  Even well-written formulas can be hard to understand,
  2077.    so let's not carelessly (or deliberately) make it worse!  IfThen-A1 is
  2078.    obscure at best, and is likely to mislead the unwary reader.
  2079.  
  2080.    Even worse, some formula authors leave out parts.  Consider:
  2081.  
  2082.      weirdo { ;Mandelbrot with no bailout test
  2083.        z = c = pixel:
  2084.          z = z*z + c
  2085.      }
  2086.  
  2087.    This one has an initializing section and an iterated section, but
  2088.    there's no bailout test.  So what stops it from iterating?  In my first
  2089.    analysis, I assumed it would stop iterating only when 1) the maximum
  2090.    number for iterations had been reached, or 2) 'z' fell into a periodic
  2091.    loop.  Recall that in both of these situations, Fractint assumes that
  2092.    the "test point" (the value of pixel) is part of the set; therefore I
  2093.    expected that the whole screen would be colored blue.
  2094.  
  2095.    If you run the formula, though, you will see that I was wrong.  I get
  2096.    what looks like a normal Mandelbrot lake, but the color bands outside
  2097.    the set are different.  (Warning: if you're using Fractint version 18.2
  2098.    or earlier and don't have an FPU or math coprocessor, the program
  2099.    might crash.)
  2100.  
  2101.    Luckily for me, Tim Wegner was able to explain what was happening here.
  2102.    In brief:
  2103.  
  2104.    The parser uses a stack to store values.  (If you don't know what a
  2105.    stack is, just think of it for now as a location in memory.)  After the
  2106.    iterated section has been performed, the value remaining on the stack
  2107.    determines whether the formula will be reiterated.  It is just *assumed*
  2108.    that the last operation will be a comparison.
  2109.  
  2110.    Now if the value left on the stack is zero (as it would be with a FALSE
  2111.    comparison), then the iterations end.  Otherwise (assuming we haven't
  2112.    reached the maximum iteration number or fallen into a periodic loop) the
  2113.    parser loops back up to the colon.
  2114.  
  2115.    In "weirdo", the value left on the stack would be the value assigned to
  2116.    'z'.  So if by chance real(z) == 0, the iterations would stop and the
  2117.    parser would choose the next test-point.  For most test-points outside
  2118.    the M-set, however, the formula will keep iterating until 'z' becomes so
  2119.    large that a math error occurs; after this happens (and assuming
  2120.    Fractint didn't crash) the value left on the stack is zero.  Fortunately,
  2121.    versions 19.0 and higher should be able to take these errors in stride
  2122.    and move on to the next test point, even without an FPU or coprocessor.
  2123.  
  2124.    As Tim put it, instead of using an escape-time algorithm, this formula
  2125.    could be said to use a "crash-and-burn-time algorithm".
  2126.  
  2127.    A formula that depends on math errors to produce an image!  And "weirdo"
  2128.    is not unique; several formula files have been circulated containing
  2129.    formulas that lack bailout tests.
  2130.  
  2131.    I believe that this is undesirable, because even when it "works" the
  2132.    *way* that it works is exceedingly obscure.  If this fails to persuade
  2133.    you, consider that when you create images that depend on computational
  2134.    quirks, math errors or bugs, you may find it impossible to reproduce
  2135.    your images later on when the software has been revised.
  2136.  
  2137.    On the other hand, Tim has pointed out that most real-life fractals are
  2138.    poorly understood (if at all), and that many beautiful and mysterious
  2139.    images have been produced that depend on computational quirks or
  2140.    inaccuracies.  Why discount these images, just because we don't fully
  2141.    understand how they came about?
  2142.  
  2143.    What do you think?
  2144.  
  2145.  
  2146.    12.4  A GHOST STORY
  2147.    -------------------
  2148.    When formulas get complicated, it can be very difficult to understand
  2149.    what's happening.  That comment just proves my keen grasp of the
  2150.    obvious, I suppose, but here's an interesting example I found recently.
  2151.  
  2152.    (Warning -- murky water ahead!)
  2153.  
  2154.      ghost { ;Demonstrates strange parser behavior
  2155.              ;To see effect, use floating point and make sure
  2156.              ;FN2() is not IDENT
  2157.        z = oldz = c1 = pixel, c2 = fn1(pixel)
  2158.        tgt = fn2(pixel), rt = real(tgt), it = imag(tgt):
  2159.          oldx = real(oldz) - rt
  2160.          oldy = imag(oldz) - it
  2161.          olddist = (oldx * oldx) + (oldy * oldy)
  2162.          x = real(z) - rt
  2163.          y = imag(z) - it
  2164.          dist = (x * x) + (y * y)
  2165.          a = (dist <= olddist) * (c1)
  2166.          b = (olddist < dist)  * (c2)
  2167.          oldz = z
  2168.          z = z*z + a + b
  2169.          |z| <= 4
  2170.      }
  2171.  
  2172.      ghostless-A { ;One solution to the ghost problem -- reorder expressions
  2173.        z = oldz = c1 = pixel, c2 = fn1(pixel)
  2174.        tgt = fn2(pixel), rt = real(tgt), it = imag(tgt):
  2175.          oldx = real(oldz) - rt
  2176.          oldy = imag(oldz) - it
  2177.          olddist = (oldx * oldx) + (oldy * oldy)
  2178.          x = real(z) - rt
  2179.          y = imag(z) - it
  2180.          dist = (x * x) + (y * y)
  2181.          a = (c1) * (dist <= olddist) ;Reverse order of value and comparison
  2182.          b = (c2) * (olddist < dist)  ;Ditto
  2183.          oldz = z
  2184.          z = z*z + a + b
  2185.          |z| <= 4
  2186.      }
  2187.  
  2188.      ghostless-B { ;Another solution to the ghost problem -- reinitialize
  2189.        z = oldz = c1 = pixel, c2 = fn1(pixel)
  2190.        tgt = fn2(pixel), rt = real(tgt), it = imag(tgt):
  2191.          oldx = real(oldz) - rt
  2192.          oldy = imag(oldz) - it
  2193.          olddist = (oldx * oldx) + (oldy * oldy)
  2194.          x = real(z) - rt
  2195.          y = imag(z) - it
  2196.          dist = (x * x) + (y * y)
  2197.          a = b = 0                    ;Make sure a & b are set to zero
  2198.          a = (dist <= olddist) * (c1)
  2199.          b = (olddist < dist) * (c2)
  2200.          oldz = z
  2201.          z = z*z + a + b
  2202.          |z| <= 4
  2203.      }
  2204.  
  2205.    First, look at the "ghost" formula.  I created this formula while
  2206.    experimenting with new variations on the "in and out" theme.  You won't
  2207.    need to try to follow all of its logic; just note that this is a fairly
  2208.    complicated formula, with several variables and functions, an iterated
  2209.    section with many steps, and a couple of lines that use the conditional
  2210.    logic technique.
  2211.  
  2212.    If you'll look at the images that the "ghost" formula makes (make sure
  2213.    you're using floating-point math) you should notice a very strange
  2214.    thing: it appears that there is more than one image, and that these
  2215.    images are somehow superimposed over each other.
  2216.  
  2217.    This is an interesting effect, but it is due to the parser behaving in a
  2218.    way that I hadn't intended.  After quite a bit of experimenting, I found
  2219.    a few ways to make the ghosting effect go away.
  2220.  
  2221.    For example, set FN2() to IDENT.  No more ghosting; any other function
  2222.    will make it reappear, however.
  2223.  
  2224.    Now try the same formula with integer math.  Again, no ghosting problem,
  2225.    regardless of the function selected for FN2().
  2226.  
  2227.    Turn floating point back on and look at the images made by "ghostless-A"
  2228.    and "ghostless-B".  Once again, the ghosting effect vanishes.  If you'll
  2229.    compare these formulas to "ghost", you should see that the only
  2230.    difference is in the way the conditional logic lines were written.
  2231.    Instead of writing "a = (dist <= olddist) * (c1)", I wrote "a = (c1) *
  2232.    (dist <= olddist)". Thus, the order of the expressions seems to make a
  2233.    difference, even when care is taken to make the choices mutually
  2234.    exclusive, and even when assignments are performed *after* the
  2235.    comparisons are made.
  2236.  
  2237.    A possible hint about what is happening is provided by "ghostless-B".
  2238.    This formula is just like "ghost", except for the addition of the line
  2239.    "a = b = 0" just before the lines with the conditional logic.  With this
  2240.    line added, the formula makes the same images as "ghostless-A".
  2241.  
  2242.    The meaning of this (it seems to me) is that in the "ghost" formula, if
  2243.    "dist <= olddist" is FALSE, 'a' doesn't always get set to zero as I
  2244.    would expect.  My guess is 'a' just keeps the old value from the
  2245.    previous iteration.
  2246.  
  2247.    It has been suggested that floating-point optimizations may be behind
  2248.    this odd behavior.  If any reader knows more, please contact me.  But in
  2249.    the meantime, this appears to reinforce Chuck Ebbert's suggestion that
  2250.    when using conditional logic we should write the comparison expression
  2251.    after the '*'.
  2252.  
  2253.    Finally, I should point out that this "ghosting" effect is quite unusual
  2254.    in my experience; it's *not* an everyday problem.  I believe it is
  2255.    aggravated by the formula's complexity.  Let me illustrate:
  2256.  
  2257.      ghostless-C { ;Yet another solution -- simplify!
  2258.        z = c1 = pixel, c2 = fn1(pixel), olddist = 100
  2259.        tgt = fn2(pixel), rt = real(tgt), it = imag(tgt):
  2260.          x = real(z) - rt
  2261.          y = imag(z) - it
  2262.          dist = (x * x) + (y * y)
  2263.          a = (dist <= olddist) * (c1)
  2264.          b = (olddist < dist)  * (c2)
  2265.          olddist = dist
  2266.          z = z*z + a + b
  2267.          |z| <= 4
  2268.      }
  2269.  
  2270.    I simplified the logic of "ghost" and by doing this, I was able to
  2271.    eliminate three variables: oldx, oldy, and oldz.  This formula has no
  2272.    ghosting problem, even though the conditional statements are the same as
  2273.    in "ghost".  And because it is simpler, it is also faster!
  2274.  
  2275.    So here we have a problem with five different solutions: setting FN2()
  2276.    to IDENT, using integer math, changing the order of expressions,
  2277.    re-initializing variables, and simplifying formula logic.  Very
  2278.    peculiar...
  2279.  
  2280.    Although I don't yet know the real cause of the problem, I have drawn
  2281.    some lessons from the experience: If a formula gets too complicated,
  2282.    things might go haywire.  When the parser starts behaving strangely, try
  2283.    rewriting the formula in a different way.  And above all, look for ways
  2284.    to simplify your formulas.
  2285.  
  2286.  
  2287.    ===========================
  2288.    13.0  WHERE TO GO FROM HERE
  2289.    ===========================
  2290.  
  2291.    One of the amazing things about exploring a fractal is that you can
  2292.    continue to zoom deeper and deeper into the image, and yet you keep
  2293.    seeing new details.  Similarly, the study of fractals and formulas
  2294.    appears to offer an inexhaustible supply of new things to learn.  This
  2295.    document has only scratched the surface.
  2296.  
  2297.    Here are a few suggestions on how you can increase your knowledge.
  2298.  
  2299.  
  2300.    13.1  LEARN MORE ABOUT COMPLEX NUMBERS
  2301.    --------------------------------------
  2302.    Complex math lies at the heart of the fractals produced by the parser.
  2303.    If you have no understanding of the math, I don't see how you can
  2304.    really understand a formula.  So find a good teacher and take a class.
  2305.    Read a textbook or FRACTAL CREATIONS.  Practice complex arithmetic with
  2306.    a paper and pencil.  But don't skip over the subject, and don't be
  2307.    overwhelmed by the word "complex"; if you can learn algebra, you can
  2308.    learn about complex numbers.
  2309.  
  2310.  
  2311.    13.2  LEARN MORE ABOUT PROGRAMMING
  2312.    ----------------------------------
  2313.    It bears repeating that a formula is a program.  The parser language,
  2314.    although comparatively small, is sometimes more obscure than most modern
  2315.    programming languages; so if you have never learned another programming
  2316.    language, doing so would probably be very helpful to you.  Although the
  2317.    details vary from one language to another, there are common concepts
  2318.    that will help you understand Fractint formulas.  If you become familiar
  2319.    with the main concepts (variables, looping, assignment and comparison,
  2320.    conditional execution, etc.) in a setting that makes these concepts
  2321.    easier to understand, that experience will help you understand the
  2322.    programming aspects of a formula.
  2323.  
  2324.  
  2325.    13.3  LEARN MORE ABOUT FRACTALS
  2326.    -------------------------------
  2327.    You may not find this subject taught in your school yet, but there are
  2328.    some excellent books that can help you learn more.
  2329.  
  2330.    The best introductory book for a Fractint user (in my opinion) is still
  2331.    FRACTAL CREATIONS by Timothy Wegner and Bert Tyler.  The second edition
  2332.    of the book also includes a CD with some terrific images.
  2333.  
  2334.    James Gleick's CHAOS: MAKING A NEW SCIENCE is a fascinating introduction
  2335.    to the related notions of chaos, non-linear dynamics and fractals.  It
  2336.    discusses how and why these concepts came into being, and gives glimpses
  2337.    into the minds of some fascinating people.
  2338.  
  2339.    CHAOS AND FRACTALS: NEW FRONTIERS OF SCIENCE by Peitgen, Jurgens and
  2340.    Saupe is practically an encyclopedia of fractals; it's full of history,
  2341.    good illustrations, illuminating discussions of the math, and sample
  2342.    programs.
  2343.  
  2344.    THE FRACTAL GEOMETRY OF NATURE by Benoit Mandelbrot is the book that
  2345.    started it all, but be aware that it is *not* for the mathematical
  2346.    dilettante; neither is FRACTALS EVERYWHERE by Michael Barnsley.  Both
  2347.    books are very highly regarded as standard works in the fractal library,
  2348.    however.
  2349.  
  2350.    Clifford Pickover has written several books that discuss fractals,
  2351.    including COMPUTERS, PATTERN, CHAOS AND BEAUTY and MAZES FOR THE MIND.
  2352.    These books are jammed with great pictures, stimulating ideas, program
  2353.    listings and pseudo-code, and much more.  Dr. Pickover also edits the
  2354.    journal COMPUTERS AND GRAPHICS, which includes articles on fractal
  2355.    graphics.
  2356.  
  2357.    There are a few other periodicals that deal with fractals.  AMYGDALA is
  2358.    published in the US, while the diskette-based FRAC'CETERA comes to us
  2359.    from the UK.  Both of these publications are warmly endorsed by their
  2360.    readers.
  2361.  
  2362.  
  2363.    13.4  FIND OTHER FRACTAL ENTHUSIASTS
  2364.    ------------------------------------
  2365.    When you're struggling to learn new concepts, it's wonderful to have a
  2366.    knowledgeable friend who'll help you.  If you don't know anyone who fits
  2367.    that description, get a modem and go online.  You'll be able to meet
  2368.    fellow fractal nuts on CompuServe, for example, in the GRAPHDEV area.
  2369.    Look for fractal discussions on the Internet or on your favorite online
  2370.    service or BBS, and if nobody is talking about the subject, bring it up
  2371.    yourself.  We're a small minority, but our ranks are constantly growing.
  2372.    For years I created fractal images by and for myself, and I'm here to
  2373.    tell you that it's a *lot* more fun when you meet people with whom you
  2374.    can share your questions and accomplishments.
  2375.  
  2376.  
  2377.    ================
  2378.    14.0  CONCLUSION
  2379.    ================
  2380.  
  2381.    That's all for this iteration of the file.  I hope you found it to be
  2382.    interesting and instructive.  There's no doubt in my mind that it can be
  2383.    improved.  If you have any insights or suggestions that will make it
  2384.    better, please share them with me so I can share them with everyone
  2385.    else.
  2386.  
  2387.  
  2388.  
  2389.