LaFarr Stuart's Integer Arithmetic Progam IA

Last Up date on: 2003 November 14

DH came into existence because I needed to convert large decimal numbers to Hexadecimal. The pocket calculators I had did not have the accuracy I wanted; nor could I put my hands on a program that gave the accuracy I needed. I was frustrated. I could certainly do it with a pencil and paper; but that was a lot of work and my arithmetic is prone to error. I had a computer with 8 megabytes of memory; but it could not handle accurately a number with 20 decimal digits!

It took less than a day to write a program that would input virtually any number of decimal digits converting the value to binary. (For each additional digit you just multiply the current value by ten and add on the digit.) The following is roughly the order in which enhancements came into being:

  1. It should display the result; and then take another value.
  2. It should be able to take more than one value. A Stack would be a neat way to handle several values.
  3. It should be able to convert the other way from Hex to Decimal.
  4. It would be nice to be able to do simple arithmetic with the values on the stack.
  5. It would be nice to be able to manipulate values on the stack.
  6. It might be nice to convert to number system bases other than decimal and hex.
  7. Multiplication and Division would be useful. (It turns out Division with very large divisors was a bear.)
  8. It should be able to send the output to a file or the printer.
  9. It would be nice to repeat a sequence of operations a given number of times.
  10. It is now getting complicated enough that a Help Screen would be nice.
  11. FORTH has a second stack (they call it the "Return Stack") which is nice to park values in. Enter the "Alternate Stack."
  12. With multiple precision Division available Square Root is not very difficult.
  13. It would be nice to be able to assign a series of operations to a single key; sort of a macro capability.
  14. An acquaintance put Factorials in an arithmetic package he did, so I added Factorials.
  15. A practical application of Factorials is to figure out the number of permutations; but with permutations why not add combinations as well.
  16. Powers are nice for evaluating the number of combinations. I gave out several copies of this version on Sat 9/23/1995 at the SVSC Forth meeting.
  17. Changed name from DH (Decimal to HEX) to IA (Integer Arithmetic).
  18. Allow "dot input" number base to be changed from 16 to anything less than 256; but input characters only available from 0-9,then A-Z.
  19. Put in "Decimal Coded Digits" to allow input digits grater than Z
  20. Moved help screen to under hardware stack freeing up 1214 bytes for main user stack. Also, made create output string in a separate segment, allowing almost a full 64K segment long output.
  21. Made .{ and .} so could capture and move the entire stack to the alternate stack and then later copy or move it back.
  22. Put in facility to convert values to Intel Floating point format.

I dislike programs that must be "INSTALLed" and then: make private Subdirectory in the Root of your hard drive; modify your AUTOEXEC.BAT; and load megabytes of files to support programs and devices you have never heard of. One file programs are easy to move and use, which puts you in control of your computer; instead of making you victim of programmers who believe your computer should be dedicated to their software. I just noticed Windows has everything that I hate!

The "Flavor" of in IA comes from features I liked from Stack oriented HP calculators, and Forth. Single character operators is largely from APL. Minimal "Screen Fanfare" is from my belief that screen space is very valuable and should be dedicated to the user. Furthermore, whatever the user has on the screen may be valuable and should be preserved as long as possible. Lastly, I hate the intrinsic use of mice or Function keys. There use precludes running the program from a .BAT file and forever commits an operator to the task of running the program.


Supporting "Help"

You can get a terse reminder of the command line syntax using the DOS TYPE command. Yes, I know some people think you should not TYPE "Binary Files" but with IA.COM you will see something like the following:
D>type ia.com

        Integer-Arithmetic
        <i*file IA [ /userdef-file][ print-file]>o-file

 Copyright 26 February 2001.  LaFarr Stuart (408)946-8517  LaFarr@Stuart.org

D>
The first line more or less explains the programs' name. The middle line is the general syntax. "i*file" is an input file which IA can use instead of the keyboard for its input. "ud-file" is an optional file which can be assigned to the User Defined key. "print-file" is an optional file which can receive output that would otherwise go to the printer. "o-file" is a file which would receive what would normally go to the display screen. All of the files can be fully specified, that is; the drive, path, and extension may be specified.

If, from within IA, one uses the User Defined key: Reverse Tic, and has not specified a User Defined file (denoted by a leading slash) on the command line; then the third line above which contains the assembly date and my name and phone number is displayed.

