Curve Fitting 3
 Volume Number: 1 Issue Number: 13 Column Tag: Forth Forum

# Curve Fitting, Part III

By Jörg Langowski, Chemical Engineer, Grenoble, France, MacTutor Editorial Board

Last time I promised you to add some input/output to the curve fitter program so that it becomes a useful application. We'll do this here today.

A lot of basic graphic routines which you would have to write yourself on other machines are included in the Quickdraw ROM. This makes life very easy; we can use the screen like we would use a plotter (of course, we can do much better than that, but this is what we are dealing with today). What is not included in the ROM, of course, are utilities that plot coordinate axes, draw lines through pairs of x/y points, add symbols etc.

Most computer systems that are used for numerical calculation purposes contain a set of standard plotting routines, mostly callable from FORTRAN, that will help you generating a 'nice' graphical output with not too much effort. This column gives you some similar routines in FORTH; I have tried to stick closely to the Calcomp plotting routines, since they are something of a standard.

Our objective is to produce something like the curve in Fig. 1. The data points that the model is fitted to will be displayed using some symbols, while the fitted curve is plotted as a smooth line. X- and Y-axes are added to the plot.

The numbers that are to be plotted will be given in floating point format (in this case, single precision arrays as defined previously). So first of all we have to know how to scale the data to the integer values of the bit map that we are going to plot to.

The Calcomp convention is, for an array of N floating point numbers, to store the minimum of these numbers in cell N+1 of the array and the difference between the minimum and the maximum in cell N+2. These two numbers are then rounded to one significant figure. Given this information, one can write routines that automatically draw an axis that spans the range of the data values.

The rounding to one significant figure is done by the word next.int, which given the address of an extended number on the stack returns with the address of the rounded number (which is a local variable of next.int).

fscale finds the minimum and maximum values of an array and stores the scaling numbers above the last data point after rounding them to one significant digit.

