
       FRACTINT'S NEW FLOW CONTROL INSTRUCTIONS FOR THE FORMULA PARSER


    Version 19.6 of Fractint provides for flow control statements in user
  created formulas.  This feature should make formulas more readable, and
  preliminary testing indicates that more complicated formulas will run as
  much as 2 to 3 times faster when the formula is written using the new
  instructions.

    This tutorial provides an overview of the new feature.  It assumes that
  the reader is familiar with the syntax of Fractint formulas.  If you are
  new to Fractint, the documentation accompanying Fractint provides a good
  start, and Bradley Beacham's tutorial (available in Library 4 of the
  CompuServe Graphics Developers Forum as frmtut.zip, and at Noel Giffen's
  Fractint web page - http://spanky.triumf.ca) will provide a more detailed
  explanation of Fractint formula writing.  Sylvie Gallet's tutorial on PHC
  and PTC formulas is a more advanced text, and is available at the same
  sites. These tutorials are also included in the Fractint v. 19.6 package.

    Until Fractint v. 19.6, each section of a Fractint formula was always
  executed one instruction at a time, sequentially through the section
  without exception.  Formula writers worked out ingenious solutions to
  achieve different results in a formula based on a testing of some
  condition.  For example, if the writer wanted c to be equal to sin(z) if
  x==y, and cos(z) if not, the formula would contain the following line:

    c = sin(z)*(x==y) + cos(z)*(x!=y)

    Each time this line is reached in the formula, which in the course of
  drawing an image could be many millions of times, each element of the line
  is computed, so both the x==y and the x!=y tests are evaluated (one of
  which, of course, will be 0 and the other 1), and both sin(z) and cos(z)
  are computed.  Obviously, it would be much more efficient to evaluate only
  x==y, and then compute only sin(z) or cos(z) depending on the result.


