2.7 Controlling the radix

If you are a programmer, you know how important this subject is to you. Sometimes, you want to print numbers in octal, binary or hex. 4tH can do that too. Let's take the previous program and alter it a bit:

     ." Enter a number: "               \ write prompt
     refill drop                   \ enter string
     bl word                       \ parse string
     number dup                    \ convert to a number
     (error) =                     \ test for valid number
     if                            \ if not valid
          ." You didn't enter a valid number!" drop cr
     else                          \ print if valid
          hex
          ." The number was: " . cr
     then

We added the word 'HEX' just before printing the number. Now the number will be printed in hexadecimal. 4tH has a number of words that can change the radix, like 'DECIMAL' and 'OCTAL'. They work in the same way as 'HEX'.

4tH always starts in decimal. After that you are responsible. Note that all radix control follows the flow of the program. If you call a self- defined word that alters the radix all subsequent conversion is done too in that radix:

     : .hex hex . ;                \ print a number in hex

     ." Enter a number: "               \ write prompt
     refill drop                   \ enter string
     bl word                       \ parse string
     number dup                    \ convert to a number
     (error) =                     \ test for valid number
     if                            \ if not valid
          ." You didn't enter a valid number!" drop cr
     else                          \ print if valid
          ." The number was: " .hex cr
     then

In this example not only that single number is printed in hex, but also all subsequent numbers will be printed in hex! A better version of the ".HEX" definition would be:

     : .hex hex . decimal ;

Since that one resets the radix back to decimal. Words like 'HEX' do not only control the output of a number, but the input of numbers is also affected:

     ." Enter a number: "               \ write prompt
     refill drop                   \ enter string
     bl word                       \ parse string
     hex                           \ convert hexadecimal
     number dup                    \ convert to a number
     (error) =                     \ test for valid number
     if                            \ if not valid
          ." You didn't enter a valid number!" drop cr
     else                          \ print if valid
          dup
          ." The number was: " decimal . ." decimal" cr
          ." The number was: " hex . ." hex" cr
     then

'NUMBER' will now also accept hexadecimal numbers. If the number is not a valid hexadecimal number, it will return '(ERROR)'. You probably know there is more to radix control than 'OCTAL', 'HEX' and 'DECIMAL'. No, we have not forgotten them. In fact, you can choose any radix between 2 and 36. This slightly modified program will only accept binary numbers:

     : binary 2 base ! ;

     ." Enter a number: "               \ write prompt
     refill drop                   \ enter string
     bl word                       \ parse string
     binary                        \ convert hexadecimal
     number dup                    \ convert to a number
     (error) =                     \ test for valid number
     if                            \ if not valid
          ." You didn't enter a valid number!" drop cr
     else                          \ print if valid
          dup                      \ both decimal and hex
          ." The number was: " decimal . ." decimal" cr
          ." The number was: " hex . ." hex" cr
     then

'BASE' is a predefined variable that enables you to select any radix between 2 and 36. This makes 4tH very flexible. However, this won't work:

     hex 02B decimal . cr

4tH will try to compile "02B", but since it isn't a word or a valid decimal number, it will fail. Words like 'HEX' and the 'BASE' variable work only at run-time, not at compile-time! Isn't there a way to compile non-decimal numbers?

Sure, there is, although it is not that flexible. There are four words that control the interpretation of numbers at compile-time:

  1. [BINARY]
  2. [OCTAL]
  3. [DECIMAL]
  4. [HEX]

They work fundamentally different than their run-time equivalents. First, they only work at compile-time. Second, they are interpreted sequentially and do not follow the flow of the program. Let's take a look at these two programs:

     [binary] 101 . cr
     [octal] 101 . cr
     [decimal] 101 . cr
     [hex] 101 . cr

This will print the decimal numbers "5", "65", "101" and "257", since each one of them is compiled with a specific radix.

     : binary 2 base ! ;
     binary 101 . cr
     octal 101 . cr
     decimal 101 . cr
     hex 101 . cr

Now the decimal number "101" is printed in four different radixes, since at compile-time the radix was set to decimal (which is the default). Now take a look at this program:

     : do_binary [binary] ;
     : do_decimal [decimal] ;
     do_binary 101 decimal . cr
     do_decimal 101 decimal . cr

The program will print "101" two times! Haven't we selected binary at compile-time? No, both '[BINARY]' and '[DECIMAL]' are interpreted sequentially!

When '[BINARY]' is encountered at the first time, it will set the radix at compile-time to binary. When '[DECIMAL]' is encountered in the second line, it will set the radix to decimal. When the third line it compiled, the radix is still set to decimal. If you want to make this program work, try this:

     [binary]
     101 decimal . cr
     [decimal]
     101 decimal . cr

When the first line is encountered, it sets the radix (at compile-time) to binary. So the number "101" at line two is compiled as a binary number. 'DECIMAL' will just be compiled. It will only influence the radix at run-time. The third line sets the radix at compile-time to decimal. So the number "101" at line four is compiled as a decimal number.

Since the run-time of 4tH starts up in decimal, both occurrences of 'DECIMAL' have little value. We can even eliminate 'DECIMAL' from the program altogether without affecting the result:

     [binary] 101 . cr
     [decimal] 101 . cr

Note that both the compile-time radix control words and the run-time radix control words stay in effect until they are superseded by others:

     [binary]                        \ compile-time binary
     101                             \ first binary number
     1011                            \ second binary number
     [decimal]                       \ compile-time decimal
     5                               \ decimal 5
     do                              \ set run-time radix
           i base !                  \ to loop-index
           dup . cr                  \ print number
     loop
     drop                            \ clean stack