xaxis and yaxis draw coordinate axes in x- and y-direction. Input parameters are (#ticks\length\array\npts), #ticks gives the number of ticks to be drawn (to the bottom of the x- and to the left of the y-axis), length is the total axis length in points, array the address of the scaled data array and npts the number of points in array.

Given two scaled arrays, line draws a line through the (x y) pairs defined by the two arrays. The symbol defined by the global symbol is plotted at each of the data points. Symbols could be e.g. '+' or '*'. Setting symbol to zero will draw no symbols (how could you have guessed). Depending on the setting of the global flag connecting, the symbols are either connected by a line or not.

For all the plotting routines cartesian has to be switched on and the origin to be defined within the output window by xyoffset. init.plot is used to do this job.

The main curve fitter program now consists of the following:

- the data arrays xdat and ydat are initialized with the simulated 'experimental data' (init). In this month's example, we use a sum of two exponentials as our model; this gives us five parameters to fit.

- a routine is called in which one can deliberately change the values of the parameters (for this we need floating point input, see below), so that one can see how the correct curve is fitted through the data starting from wrong parameters. One may also change the total number of parameters to be fitted; for instance, fitting three parameters only will force a single exponential fit to the data points. In this case, parameters 4 and 5 will have to be set to zero.

- the main loop calculates theoretical function values from xdat and the parameters and stores them in zdat. The data arrays are scaled and the plot displayed (like in Fig. 1); then one iteration of the fitting routine is taken, the parameters changed accordingly, displayed and the process repeated until parameter changes are below 1 part in 104.

## Floating point input

As I mentioned, the program would not be very useful without floating point input routines. In order to be independent of any particular Forth implementation, I am including a simple floating point input routine here which accepts a string and converts it to the decimal string format used by the SANE conversion routines.

Any such routine would mainly consist of taking successive characters from the input string, generating a decimal mantissa and keeping track of the number of digits behind the decimal point, then looking for an 'e' or 'E' to indicate an exponent and converting the exponent finally. In that aspect, the routine written here is very similar to the MacForth floating input routine. There is one difference, in that numbers without an exponent will be accepted and converted to floating point numbers, too. Therefore, you won't be able to use this routine as an extension of the Forth interpreter, as MacForth level 2 does. But in entering a lot of data, it can be very tedious always having to type an exponent.

fnumber takes a string as its input parameter and leaves on the stack:

```( addr of float\true ) if a valid floating point number was read from
the string,
( false ) if the conversion was not successful.
```

In the latter case, an error message is printed.

input.float reads a string from the keyboard into pad, then calls fnumber to convert it.

With the additions from this column, the curve fitter should finally be a utility that is useful to you (in case you have any curves to fit). Changing the function to be fitted is easy, and you might even install a make switch for vectored execution (V1#7) so that you can easily switch between different functions within one program.

Data input still has to be done manually, number by number. However, input.float may easily be extended to read input from a file. To transfer data to/from other applications through the scrap requires some more work; I'll deal with that problem soon.

## Feedback dept. Re: finding object code of unnamed tokens

The procedure to decompile the object code of an axed token is the following (V1#2):

- convert the token to an absolute address, using token>addr. If the word contained there is \$4e4f (TRAP \$F), the next words will be Forth code. Start decompiling at the following word. Of course, different versions of MacForth will give different addresses for the individual words due to different dictionary arrangements; but this procedure should work for any version of Level 1 or Level 2.

## Re: MacModula floating point

Shortly after my comment on errors in MacModula 2's 32-bit floating point arithmetic, I received a letter from the author of those routines, Daan Strebe:

" A few weeks ago I followed several bug reports to find two fundamental errors in the floating-point routines, one a conceptual error in the rounding and the other a misunderstanding about the 68000 processor instruction set. These two errors affected the multiply routine most, although the others were somewhat affected also. I revamped those routines and then ran a complex set of comprehensive tests, and the results allow me to state with a margin of confidence that the floating point in the latest rev is now not only slightly faster than it was, but also that the only errors in the basic routines (not necessarily including those in the math library) are from rounding. The rounding as it is now implemented yields 3 downward, 4 upward, and 1 non-round per 8 random floating-point operations. This should be satisfactory for most users; full IEEE rounding would considerably decrease the speed. I believe the compromise was successful. "

So everything should be fixed now. Let's hope that the new update will be distributed soon (it probably is when this goes to the printer's).

```Listing 1: Plotting routines and floating point input for the curve fitter
program

( Additions to the curve fitting program)
( for graphical output and floating point input.)
( © 1985 J. Langowski for MacTutor)
( Again, only the parts that have been changed)
( or added with respect to the last two columns )
( are printed here)

: s> 1008 fp68k @sr 10 and ;

: numstring create 24 allot ;
numstring zzs1 ( internal conversion string )

: dec. ( float\format# -- )
zzformat ! zzformat swap zzs1 b2d
zzs1 dup w@ 255 > if ." -" else ."  " then
dup 4+ count over 1 type ." ."
swap 1+ swap 1- type ( mantissa )
2+ w@ ( get exponent )
1 w* zzformat @ + 1-
." E" 0 .r ;

create xdat 400 allot   create ydat 400 allot
create zdat 400 allot   create residues 400 allot
100 10 matrix derivmat    10 11 matrix resmat
5 constant npars        80 constant npts
create par 5 10 * allot
create delta 5 4*  allot

float logten  ten logten x2x  logten lnx
: log10x dup lnx logten swap f/ ;

( define function )                               ( 090485 jl )
float temp ( local to func)

func ( x -- f[x] = par[1] + par[2] * exp[par[3]*x]
+ par[4] * exp[par[5]*x] )
dup temp x2x
par 40 + temp f* temp expx  par 30 + temp f*
par 20 + over f* dup expx  par 10 + over f*
par over f+  temp over f+ ;
axe temp
: >fa1  fa1 s2x ;
: init_pars   one par x2x  two par 10+ x2x
-one par 20 + x2x  two par 20 + f/
one par 30 + x2x
-one par 40 + x2x ten par 40 + f/ ;
init_pars

: one_iter
make_derivmat  residuals
make_resmat     delta 0 0 resmat npars gauss ;

: new_pars 16 ( true if no significant changes)
npars 0 do par i 10 * +
delta i 4* +  over  s+
delta i 4* + fa1 s2x  fa1 f/
fa1 fabs  eps fa1 f> and loop ;

80 ' npts !    5 ' npars !

: init ( initialize data arrays)
npts 0 do i sp@ fa1 in2x 4*
xdat over + fa1 swap x2s
ydat over + fa1 func  ranf fa2 x2x
ten fa2 f/  fa2 over f+  swap x2s
drop  loop ;

( plotting routines)                        ( 092385 jl )
float 1/2  1 sp@ 1/2 in2x drop  2 sp@ 1/2 in/ drop
float small  ten small x2x  -200 sp@ fa1 in2x drop
fa1 small x^y
( anything smaller than small will be zero)
float sc.aux  float sc.exp
: next.int ( float -- rounded to 1 dec. place )
dup small f>
if dup sc.aux x2x  sc.aux  dup fabs  dup log10x
dup 1/2 swap f- frti
ten sc.exp x2x  sc.aux sc.exp x^y   sc.aux x2x
sc.exp sc.aux f/  sc.aux frti  sc.exp sc.aux f*
sc.aux
else drop zero then  ;

float xlow  float xhi  float sc.factor
: fscale
( array \ n -- | start, scale -> array[n+1..n+2] )
over xlow s2x  over xhi s2x
over over 1 do
dup i 4* + dup xlow s> not if dup xlow s2x then
dup xhi  s> if xhi s2x  else drop then  loop
xlow xhi f-
over 4*  +  xlow next.int swap x2s
1+ 4* +  xhi  next.int swap x2s  ;

: .fscale ( array \ n -- )
4* + dup fa1 s2x ." min = " fa1 7 dec.
4+ fa1 s2x ." , scale = " fa1 7 dec. cr ;

( xtick, ytick )                                  ( 092385 jl )

: xtick ( rx x -- ) dup 0 move.to
dup -5 draw.to  dup 15 - -16 move.to
get.textsize >r 9 textsize swap 2 dec. r> textsize
0 move.to ;

: ytick ( ry y -- ) -45 over 4- move.to
get.textsize >r 9 textsize swap 2 dec. r> textsize
0 over move.to    -5 over draw.to
0 over 6- move.to  0 swap draw.to ;

( xaxis)                                           ( 092385 jl )
float start  float del
: xaxis
( #ticks\length\array\npts -- | starts at origin )
0 0 move.to
4* + dup  start s2x  4+ delta s2x
over /  ( #ticks\length/tick -- )
over 0 do dup i 1+ * dup 0 draw.to
delta fa1 x2x i 1+ sp@ fa1 in* drop
3 pick sp@ fa1 in/ drop
start fa1 f+    fa1 swap xtick loop
drop drop ;

( yaxis)                                          ( 092385 jl )
: yaxis
( #ticks\length\array\npts -- | starts at origin )
0 0 move.to
4* + dup  start s2x  4+ delta s2x
over /  ( #ticks\length/tick -- )
over 0 do dup i 1+ * 0 over draw.to
delta fa1 x2x i 1+ sp@ fa1 in* drop
3 pick sp@ fa1 in/ drop
start fa1 f+    fa1 swap ytick loop
drop drop ;

( line, variables )                               ( 092585 jl )
variable xline.length variable yline.length
variable xpos  variable ypos  variable symbol
variable connecting  connecting off
float xstart float ystart float xdel float ydel

( line)                                           ( 092585 jl )
: line ( xarray\yarray\npts\xlength\ylength -- )
yline.length !  xline.length !   0 0 move.to
over over 4* + dup ystart s2x 4+ ydel s2x
3 pick over 4* + dup xstart s2x 4+ xdel s2x
0 do over i 4* + fa1 s2x  xstart fa1 f-  xdel fa1 f/
dup  i 4* + fa2 s2x  ystart fa2 f-  ydel fa2 f/
xline.length fa1 in*  fa1 xpos x2in
yline.length fa2 in*  fa2 ypos x2in
xpos @  ypos @  over over
connecting @ if draw.to else move.to then
-4 -4 rmove symbol @ emit move.to
loop   drop drop ;

( calc.theor, disp.theor, disp.data, scale.all)
( 092585 jl )
: calc.theor
npts 0 do xdat i 4* + fa1 s2x fa1 func
zdat i 4* + x2s  loop ;
: disp.theor
0 symbol !  connecting on
xdat zdat npts 400 250 line ;
: disp.data
43 symbol !  connecting off
xdat ydat npts 400 250 line ;
: scale.all
xdat npts fscale  ydat npts fscale
ydat npts 4* + @  zdat npts 4* + !
ydat npts 1+ 4* + @  zdat npts 1+ 4* + !  ;

( disp.axes)                                      ( 092585 jl )
: disp.axes
5 400 xdat npts xaxis  5 250 ydat npts yaxis ;
: init.plot
page 50 255 xyoffset cartesian on ;

( floating point input)                           ( 092385 jl )
: fsign zzs1 ;  : fexpo zzs1 2+ ;
: fmant zzs1 4+ ;  variable frac   float float.out
variable decimals
: input.sign 0 fsign !
dup c@ case 45 of -1 fsign w! 1+ endof
43 of             1+ endof endcase ;
: input.mantissa   0 decimals !   0 frac !
fmant 21 +  fmant 1+ do  i fmant 1+ -  fmant c!
dup c@ dup
case 48 57 range.of ic! frac @ decimals +!
1+ 1 endof
46 of   drop 1 frac !    1+ 0 endof
20 swap endcase  +loop drop ;
: input.exponent
dup c@ dup bl = not
if dup 69 =  swap 101 =  or not
if  drop 0
else dup 1+ c@ 43 = 1 and +
number decimals @ - fexpo w! -1
then
else  decimals @ -1 * fexpo w! -1  2drop
then  ;

: fnumber zzs1 24 blanks
if fsign float.out d2b float.out -1
else ." floating input error!" cr 0 then ;

: get.pars
npars 0 do
begin cr ." par[" i 1+ . ." ] = " input.float until
par i 10 * + x2x loop
cr begin cr ." total # of parameters to be fitted "
5 input.number until
' npars !  cr ;

: .pars npars 0 do
." par[" i 1+ . ." ] = " i 10 * par + 7 dec. cr loop ;

( main curve fitter program)                 ( 092685 jl )
: fit.curve  page
init_pars ." initializing data arrays..." cr init
5 ' npars ! init.plot get.pars .pars
." fitting " npars . ." parameters to "
npts . ." data points "
calc.theor scale.all page
disp.data disp.axes disp.theor
begin  one_iter new_pars not while
page .pars
calc.theor page disp.data disp.axes disp.theor
repeat
300 300 move.to ;
```

Community Search:
MacTech Search:

Live Home 3D Pro 3.6.2 - \$49.99
Live Home 3D Pro is powerful yet intuitive home design software that lets you build the house of your dreams right on your Mac, iPhone or iPad. It has every feature of Live Home 3D, plus some... Read more
RapidWeaver 8.2 - Create template-based...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
Opera 60.0.3255.109 - High-performance W...
Opera is a fast and secure browser trusted by millions of users. With the intuitive interface, Speed Dial and visual bookmarks for organizing favorite sites, news feature with fresh, relevant content... Read more
DEVONthink Pro 3.0beta2 - Knowledge base...
DEVONthink Pro is your essential assistant for today's world, where almost everything is digital. From shopping receipts to important research papers, your life often fills your hard drive in the... Read more
Tunnelblick 3.7.9 - GUI for OpenVPN.
Tunnelblick is a free, open source graphic user interface for OpenVPN on OS X. It provides easy control of OpenVPN client and/or server connections. It comes as a ready-to-use application with all... Read more
Carbon Copy Cloner 5.1.9 - Easy-to-use b...
Carbon Copy Cloner backups are better than ordinary backups. Suppose the unthinkable happens while you're under deadline to finish a project: your Mac is unresponsive and all you hear is an ominous,... Read more
Dropbox 73.4.118 - Cloud backup and sync...
Dropbox is an application that creates a special Finder folder that automatically syncs online and between your computers. It allows you to both backup files and keeps them up-to-date between systems... Read more
Postbox 6.1.18 - Powerful and flexible e...
Postbox is a new email application that helps you organize your work life and get stuff done. It has all the elegance and simplicity of Apple Mail, but with more power and flexibility to manage even... Read more
Wireshark 3.0.2 - Network protocol analy...
Wireshark is one of the world's foremost network protocol analyzers, and is the standard in many parts of the industry. It is the continuation of a project that started in 1998. Hundreds of... Read more
BetterTouchTool 2.856 - Customize multi-...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom... Read more

## Latest Forum Discussions

AFK Arena guide - Everything you need to...
Ok, so if you're like me, you've been playing (and sometimes waiting) your way through AFK Arena, only to learn there's a lot more to it than there appears on the surface. There's guilds, a PvP arena, and all sorts of other systems and game modes... | Read more »
Explore an epic fantasy world in MMORPG...
Webzen have just announced the official launch date for its stunning MMORPG ‘MU Origin 2’ which will arrive for iOS and Android on May 28th. It will be the second spinoff from the classic PC-based MU Online, and it looks to further refine the... | Read more »
Solar Explorer: New Dawn guide - Tips an...
Solar Explorer: New Dawn is a lunar lander game that really ratchets the intensity up to 11. With all of the asteroids flying around as you fly around at seemingly breakneck speeds, it can be easy to feel overwhelmed bythe whole thing. | Read more »
The Dalaran Heist - How Hearthstone...
I am someone who wrote Hearthstone off a while ago. It was hard not to try and stick with it. The game has incredible production values and a core of really great talent working on the game continuously to keep it feeling fresh and fun (full... | Read more »
Steam Link App - Everything You Need to...
Steam Link has finally released for iOS! That’s right, you can play your epic backlog of PC games on the go now. Well… sort of. While the Steam Link app was announced seemingly ages ago, it only got actual approval for release last night. Check out... | Read more »
Pre-register now for endless superhero r...
Talking Tom Hero Dash is set to take the ever-popular Talking Tom and Friends franchise in a brand new direction as it opens pre-registration to players worldwide. Not only does it promise to be a beautifully rendered, fast-paced, action-packed... | Read more »
AFK Arena - Guild Wars guide
Ok, so if you're like me, you've been playing (and sometimes waiting) your way through AFK Arena, only to learn there's a lot more to it than there appears on the surface. There's guilds, a PvP arena, and all sorts of other systems and game modes... | Read more »
Superhero-themed Talking Tom Hero Dash i...
One of the exciting releases that we’re looking forward to is Talking Tom Hero Dash, an upcoming superhero-themed runner created by Outfit7. This new game is an action-packed endless runner that takes you on an epic adventure to assemble the... | Read more »
Kingdom Rush Vengeance Update Guide 2 -...
Kingdom Rush: Vengeance just got updated once again to add more content to the game. This addition, called The Frozen Nightmare, adds three new levels, five new enemies, two new heroes, and some new achievements. | Read more »
Save the world with SCIENCE in the upcom...
Previous versions of space colonization game TerraGenesis encouraged you to explore the galaxy and settle its planets. The eagerly-awaited 5.0 update will try to smash them to bits. Yep, with a new "world killers" setting, you can unleash... | Read more »

## Price Scanner via MacPrices.net

12″ 1.2GHz MacBooks on sale for \$999, \$300 of...
Amazon has current-generation 12″ 1.2GHz Retina MacBooks on sale for \$300 off Apple’s MSRP. Shipping is free: 12″ 1.2GHz Space Gray MacBook: \$999.99 \$300 off MSRP 12″ 1.2GHz Silver MacBook: \$999.99 \$... Read more
Here’s how to save \$200 on Apple’s new 8-Core...
Apple has released details of their Education discount associated with the new 2019 15″ 6-Core and 8-Core MacBook Pros. Take \$200 off the price of the new 8-Core model (now \$2599) and \$150 off the 15... Read more
Price drops! 2018 15″ 2.2GHz 6-Core MacBook P...
Amazon has dropped prices on clearance 2018 15″ 2.2GHz 6-Core Touch Bar MacBook Pros by \$300 with models now available for \$2099. These are the same models sold by Apple in their retail and online... Read more
Apple drops prices on 2018 13″ 2.3GHz Quad-Co...
Apple has dropped prices on Certified Refurbished 2018 13″ 2.3GHz 4-Core Touch Bar MacBook Pros with prices now starting at \$1489. Apple’s one-year warranty is included, shipping is free, and each... Read more
Apple drops prices on 2018 Certified Refurbis...
Apple has dropped prices on clearance 2018 15″ 6-Core Touch Bar MacBook Pro, Certified Refurbished, with models available starting at only \$1999. Each model features a new outer case, shipping is... Read more
Price drops! Clearance 2018 13″ Quad Core Mac...
Amazon has dropped prices on 2018 13″ Apple Quad-Core MacBook Pros with models now available for \$250 off original MSRP. Shipping is free. Select Amazon as the seller, rather than a third-party, to... Read more
How Much Is ‘Solace’ Of Mind Worth When Buyin...
COMMENTARY: 05.22.19- Smartphone cases give us peace of mind by providing ample protection for such a fragile gadget and the sky’s the limit as far as choices go with a plethora of brands, styles,... Read more
Get a 13″ Touch Bar MacBook Pro for the lowes...
Apple has Certified Refurbished 2017 13″ 3.1GHz Dual-Core i5 Touch Bar MacBook Pros available starting at \$1439, ranging up to \$390 off original MSRP. Each MacBook features a new outer case, shipping... Read more
Apple adds new 15″ 8-Core MacBook Pro to line...
Apple has added a new 15″ MacBook Pro to its lineup featuring a 9th generation 2.3GHz 8-Core Intel i9 processor, 16GB of RAM, a 512GB SSD, and a Radeon Pro 560X with 4GB of GDDR5 memory for \$2799.... Read more
21″ 2.3GHz iMac available for \$999 at B&H...
B&H Photo has the 2018 21″ 2.3GHz Apple iMac on sale for \$100 off MSRP. This is the same model offering by Apple in their retail and online stores. Shipping is free: – 21″ 2.3GHz iMac (MMQA2LL/A... Read more

## Jobs Board

Best Buy *Apple* Computing Master - Best Bu...
**690427BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Sales **Location Number:** 000860-Charlottesville-Store **Job Description:** **What Read more
*Apple* Mobile Master - Best Buy (United Sta...
**696430BR** **Job Title:** Apple Mobile Master **Job Category:** Store Associates **Location Number:** 001012-Bismarck-Store **Job Description:** **What does a Best Read more
Manager - *Apple* Team - SHI International...
…opportunity available in the Hardware & Advanced Solutions Department as the Manager of the Apple Team The Manager must be familiar with all aspects of Apple Read more
Best Buy *Apple* Computing Master - Best Bu...
**696375BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Sales **Location Number:** 000203-North Austin-Store **Job Description:** **What does a Read more
Geek Squad *Apple* Master Consultation Agen...
**696286BR** **Job Title:** Geek Squad Apple Master Consultation Agent **Job Category:** Services/Installation/Repair **Location Number:** 000172-Rivergate-Store Read more