THE NEW FLOW CONTROL INSTRUCTIONS

    Four new formula instructions are now permitted in a Fractint formula.
  They are:

      IF (expression)
      ELSEIF (expression)
      ELSE
      ENDIF

    Each of these instructions must be a separate statement in the formula,
  i.e. must end with a comma or an end-of-line character.
    The easiest way to avoid problems with this requirement is to put each
  of these instructions on a separate line.  The practice of the people
  testing the new feature has been to capitalize the flow control
  instructions and to indent the regular calculations which follow them.

    A group of these instructions beginning with IF and ending with ENDIF
  constitutes a unit which I'll refer to as an "if block" of instuctions.
  A formula may contain any number of if blocks, and if blocks may be nested
  inside other if blocks.  The only limitation is that the end of the
  initialization section (represented by a ":" in the formula) cannot be
  inside an if block.

    An if block contains exactly one IF, exactly one ENDIF, no more than 1
  ELSE (there may be none), and any number of ELSEIFs (there may be none),
  but all ELSEIFs must precede the block's ELSE instruction.  The format is
  therefore as follows:

      IF (expression)
         statements
      ELSEIF (expression)
         statements
      ELSEIF (expression)
         statements
      .
      .
      ELSE
         statements
      ENDIF

    ELSEIF (expression) is the equivalent of two flow control instructions,
  an ELSE immediately followed by an IF ().  The difference between the
  single and the separated instructions is that ELSEIF does not require its
  own ENDIF, whereas ELSE followed by IF would require that the separate IF
  have its own ENDIF.

    The example above, restated using these instructions, will read as
  follows:

      IF (x==y)
         c = sin(z)
      ELSE
         c = cos(z)
      ENDIF

    Not only is this formulation intuitively easier to understand than the
  earlier one, it also runs much faster, because only the elements necessary
  to make the desired assignment to c are executed.

    The formula parser does the following with these instructions:

  1. Evaluate the expression inside the parentheses of the IF instruction.
     Boolean expressions in Fractint (expressions which use the operators
     ==, !=, >, <, >=, <=, && and ||) alway evaluate to (1,0) if the
     expression is true and (0,0) if the expression is false.  The nature
     of branching instructions is such that the expression in the
     parentheses of an IF instruction will almost always be boolean, but
     this is not a requirement.  Any expression which evaluates to a
     single complex number is acceptable.  Thus, though unusual, the
     instruction IF(x+y) is perfectly valid, since the result of x+y is a
     complex number.

  2. Look at the real element, and only the real element, of the
     expression.  If it is nonzero, the expression represents "true".
     If the real element is zero, the expression represents "false".
     Thus (1,0), (-1,0), and (3.14, 6) are all "true" results.  (0,0),
     (0,1) and (0,-1) are all "false" results.

  3. If the expression is true, proceed to the next statement in the
     formula without any skipping.

  4. If the expression is false, skip to the statement immediately following
     the next flow control instruction in the if block (of necessity, an
     ELSE, the ELSE element of an ELSEIF(), or ENDIF), and begin further
     processing from there.

  5. If an ELSE or the ELSE portion of an ELSEIF() instruction is reached
     in the course of processing, jump to the instruction following the
     ENDIF at the end of that if block.

    Looking at the above example, the parser first evaluates the expression
  x==y.  If it is true, the next statement, c = sin(x) is executed, and then,
  the ELSE now being reached, execution jumps to the ENDIF.  If x==y is
  false, execution jumps straight to the statement after the ELSE, which is
  c = cos(x), and executes it, continuing on from there.

    With a little reflection you will realize that only one of the sets of
  statements following flow control instructions in an if block is executed.
  For example,

      IF (expr1)
         group1_statements
      ELSEIF (expr2)
         group2_statements
      ELSEIF (expr3)
         group3_statements
      ELSE
         group4_statements
      ENDIF

    If expr1 is true, the group1_statements will be executed and then the
  execution will jump to the ENDIF.  The fact that expr2 or expr3 may be
  true is irrelevant; the conditions will not be tested if expr1 is true.
  If expr1 is false, then expr2 will be tested, and if true the
  group2_statements will be executed, and when done the execution will jump
  to the ENDIF.  expr3 is only evaluated if expr1 and expr2 are both false.
  You can also see that the group4_statements will only be executed if all
  three of the test expressions are false.

    If there is no ELSE statement in an if block, it is possible that none of
  the calculation statements in the block will be executed.  For example,

      IF (expression)
         statements
      ENDIF

    will cause the statements to be executed only if the expression is true;
  otherwise they are skipped entirely.

