Level 4, lesson 8

# 4.8 Fixed point calculation

We already learned that if we can't calculate it out in dollars, we can calculate it in cents. And still present the result in dollars using pictured numeric output:

         : currency <# # # char . hold #s char $ hold #> type cr ;

In this case, this:

         200012 currency

will print this:

         $2000.12

Well, that may be a relief for the bookkeepers, but what about us scientists? You can do the very same trick. We have converted some Forth code for you that gives you very accurate results. You can use routines like SIN, COS and SQRT. A small example:

         31415 CONSTANT PI
         10000 CONSTANT 10K         ( scaling constant )
         VARIABLE XS                ( square of scaled angle )

         : KN  ( n1 n2 -- n3, n3=10000-n1*x*x/n2 where x is the angle )
               XS @ SWAP /          ( x*x/n2 )
               NEGATE 10K */        ( -n1*x*x/n2 )
               10K +                ( 10000-n1*x*x/n2 )
         ;

         : (SIN)                    ( x -- sine*10K, x in radian*10K )
               DUP DUP 10K */       ( x*x scaled by 10K )
               XS !                 ( save it in XS )
               10K 72 KN            ( last term )
               42 KN 20 KN 6 KN     ( terms 3, 2, and 1 )
               10K */               ( times x )
         ;

         : SIN                      ( degree -- sine*10K )
               PI 180 */            ( convert to radian )
               (SIN)                ( compute sine )
         ;

If you enter:

         45 sin . cr

You will get "7071", because the result is multiplied by 10000. You can correct this the same way you did with the dollars: just print the number in the right format.

         : /10K. <# # # # # char . hold #S #> type cr ;
         45 sin /10K.

This one will actually print:

         0.7071

But note that 4tH internally still works with the scaled number, which is "7071". Another example:

         : SQRT                     ( n1 -- n2, n2**2<=n1 )
               0                    ( initial root )
               SWAP 0               ( set n1 as the limit )
               DO 1 + DUP           ( refresh root )
                    2* 1 +          ( 2n+1 )
               +LOOP                ( add 2n+1 to sum, loop if )
         ;                          ( less than n1, else done )

         : .fp <# # char . hold #S #> type cr ;

If you enter a number of which the root is an integer, you will get a correct answer. You don't even need a special formatting routine. If you enter any other number, it will return only the integer part. You can fix this by scaling the number.

However, scaling it by 10 will get you nowhere, since "3" is the square root of "9", but "30" is not the square root of "90". In that case, we have to scale it by 100, 10,000 or even 1,000,000 to get a correct answer. In order to retrieve the next digit of the square root of "650", we have to multiply it by 100:

         650 100 * sqrt .fp

Which will print:

         25.4

To acquire greater precision we have to scale it up even further, like 10,000. This will show us, that "25.49" brings us even closer to the correct answer.

You might not be able to find the routine here that you actually need. We are not much of a mathematician, but when we encounter new routines they will be added to 4tH. We would appreciate your input!