If, from within IA, a ? occurs as the last character on a line then something akin to the following is displayed:

 Functions in the 26 February 2001 version of IA (Integer Arithmetic)
        . Dot input (Decimal)           $ Square Root, $Enter shows .
        , Start new value,at 0          ! Factorial, !Enter shows all
        & Duplicate Top                 | M-things, taken N at a time
        [ Copy 2nd to Top               ` User definable, see _` .`
        ' Delete Top                    @ Count of digits
        " Delete 2nd                    ; Continue to next Line
        ] Delete 3rd                    ( Start Looping
        > To Alternate Stack            ) End Looping
        < From Alternate Stack          = Display Top in Decimal
        ~ Increment Alternate Top       # = with blocked groups
        \ Decrement Top                 : Display Top in Hex
        + Add. Top+2nd=New              % 1.193 MHz Ticks since Midnight
        - Subtract. 2nd-Top=New         { Send Output to PRN/file
        * Multiply. Top*2nd=New         } Return Output to CRT
        / Divide. 2nd/Top=Rem,Quot      ? Help, or Output following
        ^ Power. 2nd^Top=New            _ Decimal Coded Digits (. Input)
>< <> Copy to/from alt. Stack.          .= .: Change Out/In number bases.
Horizontal output with _= _# or _:      _Enter. Kills stack display.
        .' Empty Alternate Stack        _) Loop Top Not Zero
        .- 2's Complement               .} Infinite Loop
        .< .> Double/Half shifts        .) Loop on Keyboard
        .. 80-bit Float of top          .; Wait, for Keyboard
        .@  Count of stack values       .# Block size and symbol for #

Description of IA Input

An important feature of any program is: How to get out of the program. In IA that is very simple: You just give it a line with nothing to do; in other words just press <Enter> with nothing on the line.

IA lets the user know it is ready for input by moving the cursor two spaces to the right. (This idea is from APL.) And its output always begins at the left edge of the screen. It is easy to look at a screen and see what was entered and what was resulting output.

IA has two input modes: Decimal and Hex. Input spaces are ignored. Each input line starts in decimal mode with a stack containing one value which is zero. As one enters digits the top value on the stack is multiplied by ten and the digit value added on for each digit. For example if one enters: 256 the stack starts out with the value zero when the 2 is processed the value zero is multiplied by ten and 2 added (in actuality IA is smart enough to not multiply by zero) when the 5 is processed the value 2 is multiplied (in binary) by ten and 5 is added (leaving the value 25 on the stack) when the 6 is processed the 25 is multiplied by ten and the 6 added. (Internally in IA all values on the stack are in binary; and all arithmetic is done in binary using bytes and 16-bit words. No 80386, or higher, 32-bit instructions are used; hence, IA will work on any IBM PC compatible computer that has 191k of available memory.)

When IA detects a CR, which denotes the end of the input line, IA displays the entire stack in the opposite mode that it was in when the CR was encountered. Thus, continuing the proceeding example, if the user enters 256 and then presses <Enter> IA will display the result in hexadecimal (100) on the following line.

IA goes into Hex input mode when a period . is encountered; any other operator returns the input mode to decimal. Thus if one inputs: .20 followed by <Enter> IA will display 32 on the following line. In hex mode (that means following a period) letters have the same value in either upper or lower case. The letters "A" through "F" have, as you would expect, the values: ten through fifteen; but, as you might not expect, the letters "G" through "Z" have values: sixteen through thirty-five. Thus if you input: .fag <Enter> IA will output on the following line the same value as if you input: .FB0 <Enter> which is 4016. (Latter we will explain how to get IA to display both the Decimal and Hex values.)

Hex input mode differs from decimal in that the value on the stack is logically multiplied by sixteen instead of ten, as each digit is processed; and, letters are allowed as digits. To emphasize how this works suppose the user inputs: 25.6 followed by <Enter>; the 25 is entered as a decimal value, then it is multiplied by sixteen and then six is added, resulting in: 406. (Incidentally, this is the number of ounces in 25 pounds 6 ounces.) This is all very logical IF you understand how input conversion works.

If you know how DOS, on the command line, handles the function keys: F1 through F5, and Insert and Delete as well as the Right and Left arrow keys; they work exactly the same in IA. You will find this very convenient, and worth learning, to save key strokes when re-entering a slightly modified line.


Stack Manipulating Operations.

The following descriptions follow the HELP-SCREEN order shown above.

The comma is used in IA to separate values. When IA encounters a comma it pushes a new value of zero on the stack. Thus if one inputs: 10,20 followed by <Enter> IA will print out: 14 then A on the next line. Notice that the value entered last is on the top of the stack and gets printed out first; making it highest on the screen. Also, notice that both values were printed in hex. (Because the mode was decimal when IA encountered the CR that ended the input line.) If you now pressed F3, to get the last line input, and added a period at the end; and press <Enter> IA would print out the values in decimal. (Because the terminal period switched the input mode hex.) Terminating an input line with a period is the usual way to force the values on the stack to be displayed in decimal.

The Ampersand, &, makes a duplicate copy of on the top value on the stack. Thus, if you input: 7& <Enter> you will see two lines of "7". If you understood what was said earlier about how input conversion works, you can probably predict what will happen if you input: 1&0&0&0 followed by <Enter>. Again if you follow the input with a period you will see the result in decimal. You might also try: .1&.0&.0&.0

The next four operators: [ ' " and ] respectively: Copy the 2nd to the top, Delete the top, Delete the second, and Delete the third. They are straight forward enough that we will let you think up examples and try them. However, I might point out that [[ performs the rather useful function of duplicating the top two values on the stack. The [ and ] characters were selected for the functions they perform mainly because: [] as a pair perform a frequently used function, specifically that of swapping the top two values on the stack. For efficiency when IA encounters a [ it checks to see if it is followed by ] and if it is then the swap is performed. (If the [ and ] are separated by a space each operation is done separately, and hence is less efficient.)

There is an alternate stack in IA and values can be moved to and from it using > and < respectively. Unlike the main stack which is displayed and emptied at the end of each input line, values stay on the alternate stack until they are explicitly removed or IA is terminated. It should be pointed out that the alternate stack actually has more room than the main stack. However, it is still good practice to not just willy-nilly leave junk on the alternate stack.

Logically from the definitions of > and < it would be meaningless to use >< or <> because the second operation would just undo the first. But, in IA we have added meaning to these "paired" operations: they perform a copy function instead of a move. More explicitly: when a > is encountered it copies the top value to the alternate stack and then checks to see if the next input character is a < and if it is IA does not delete the top value. Thus, technically >< is faster than just > and similarly for <> and < which copy and move from the alternate stack.

There is only one arithmetic operation that can be performed on the Alternate stack; it is ~ which simply increments the value on the alternate stack by one. This is sometimes useful to generate consecutive values.


Arithmetic Operations.

There are several arithmetic operations that work on the main stack in IA. The first one described is probably the weakest, it is \ which simply decrements the top value on the stack. It could be replaced with: ,1- (In the future \ may be used for some other function?)

Add, Subtract, Multiply, and Divide all replace the top two values on the stack with the result of the operation. There are two non-obvious details: First IA does not do signed arithmetic; therefore, if you try to subtract a larger number from a smaller IA will beep and display a cryptic message and leave zero on the top of the stack. Second, except for square roots, there is no truncation (or rounding) in IA. On division IA leaves both the Remainder and Quotient as separate values on the stack. If you don't want the Remainder use /" or if you just want the remainder use /'

With the power function: ^ there is a restriction that the top value must not be larger than 65535. This should not be too restrictive; even 3,65535^ is a very large number. (This would be done with approximately 30 multiplies not 65354; but even so, multiplying rather large numbers, could take a little time.)

IA requires two values on the stack for Square Roots. The top value on the stack specifies the number of decimal places to compute the square root of the value that is second on the stack. For Square Roots IA "fakes" a decimal facility. Because the Square Root logic "knows" how many decimal places the user has specified it is easy for IA to show a "decimal point" if the value is immediately printed. When the $ (Square Root operator) is immediately followed by a CR or = the value is output, in decimal, with a period properly inserted in the digit string.

If the $ is followed by anything other than a CR (or = a period, or a space) the decimal position is lost. IA works only with variable length unsigned integers. There is really no facility in IA to keep track of the decimal position.

A couple actual examples should help make this clear. If 2,10$ and <Enter> are input, IA will output the Square Root of 2 with ten digits following the decimal point. If 2,67$ and <Enter> were input there would be 67 digits following the decimal point. (To keep computing time from being excessive IA limits the number of decimal places requested to 8191; but be warned, on slower machines if you specify a thousand or more places the calculation will take a little time.)

The value output for square roots is truncated and hence will be small; however, the last digit is correct. This means if the last digit were any larger the value would be larger than the actual square root. (You can verify this by squaring the Square Root.)

On the HELP-SCREEN you will notice that the descriptions for $, ! and ? have something enclosed in parenthesis. This denotes that they behave differently when they occur as the last character on the line.

The Factorial of a positive number is the value obtained by multiplying that number and each integer less than it down to 1 together. (Thus 5! is 2 times 3 times 4 times 5, or 120.) IA evaluates this simply by multiplying all the integers together; so it is very easy for IA to output each of these values as it is generated. And that is exactly what happens when ! is immediately followed by the CR that ends the line; otherwise, IA simply multiplies the consecutive integers together.

An application of Factorials is calculating the number of ways things can be arranged. For example: the number of ways you could arrange the three letters: A B and C is 3! or six. (The six ways are: ABC, ACB, BAC, BCA, CAB, and CBA.) Or, the number of different ways the cards in a 52 card deck can be arranged is computed by inputting: 52!. and <Enter>. (To keep computing time down, and the size of the result manageable, IA limits factorials to 15871! which has 59,778 digits.)

IA has an operator | to calculate the number of combinations of M-things taken N-at a time. To help understand this consider the number of two digit numbers you could write using the ten digits 0 through 9. This would be 100; 00 through 99, and in IA you would compute this with: 10,2^. The number of possible 4 letter words using the 26 letters of the alphabet would be: 26,4~. In both of these examples we have allowed repetition. XTXZ would be a valid 4 letter word. But if we do not allow repetition the number would be reduced; in the case of two digit numbers there would only be 90 because the ten that use the same digit (00, 11, 22, etc.) would not be possible. Now if instead of writing numbers we were selecting committees of two people from a population of ten; then the order would not count, in other words: the committee made up of members 7 and 3 is the same as the committee 3 and 7. Hence there is only be 45 different committees of two people that can be selected from a population of ten. If you input: 10,2|. IA will print out: 45 and 90, the first is the number of combinations of ten items selected 2 at a time when ordering does not matter; the second is the number of combinations if there is ordering. As a final example, if you input: 52,13|. the first value is the number of different 13 card Bridge hands that are possible; the second is the number when the order in which the cards were received is significant.


Input/Output Related Functions

You may have a values and operations, that are too long to fit on one line. The continuation character ; allows input to extend to any number of lines. When IA encounters the ; it ignores what ever follows it and reads in the next line and processes the second line as though it began where the ; occurred.

IA has an elementary form of looping which is done with the ( and ). The number of times the sequence of characters between the parenthesis is repeated is specified by the top value on the stack when the ( is encountered. For example, a Goggle (which is 1 with one hundred zeros behind it) could be input and converted to hex with the following: 1,100(0) and <Enter>. Or if you wanted to print out the numbers from 1 to 20 try: 20,19(&\). (IA does not allow nesting of loops; although ` can be used in a loop even when there is looping in the string that defines the ` function.)

= # and : all are used to display the value of the top (without removing it). Equal displays the top in decimal. Colon (which sort of looks like a shortened equal) displays the top in hex. And, Pound sign (which looks like and equal with frills) displays the top in decimal in groups of 5 digits separated by a comma. A handy use of = is at the end of an input line to display the top value in both decimal and hex.

Because IA can be used to produce extremely large numbers, it is sometimes desirable to know how many digits is in the number. @ pushes a value which is the number of digits in the last decimal string processed by IA on the stack. Thus if you input: 777@. IA will output 3 then 777. Or if you input: 52!. <Enter> then on the next line @. <Enter> you will get the number of possible arrangements of a 52 card deck and the number of digits in this number.

So far, we have considered two number system bases: Decimal and Hex. As has been mentioned earlier all values in IA are kept and manipulated with 16-bit unsigned arithmetic. Hex is fundamental to IA, while decimal is a "convenience" conversion for input and output. For output "decimal" can be any base two through fifteen. When the top value on the stack is not zero .= operator changes the base for all "decimal" output. Furthermore, that base is used for all "decimal" output until it is explicitly changed again or IA is restarted.

When IA encounters .= and the value on the top is 2 through 15 it becomes the new output base. For illustrative purposes consider changing the output base to five. 5.=100= <Enter> will output the value one hundred in base 5 and hex. If on the next line we input: 2,20$ <Enter> we will see the Square Root of 2 in base 5 with twenty digits following the period. If we attempt to set the "decimal" output base to one or zero the value of ten is used; so we can get back to "normal decimal" output by simply entering just a ? or 1? or 10? on a line.

It should be pointed out that when the output base is greater than 10 the "digits" output that are greater than 9 are not letters but the ASCII characters that follow 9. Specifically: : ; < = > and ? in that order. (I have "fixed" this to use the letters A-F, but decided it is used so infrequently, and the program had to check for each digit; so I took the "fix" out. If you find this too distracting, I could be persuaded.)


Using a Printer or Output File

The results of calculations may need to be printed or saved in a file. In IA { redirects the output to the printer (PRN). Or, to an output file when an output file was specified when IA was started from DOS. Like changing the output base, the redirection stays in effect until you change it back.

} redirects the output back to the display screen. Thus, to send output to the printer/file simply put the generating code after { and before }

When the last thing on an input line puts the input mode in hex; but you want the result to be in hex (instead of decimal) you can terminate the line with } or a , and the stack will be displayed in hex. (When a , is the last character of an input line it does not start a new value of zero on the stack.)

There are times when you would like to output comments. When the top value on the stack is zero (like at the beginning of a line) the ? outputs everything following it; unless it is the last thing on the line, then the HELP-SCREEN is output.


Two Character Extended Functions

The seven-bit ASCII character set didn't have quite enough symbols. IA uses the character . and sometimes _ to modify whatever immediately follows it to denote a new function.

' normally deletes the top value, .' deletes the entire Alternate stack.

.- does a 2's complement of the top value on the stack. Because IA has to use a variable number of 16-bit words (depending on the size of the value) the .- may produce a shorter value than what you expected.

One bit shifts, which have the effect of doubling or halving a value are much more efficient than multiplying or dividing by two. Halving was needed (for square roots) so the user is given access to the facility with .> and .< which half and double respectively.

IA has virtually no conditional logic. But, when using .) to end a loop; the count that was used by the ( to mark the beginning of the loop is ignored, and IA loops if the top value is not zero. Ending a loop with _} is an infinite loop. _} probably has no value; but, it came for free.

.; causes IA to pause waiting for any keyboard response after it has read in a line. DEMO.IA is a sample file that can be used instead of the keyboard for input. Look and the files: DEMO.BAT and DEMO.IA to see examples of redirecting a file to IA for input; and the use of .; to stop so you can see the result of each input line.

IA uses the STDIN and STDOUT (Features of DOS) thus input and output redirection (sometimes called "Piping") can be used. With any program getting its input from STDIN, rather than the keyboard, there should be something in the STDIN file to terminate the program. (DOS does not return to the keyboard when STDIN is exhausted.) For IA an empty line, anywhere in the file; but typically at the end will terminate IA. (A Ctrl-Z or a NUL character also terminates IA.) A Ctrl-C or Ctrl-Break from the keyboard will always terminate IA; even when there is nothing in the STDIN file to get you out.


The User Defined Function

IA has a facility to assign many key strokes to the ` key. An example might be to produce a "rounded Quotient" on division. This could be done by adding half of the divisor onto the numerator before the divide then throwing the remainder away. Assuming we have the numerator then the divisor on the stack, the following should do the job: ><.>+</" what this does is: copies the divisor to the alternate stack, then it divides by 2 throwing away the remainder, then adds half of the divisor to the numerator, then retrieves the original divisor from the alternate stack, finally it does the divide and throws away the remainder. To put this into the ` key use .` immediately before the string you want into the ` key. The entire line should look like:
        .`><.>+</"
Now you can simply enter the numerator , denominator ` and you will see the result in hex unless you follow the ` with a . If you want to start IA with the ` key already defined, at the DOS prompt type:
        copy con rd
        ><.>+</"
        F6
The above should create the file RD (for Rounded Divide) and if you TYPE it, it should contain the desired string. Now if you run IA by entering at the DOS prompt:
        ia /rd
The ` key will replace the top two values on the stack with the rounded quotient. Try it! On the command line that invokes IA when the first character is a / IA knows the first line of that file should be used ad a definition for the User defined key. You can, and probably should, put a description of the function on following lines. If you want to use a print file also put that name after the User-define file name without any leading /.

Another example could be to just assign a string of digits to the ` key, although if you just want ` to provide a value it would be faster to just have it on the alternate stack.

If you just want to see what is "in" the ` key, you can use _`


If you have suggestions, comments or ideas e-mail me. I would like to hear from you.
My Home Page or Jump to TOP of this page.