EXAMPLE

    Carr2821 is one of Bob Carr's many formulas which make use of the
  formula branching technique developed by Sylvie Gallet.  It has received
  much attention lately because of Lee Skinner's marvelous collection of 186
  images derived from the formula.
    Following is the original formula and an IF..ELSE rewrite of it.  In
  addition to the straightforward switch from the old method of branching to
  the new, you will see that the flow control instructions make much easier
  the implementation of other short cuts which speed up execution.
    The IF..ELSE rewrite produces the same images as the original, but in
  about 1/2 the time, depending on your processor.

  Carr2821 {; Modified Sylvie Gallet frm. [101324,3444],1996
            ; passes=1 needs to be used with this PHC formula.
    b5=pixel-conj(0.1/pixel)
    b4=pixel-flip(0.1/pixel)-conj(0.001/pixel),
    c=whitesq*b4-(whitesq==0)*b4
    z=whitesq*b5-(whitesq==0)*b5
    c1=1.5*z^1.2,c2=2.25*conj(z),c3=3.375*flip(z),c4=5.0625*flip(z),
    l1=real(p1),l2=imag(p1),l3=real(p2),l4=imag(p2),
    bailout=16,iter=0:
    t1=(iter==l1),t2=(iter==l2),t3=(iter==l3),t4=(iter==l4),
    t=1-(t1||t2||t3||t4),z=z*t,c=c*t+c1*t1+c2*t2+c3*t3+c4*t4,
    z=(|z|/5)+z*z+c-0.09/pixel
    iter=iter+1
    |z|<=bailout
  }

  carr2821 {; Modified Sylvie Gallet frm. [101324,3444],1996
            ; Converted to if.else by Sylvie Gallet and George Martin 3/97
            ; passes=1 needs to be used with this PHC formula.
     pixinv = 0.1/pixel
     p9 = 0.9*pixinv
     imagp1 = imag(p1)
     imagp2 = imag(p2)
     IF (whitesq)
        z = zorig = pixel - conj(pixinv)
        c = pixel - flip(pixinv) - conj(0.01*pixinv) - p9
        mz = |z|
     ELSE
        z = zorig = conj(pixinv) - pixel
        c = flip(pixinv) + conj(0.01*pixinv) - pixel - p9
        mz = |z|
     ENDIF
     bailout = 16
     iter = 0
     :
     IF (iter==p1)
        z = mz = 0
        c = 1.5*zorig^1.2 - p9
     ELSEIF (iter==imagp1)
        z = mz = 0
        c = 2.25*conj(zorig) - p9
     ELSEIF (iter==p2)
        z = mz = 0
        c = 3.375*flip(zorig) - p9
     ELSEIF (iter==imagp2)
        z = mz = 0
        c = 5.0625*flip(zorig) - p9
     ENDIF
     z = mz*0.2 + z*z + c
     mz = |z|
     iter = iter + 1
     mz <= bailout
  }


REWRITING OLD FORMULAS

    There are more than 1500 existing Fractint formulas which could be
  written in IF..ELSE format.  If you have occasion to rewrite one, you
  should test the rewrite to make sure it is drawing the identical images
  that the original version did.  To perform this test, do the following:

  1. Using a .par file image entry which uses the formula, render the image
     using the old formula, and save the image (e.g. as oldimage.gif).

  2. Using the same .par file image entry, render the image using the
     rewritten formula, and save the image (e.g. as newimage.gif).

  3. Exit Fractint, and restart with the following command line options
     selected:  debug=50  filename=oldimage.gif

  4. With oldimage.gif on the screen, hit <r> and select newimage.gif to
     restore to the screen. Hit <CR>

  5. The effect of debug=50 is that the pixels which will be shown in the
     second restored image will only be those which are different than the
     image previously on the screen.  If the images are identical, you will
     have a completely blank screen.

  6. Differences are saved to an ASCII file "cmperr".  Exit Fractint and
     check this file to assure yourself that the two images were in fact
     identical.

    Images drawn in floating point mode on a computer with a math coprocessor
  or a 486 or higher processor may have slight pixel variation between an
  original and an if..else rewrite because of certain optimizations
  implemented in the "fast parser" code.  If you are seeing these variations
  and want to make sure the rewritten formula is accurate, draw the images
  using the original and rewritten formulas with the command line parameter
  debug=322 selected.  This causes Fractint to skip the optimization code,
  and differences caused by the optimizer will therefore be eliminated. If 
  you still have differences and believe your rewrite is accurate, try again
  with debug=90 selected. This eliminates the use of the fast parser 
  entirely, and the original formula and your rewrite, if correct, should 
  produce identical images. 

    
    If you are satisfied that you have a good rewrite, post the revised
  formula in a message in the Fractint forum on CompuServe, or send an email
  with the revised formula to me (76440.1143@compuserve.com).  It will be
  helpful if the message includes both the old and rewritten formula, and a
  .par image entry using the formula so that we can easily verify the
  accuracy of the rewrite.  Good rewrites will be added to the orgform
  compilation of formulas in place of the old formula, with credit given to
  the author of the rewrite.

    Thanks to Sylvie Gallet and Les StClair for their help in writing this
  tutorial.

    George Martin
    3/23/97
