# QBasic Numeric Limits

Updated on April 7, 2012

Following information is taken from the online help that comes bundled with QBasic interpreter. I am reproducing here so that I can direct a reader to it from any future articles that I may write on the topic of numeric computations in computer. I am also reproducing a QBasic program which let you print the bit patterns that arise in the QBasic type SINGLE. This is the format for representing 32-bit single-precision values. And also this program lets you enter component parts of single-precision values in bits. You can see the effect of various bit patterns on the value of single-precision number. For QBasic types meant for representing whole number the internal representation is quite straightforward. These QBasic types are: INTEGER and LONG, which are respectively 16-bits and 32-bits whole number representation system. The internal representation for these types are famous 2's complement format. Those readers not familiar with the 2's complement format should search internet for more information. In future I intend to write an article describing 2's complement and other formats. Keep a watch on my articles on this website. You can reach my articles at this website by clicking on this link.

Since INTEGER and LONG types are straightforward I concentrate on floating point formats. There are 2 in QBasic: SINGLE and DOUBLE. I use this program to print bit patterns that represent the extreme values in the 32-bit single-precision format. Then I discuss these bit patterns in light of IEEE standard. There are some tidbits of information about IEEE format of floating point numbers that may interest some readers of this article. Reader can undertake similar exercise for 64-bit double-precision floating point numbers for which QBasic provides the type DOUBLE. I shall be writing a shorter article where I shall be providing a QBasic program which will provide similar interface to user for entering and viewing double-precision values both in raw data entry format as well as bits entry format. Keep a watch on my articles on this website. You can reach my articles at this website by clicking on this link.

## QBasic Numeric Limits

.

```|-------------------------------------------------------------|
| TABLE                                                       |
|                                                             |
| QBasic Numeric Limits (from the online help                 |
| that comes bundled with QBasic interpreter                  |
|-------------------------------------------------------------|
|            Maximum                  Minimum                 |
|            -----------------------  ----------------------- |
| Integers                                                    |
|   INTEGER  32,767                   -32,768                 |
|   LONG     2,147,483,647            -2,147,483,648          |
|=============================================================|
| Floating point numbers:                                     |
|-------------------------------------------------------------|
| SINGLE:                                                     |
|   +ve      3.402823E+38             2.802597E-45            |
|   -ve      -2.802597E-45            -3.402823E+38           |
| DOUBLE:                                                     |
|   +ve      1.79769313486231D+308    4.940656458412465D-324  |
|   -ve      -4.940656458412465D-324  -1.79769313486231D+308  |
|-------------------------------------------------------------|```

.

## The SINGLE.BAS program

First of all let me say that I am providing this program "as is". I am making no claim that it is free from faults. To use this program you need a working QBasic interpreter. Copy the entire program into a Notepad file and save it as SINGLE.BAS. To run this program start QBasic interpreter and open SINGLE.BAS and run it by pressing F5 function key. After the program I am showing some demo runs of the program for floating point values. If you want to quickly go to the demo section just find the section in this article titled "Example Runs".

```DIM SHARED ErrorCode AS INTEGER

OPEN "SINGLE.TXT" FOR OUTPUT AS #1
CLOSE #1
DO
CLS
PRINT "1. Enter a number"
PRINT
PRINT "2. Enter a bit pattern"
PRINT
PRINT "X. To exit"
PRINT
INPUT option\$
option\$ = UCASE\$(LTRIM\$(RTRIM\$(option\$)))
IF option\$ = "X" THEN END
IF option\$ = "1" THEN singleProcess
IF option\$ = "2" THEN singleBitProcess
LOOP

handler:
ErrorCode = ERR
RESUME NEXT

FUNCTION Binary\$ (a AS INTEGER)
DIM s AS STRING

IF a < 16! THEN
s = HEX\$(a)
Binary\$ = "0000 " + halfByte\$(s)
ELSE
s = HEX\$(a)
Binary\$ = halfByte\$(LEFT\$(s, 1)) + halfByte\$(RIGHT\$(s, 1))
END IF

END FUNCTION

SUB calculateUnsigned (s AS STRING, u AS INTEGER, NOB AS INTEGER, RC AS INTEGER)
RC = 0
s = removeSpaces\$(s)
IF LEFT\$(s, 2) = "0X" THEN 'isHex
u = 0
s = RIGHT\$(s, LEN(s) - 2)
FOR i = 1 TO LEN(s)
SELECT CASE MID\$(s, i, 1)
CASE "0"
u = u * 16
CASE "1"
u = u * 16 + 1
CASE "2"
u = u * 16 + 2
CASE "3"
u = u * 16 + 3
CASE "4"
u = u * 16 + 4
CASE "5"
u = u * 16 + 5
CASE "6"
u = u * 16 + 6
CASE "7"
u = u * 16 + 7
CASE "8"
u = u * 16 + 8
CASE "9"
u = u * 16 + 9
CASE "A"
u = u * 16 + 10
CASE "B"
u = u * 16 + 11
CASE "C"
u = u * 16 + 12
CASE "D"
u = u * 16 + 13
CASE "E"
u = u * 16 + 14
CASE "F"
u = u * 16 + 15
CASE ELSE
RC = 1
EXIT SUB'not isHex
END SELECT
NEXT i
ELSE 'assumed isBits
u = 0
FOR i = 1 TO LEN(s)
IF MID\$(s, i, 1) = "1" THEN
u = u * 2 + 1
ELSEIF MID\$(s, i, 1) = "0" THEN
u = u * 2
ELSE
RC = 2
EXIT SUB'not isBits
END IF
NEXT i
END IF
IF u > (2 ^ NOB - 1) THEN
RC = 3
END IF
END SUB

FUNCTION halfByte\$ (a AS STRING)
SELECT CASE a
CASE "0"
halfByte\$ = "0000 "
CASE "1"
halfByte\$ = "0001 "
CASE "2"
halfByte\$ = "0010 "
CASE "3"
halfByte\$ = "0011 "
CASE "4"
halfByte\$ = "0100 "
CASE "5"
halfByte\$ = "0101 "
CASE "6"
halfByte\$ = "0110 "
CASE "7"
halfByte\$ = "0111 "
CASE "8"
halfByte\$ = "1000 "
CASE "9"
halfByte\$ = "1001 "
CASE "A"
halfByte\$ = "1010 "
CASE "B"
halfByte\$ = "1011 "
CASE "C"
halfByte\$ = "1100 "
CASE "D"
halfByte\$ = "1101 "
CASE "E"
halfByte\$ = "1110 "
CASE "F"
halfByte\$ = "1111 "
END SELECT
END FUNCTION

SUB Investigate (numberStr AS STRING)

DIM OutputStr AS STRING
DIM ascii AS INTEGER

PRINT #1, "Now we look at individual bytes that make"
PRINT #1, "up the internal representation of number"
PRINT #1,

OutputStr = ""
FOR i = 1 TO LEN(numberStr)
ascii = ASC(MID\$(numberStr, i, 1))
OutputStr = Binary\$(ascii) + " " + OutputStr
NEXT i
DO
PRINT #1, LEFT\$(OutputStr, 44)
OutputStr = LTRIM\$(MID\$(OutputStr, 45))
LOOP UNTIL OutputStr = ""

END SUB

SUB modifyByte (numberStr AS STRING, byteNumber AS INTEGER)
DIM ascii AS INTEGER
DIM inValue AS STRING
DIM OutputStr AS STRING
DIM unsignedOutValue AS INTEGER
DIM returnCode AS INTEGER
DIM NOBits AS INTEGER
DIM msb AS INTEGER
DO
CLS
PRINT
OutputStr = ""
FOR i = 1 TO LEN(numberStr)
ascii = ASC(MID\$(numberStr, i, 1))
OutputStr = Binary\$(ascii) + " " + OutputStr
NEXT i
IF byteNumber = 3 THEN
REM 7 bits
PRINT "The bits being edited are: "; MID\$(OutputStr, 13, 10)
PRINT
PRINT "To change bits enter new 7 bits"
PRINT
PRINT "You can either enter bits or in hex"
PRINT "notation. Like in this example: you"
PRINT "can enter (7 bits) 010 0101 or you"
PRINT "can enter: 0x25. If you enter more"
PRINT "than 7 bits, extra most significant"
PRINT "bits must be zeroes"
PRINT
ELSE
PRINT "The byte being edited is: "; MID\$(OutputStr, 11 * (LEN(numberStr) - byteNumber) + 1, 11)
PRINT
PRINT "To change byte enter new 8 bits"
PRINT
PRINT "You can either enter bits or in hex"
PRINT "notation. Like in this example: you"
PRINT "can enter 1010 0100 or 10100100 or"
PRINT "you can enter: 0xa4. If you enter"
PRINT "more than 8 bits, extra most"
PRINT "significant bits must be zeroes"
PRINT
END IF
PRINT "     OR"
PRINT
PRINT "Enter P to go back to previous menu"
PRINT "Enter X to end program"
INPUT inValue
inValue = UCASE\$(RTRIM\$(LTRIM\$(inValue)))
IF inValue = "X" THEN
PRINT "Thank you for using program"
END
ELSEIF inValue = "P" THEN
EXIT SUB
END IF
IF inValue = "" THEN
PRINT "You need to enter 0's and 1' or enter in hex notation"
PRINT "You probably did not enter anything"
PRINT "Please try again ... press a key to continue"
WaitForKeyPress
ELSE 'possibly valid value
IF byteNumber = 3 THEN
calculateUnsigned inValue, unsignedOutValue, 7, returnCode
ELSE
calculateUnsigned inValue, unsignedOutValue, 8, returnCode
END IF
SELECT CASE returnCode
CASE 0
IF byteNumber = 3 THEN
ascii = ASC(MID\$(numberStr, byteNumber, 1))
msb = ascii \ 128
MID\$(numberStr, byteNumber, 1) = CHR\$(msb * 128 + unsignedOutValue)
ELSE
MID\$(numberStr, byteNumber, 1) = CHR\$(unsignedOutValue)
END IF
EXIT SUB
CASE 1
PRINT "Invalid hex character enterd"
PRINT "hex character can be: 0-9, and A-F"
CASE 2
PRINT "Invalid bit character enterd"
PRINT "bit character can be: 0 or 1"
CASE 3
IF byteNumber = 3 THEN
PRINT "Number bigger than 7 bits"
ELSE
PRINT "Number bigger than 8 bits"
END IF
END SELECT
PRINT "Please try again ... Press a key"
WaitForKeyPress
END IF
ascii = ASC(RIGHT\$(numberStr, 1))
LOOP

END SUB

SUB modifyExponent (numberStr AS STRING)
DIM ascii AS INTEGER
DIM inValue AS STRING
DIM OutputStr AS STRING
DIM unsignedOutValue AS INTEGER
DIM returnCode AS INTEGER
DIM NOBits AS INTEGER
DIM tempLongStr AS STRING
DIM tempLong AS LONG
DIM tempRemainingBits AS LONG
DIM tempExponent AS LONG
DIM tempSign AS LONG
DO
CLS
PRINT
OutputStr = ""
FOR i = 1 TO LEN(numberStr)
ascii = ASC(MID\$(numberStr, i, 1))
OutputStr = Binary\$(ascii) + " " + OutputStr
NEXT i
PRINT "Exponent bits are: "; MID\$(OutputStr, 2, 11)
PRINT
tempLongStr = STRING\$(4, 0)
MID\$(tempLongStr, 1, 2) = MID\$(numberStr, LEN(numberStr) - 1, 2)
tempLong = CVL(tempLongStr)
tempLong = tempLong \ 128
tempLong = tempLong MOD 256
PRINT "(Biased) Exponent Value: "; tempLong
PRINT
PRINT "Bias: "; 127
PRINT
PRINT "Actual Exponent Value: ";
IF tempLong = 0 THEN
PRINT 126
ELSE
PRINT tempLong - 127
END IF
PRINT
PRINT "To change exponent enter new 8 bits"
PRINT
PRINT "You can either enter bits or in hex"
PRINT "notation. Like in this example: you"
PRINT "can enter 1010 0100 or 10100100 or"
PRINT "you can enter: 0xa4. If you enter"
PRINT "more than 8 bits, extra most"
PRINT "significant bits must be zeroes"
PRINT
PRINT "     OR"
PRINT
PRINT "Enter P to go back to previous menu"
PRINT "Enter X to end program"
INPUT inValue
inValue = UCASE\$(RTRIM\$(LTRIM\$(inValue)))
IF inValue = "X" THEN
PRINT "Thank you for using program"
END
ELSEIF inValue = "P" THEN
EXIT SUB
END IF
IF inValue = "" THEN
PRINT "You need to enter 0's and 1' or enter in hex notation"
PRINT "You probably did not enter anything"
PRINT "Please try again ... press a key to continue"
WaitForKeyPress
ELSE
calculateUnsigned inValue, unsignedOutValue, 8, returnCode
SELECT CASE returnCode
CASE 0
REM plugin entered 8 bits into numberStr at bit positions=30-23
REM analyze 2 MSBytes into sign, exponent, and remaining bits
tempLongStr = STRING\$(4, 0)
MID\$(tempLongStr, 1, 2) = MID\$(numberStr, LEN(numberStr) - 1, 2)
tempLong = CVL(tempLongStr)
tempRemainingBits = tempLong MOD 128
tempLong = tempLong \ 128
tempExponent = tempLong MOD 256
tempSign = tempLong \ 256
REM rebuild 2 MSBytes using now the new value for exponent
tempLong = tempSign * 256
tempLong = tempLong + unsignedOutValue
tempLong = tempLong * 128
tempLong = tempLong + tempRemainingBits
tempLongStr = MKL\$(tempLong)
MID\$(numberStr, LEN(numberStr) - 1, 2) = MID\$(tempLongStr, 1, 2)
EXIT SUB
CASE 1
PRINT "Invalid hex character enterd"
PRINT "hex character can be: 0-9, and A-F"
CASE 2
PRINT "Invalid bit character enterd"
PRINT "bit character can be: 0 or 1"
CASE 3
PRINT "Number bigger than 8 bits"
END SELECT
PRINT "Please try again ... Press a key"
WaitForKeyPress
END IF
ascii = ASC(RIGHT\$(numberStr, 1))
LOOP

END SUB

SUB modifySign (numberStr AS STRING)
DIM ascii AS INTEGER
DIM tempSign AS INTEGER
DIM tempRemainingBits AS INTEGER
DIM inValue AS STRING

DO
CLS
PRINT "Current Sign is: ";
IF ASC(RIGHT\$(numberStr, 1)) < 128 THEN
CurrentSign = 0
ELSE
CurrentSign = 1
END IF
PRINT CurrentSign
PRINT "To change sign bit enter 0 or 1"
PRINT
PRINT "     OR"
PRINT
PRINT "Enter P to go back to previous menu"
PRINT "Enter X to end program"
INPUT inValue
inValue = UCASE\$(RTRIM\$(LTRIM\$(inValue)))
IF inValue = "X" THEN
PRINT "Thank you for using program"
END
ELSEIF inValue = "P" THEN
EXIT SUB
END IF
IF NOT (inValue = "0" OR inValue = "1") THEN
PRINT "You entered neither 0 nor 1"
PRINT "Please try again ... press a key to continue"
WaitForKeyPress
ELSE
ascii = ASC(RIGHT\$(numberStr, 1))
tempSign = ascii \ 128
tempRemainingBits = ascii MOD 128
IF inValue = "0" THEN
ascii = tempRemainingBits
ELSEIF inValue = "1" THEN
ascii = tempRemainingBits + 128
END IF
MID\$(numberStr, LEN(numberStr), 1) = CHR\$(ascii)
EXIT SUB
END IF
LOOP
END SUB

SUB PrintReport (numberStr AS STRING)
DIM OutputStr AS STRING
DIM ascii AS INTEGER
DIM tempLongStr AS STRING
DIM tempLong AS LONG

OPEN "SINGLE.TXT" FOR APPEND AS #1
PRINT #1, "Value of single precision number: "; CVS(numberStr)
PRINT #1,
IF ASC(RIGHT\$(numberStr, 1)) < 128 THEN
PRINT #1, "Sign (Bit 31) = 0 ... Positive"
ELSE
PRINT #1, "Sign (Bit 31) = 1 ... Negative"
END IF
PRINT #1,
PRINT #1, "Remaining bits:"
PRINT #1,
OutputStr = ""
FOR i = 1 TO LEN(numberStr)
ascii = ASC(MID\$(numberStr, i, 1))
OutputStr = Binary\$(ascii) + " " + OutputStr
NEXT i
DO
PRINT #1, LEFT\$(OutputStr, 44)
OutputStr = LTRIM\$(MID\$(OutputStr, 45))
LOOP UNTIL OutputStr = ""
FOR i = 1 TO LEN(numberStr)
ascii = ASC(MID\$(numberStr, i, 1))
OutputStr = Binary\$(ascii) + " " + OutputStr
NEXT i
PRINT #1,
PRINT #1, "(Exponent Bit 30-23) "; MID\$(OutputStr, 2, 11)
PRINT #1,
tempLongStr = STRING\$(4, 0)
MID\$(tempLongStr, 1, 2) = MID\$(numberStr, LEN(numberStr) - 1, 2)
tempLong = CVL(tempLongStr)
tempLong = tempLong \ 128'shift 7 LS bits
tempLong = tempLong MOD 256'pick 8 LS bits
PRINT #1, "(Biased) Exponent Value: "; tempLong
PRINT #1,
PRINT #1, "Bias: "; 127
PRINT #1,
PRINT #1, "Actual Exponent Value: ";
IF tempLong = 0 THEN
PRINT #1, 126
ELSE
PRINT #1, tempLong - 127
END IF
PRINT #1,
OutputStr = LTRIM\$(MID\$(OutputStr, 12))
PRINT #1, "(Bit 22-16) "; MID\$(OutputStr, 2, 10)
PRINT #1,
OutputStr = LTRIM\$(MID\$(OutputStr, 12))
PRINT #1, "(Bit 15-8) "; LEFT\$(OutputStr, 11)
PRINT #1,
OutputStr = LTRIM\$(MID\$(OutputStr, 12))
PRINT #1, "(Bit 7-0) "; LEFT\$(OutputStr, 11)
PRINT #1,
PRINT
PRINT "Please find the bit pattern in file SINGLE.TXT"
PRINT "Thank you for using program"
END
END SUB

FUNCTION removeSpaces\$ (aString AS STRING)
DIM returnedString AS STRING
DIM aSpaceSeen AS INTEGER
returnedString = aString
aSpaceSeen = (1 = 1)
DO
spaceSeenAt = INSTR(returnedString, " ")
IF spaceSeenAt > 0 THEN
returnedString = LEFT\$(returnedString, spaceSeenAt - 1) + LTRIM\$(MID\$(returnedString, spaceSeenAt + 1))
ELSE
aSpaceSeen = (1 = 0)
END IF
LOOP WHILE aSpaceSeen
removeSpaces\$ = returnedString
END FUNCTION

SUB singleBitProcess

DIM singleValue AS INTEGER
DIM inValue AS STRING
DIM OutputStr AS STRING
DIM ascii AS INTEGER
DIM numberStr AS STRING
DIM tempLongStr AS STRING
DIM tempLong AS LONG
numberStr = STRING\$(4, 0)

DO
CLS
PRINT "Enter Bits of a Single Precision Floating Point Number"
PRINT
PRINT "Value of single precision number as of now is:"; CVS(numberStr)
PRINT
IF ASC(RIGHT\$(numberStr, 1)) < 128 THEN
PRINT "[1] (Bit 31) Sign = 0 ... Positive"
ELSE
PRINT "[1] (Bit 31) Sign = 1 ... Negative"
END IF
PRINT
OutputStr = ""
FOR i = 1 TO LEN(numberStr)
ascii = ASC(MID\$(numberStr, i, 1))
OutputStr = Binary\$(ascii) + " " + OutputStr
NEXT i
PRINT "[E] (Exponent Bit 30-23) "; MID\$(OutputStr, 2, 11)
PRINT
tempLongStr = STRING\$(4, 0)
MID\$(tempLongStr, 1, 2) = MID\$(numberStr, LEN(numberStr) - 1, 2)
tempLong = CVL(tempLongStr)
tempLong = tempLong \ 128'shift 7 LS bits
tempLong = tempLong MOD 256'pick 8 LS bits
PRINT "(Biased) Exponent Value: "; tempLong
PRINT
PRINT "Bias: "; 127
PRINT
PRINT "Actual Exponent Value: ";
IF tempLong = 0 THEN
PRINT 126
ELSE
PRINT tempLong - 127
END IF
PRINT
OutputStr = LTRIM\$(MID\$(OutputStr, 12))
PRINT "[2] (Bit 22-16) "; MID\$(OutputStr, 2, 10)
PRINT
OutputStr = LTRIM\$(MID\$(OutputStr, 12))
PRINT "[3] (Bit 15-8) "; LEFT\$(OutputStr, 11)
PRINT
OutputStr = LTRIM\$(MID\$(OutputStr, 12))
PRINT "[4] (Bit 7-0) "; LEFT\$(OutputStr, 11)
PRINT
PRINT "To modify select option in front of component"
PRINT
PRINT "     OR"
PRINT
PRINT "Enter P to go back to previous menu"
PRINT
PRINT "Enter Q to print report and end program"
PRINT
PRINT "Enter X to end program"
PRINT
INPUT inValue
inValue = UCASE\$(RTRIM\$(LTRIM\$(inValue)))
IF inValue = "X" THEN
PRINT "Thank you for using program"
END
ELSEIF inValue = "P" THEN
EXIT SUB
ELSEIF inValue = "Q" THEN
PrintReport numberStr
END IF
IF inValue = "1" THEN
modifySign numberStr
ELSEIF inValue = "2" THEN
modifyByte numberStr, 3
ELSEIF inValue = "3" THEN
modifyByte numberStr, 2
ELSEIF inValue = "4" THEN
modifyByte numberStr, 1
ELSEIF inValue = "E" THEN
modifyExponent numberStr
END IF
LOOP
END SUB

SUB singleProcess

DIM singleValue AS SINGLE
DIM inValue AS STRING
DIM numberStr AS STRING

DO
CLS
PRINT "Enter a Single Precision Floating Point Number"
PRINT "As per online help that comes with QBasic interpreter"
PRINT "QBasic type SINGLE, is either zero or takes values in"
PRINT "following ranges:"
PRINT
PRINT "  When positive: 2.802597E-45 to 3.402823E+38"
PRINT "  When negative: -3.402823E+38 to -2.802597E-45"
PRINT
PRINT "     OR"
PRINT
PRINT "Enter P to go back to previous menu"
PRINT
PRINT "Enter X to end program"
PRINT
INPUT inValue
inValue = UCASE\$(RTRIM\$(LTRIM\$(inValue)))
IF inValue = "X" THEN
PRINT "Thank you for using program"
END
ELSEIF inValue = "P" THEN
EXIT SUB
END IF

ErrorCode = 0
ON ERROR GOTO handler
singleValue = VAL(inValue)
ON ERROR GOTO 0

OPEN "SINGLE.TXT" FOR APPEND AS #1

IF ErrorCode = 0 THEN

PRINT #1, "You had input the single-precision number="; singleValue
PRINT #1, "You had input the string: "; inValue
PRINT #1,

numberStr = MKS\$(singleValue)

Investigate numberStr
'succesful data, end program
PRINT
PRINT "Please find the bit pattern in file SINGLE.TXT"
PRINT "Thank you for using program"
END

ELSE

PRINT #1, "You wanted to find bit pattern of a single-precision value"
PRINT #1,
PRINT "You wanted to find bit pattern of a single-precision value"
PRINT
PRINT #1, "You had input the number="; inValue
PRINT #1,
PRINT #1, "It should be between -3.402823E+38 and 3.402823E+38"
PRINT #1, "It is not in this range"
PRINT #1, "====="
PRINT "You had input the number="; inValue
PRINT
PRINT "It should be between -3.402823E+38 and 3.402823E+38"
PRINT "It is not in this range"
PRINT "Please try again ... press a key to continue"
END IF
CLOSE #1
WaitForKeyPress
LOOP

END SUB

SUB WaitForKeyPress
a\$ = ""
DO
a\$ = INKEY\$
LOOP UNTIL a\$ <> ""
END SUB```

.

## Example Runs

Absolutely first thing that we want to know about floating point types is how they look like at bit level. We first run the SINGLE.BAS program to enter extreme values we found in the online help of QBasic interpreter.

Program first displays following menu:

```1. Enter a number

2. Enter a bit pattern

X. To exit

?

```

First option allows you to enter specific numeric values and then the program will show the bit pattern of its internal representation. We first enter the extreme positive values for SINGLE and see how they look like internally. First we enter minimum positive single precision number given in the help. I have reproduced these extreme values above in the table above titled "QBasic Numeric Limits". We first enter menu option "1" and hit ENTER key to see following menu:

```Enter a Single Precision Floating Point Number
As per online help that comes with QBasic interpreter
QBasic type SINGLE, is either zero or takes values in
following ranges:

When positive: 2.802597E-45 to 3.402823E+38
When negative: -3.402823E+38 to -2.802597E-45

OR

Enter P to go back to previous menu

Enter X to end program

?```

We enter the value 2.802597E-45 and hit ENTER key and see a message: "Please find the bit pattern in file SINGLE.TXT" and program has ended.

```Enter a Single Precision Floating Point Number
As per online help that comes with QBasic interpreter
QBasic type SINGLE, is either zero or takes values in
following ranges:

When positive: 2.802597E-45 to 3.402823E+38
When negative: -3.402823E+38 to -2.802597E-45

OR

Enter P to go back to previous menu

Enter X to end program

? 2.802597E-45

Please find the bit pattern in file SINGLE.TXT
Thank you for using program

```

The file SINGLE.TXT that the program has created has following text:

```You had input the single-precision number= 2.802597E-45
You had input the string: 2.802597E-45

Now we look at individual bytes that make
up the internal representation of number

0000 0000  0000 0000  0000 0000  0000 0010

```

Program has printed the single precision value that was input as string. The reason for inputting the value first as string will become clear when we discuss the program. What program does is that it accepts value as string and then uses VAL function to convert the value input as string into actual value.

## The QBasic in-built function VAL

The QBasic function VAL accepts a string which contains a numeric value in human readable format and converts into internal format. If you input a numeric value which is too large or too small for the type then QBasic will not accept and force you to enter it again. For example try to enter value 99999 when input prompt appears in following program:

```INPUT x%

```

What you will see is following:

```? 99999

Overflow
Redo from start
?

```

To prevent such overflow error and to retain control of how the overflow condition is handled while inputting, we can instead do following:

```DECLARE SUB aSub ()
DIM SHARED ErrorCode AS INTEGER

CALL aSub

Handler:
ErrorCode = ERR
RESUME NEXT

SUB aSub

INPUT x\$
ON ERROR GOTO Handler
y = VAL(x)
ON ERROR GOTO 0

IF ErrorCode > 0 THEN

'process error condition

ELSE

'process no error happened

END IF

END SUB```

Use of SHARED option in DIM statement for ErrorCode variable ensures that value captured in error handler will be available to us inside a subroutine too.

With this explanation reader should now understand why I used string as a medium for data entry in this program. There is another reason which will become clear shortly (search "another reason" below on this page if you must read it now). To that end I now steer my discussion of program output.

Please notice that although QBasic help text gives 2.802597E-45 as the smallest single precision number that can be stored in a variable of type SINGLE, the bit pattern that was produced by the program in SINGLE.TXT output file is not absolute minimim. Absolute minimum would be:

```0000 0000  0000 0000  0000 0000  0000 0001
```

But what we see in SINGLE.TXT is following:

`0000 0000  0000 0000  0000 0000  0000 0010`

These values are what is called "subnormal" values. When the exponent bits are all zeroes then what is provided in significand is treated as binary digits after "binary point" with no "1" to the left of binary point. In case of "normalized" values a "1" is assumed. For example, we run the program again by entering 1.0E+0 and we will have our output file SINGLE.TXT as follows:

```You had input the single-precision number= 1
You had input the string: 1.0E+0

Now we look at individual bytes that make
up the internal representation of number

0011 1111  1000 0000  0000 0000  0000 0000

```

As you can see in this output, the sign bit is zero making this value a positive number. For 32-bit single precision numbers, 8 bits following the sign bit are for exponent stored as unsigned number whose value is Biased Exponent Value. That is a fixed bias value is added to actual exponent value. In case of single precision numbers the bias is 127. So to get the actual exponent value we need to subtract 127 from the unsigned value of exponent. As you can see in above output it is: "011 1111 1" which has value: 127. So actual exponent value is exactly zero. What follows exponent is significand bits:

`000 0000  0000 0000  0000 0000  `

All these bits are assumed to be after "binary point" which is the equivalent in binary world of what "decimal point" is in decimal world. Additionally when biased exponent value is NOT all zeroes a binary digit "1" is assumed to the left of binary point. So actual significand number is:

`1.000 0000  0000 0000  0000 0000  `

When biased exponent is all zeroes the assumed binary digit to left of binary point is "0". In other words the biased exponent value of all zeroes has special meaning; namely, that the fraction that significand represents is not a normalized binary fraction. The biased exponent value of all 1's aslo has a special meaning: it is used to represent plus and minus infinity and an invalid value calle "Not a Number". If you attempt to print such a number QBasic will simply print NaN.

After explaining difference between all zeroes in exponent and its opposite situation (at least one "1") we are now ready to return to the single precision value 2.802597E-45. As you can see, this value printed in the output in SINGLE.TXT file with biased exponent value of all zeroes. Therefore its significand is a fraction with "0" to the left of binary point:

```0.000 0000  0000 0000  0000 0010
```

Value of this fraction is: 2-22 so the value of this floating point number is: 2(0-127) * 2-22= 2-149. Using a calculator we find 1.40129846e-45. But the number printed by the SINGLE.BAS program is twice this number! Have we done something wrong? Answer is: Yes and No. As far as calculating the value of fraction is concerned YOU can try again and confirm my finding that its value indeed is: 2-22. It appears that when the exponent bits are all zeroes bias value used is not 127 but 126. And a justification for it also easy to see.

Let us build a number which will be smallest positive number with biased exponent is not all zeroes. Such a number would have minimum biased exponent which is NOT ALL ZEROES and minimum normalized significand. Such minimum biased exponent would be (000 0000 1)2. And also let us use minimum significand which is: ([1].000 0000 0000 0000 0000 0000)2. Please note that this significand as stored in a SINGLE type variable will have all 23 bits as zeroes. I have placed the assumed "1" in square brackets [ ... ] to emphasize that "1" is assumed. The value of this single precision number is: 2(1-127) * 1.0 = 1.17549435e-38. You can run SINGLE.BAS and confirm that this indeed shows significand as all zeroes and biased exponent as exactly (000 0000 1)2. This is smallest normalized number that can be represented as single precision value. Now let us assume we divide this number by 2. Ordinarily this could be accomplished by just decrementing the exponent by 1. But this is going to make it zero and therefore we must now shift the assumed "1" to right of binary point. Why? Because exponent bits all zeroes means: significand bit no longer have assumed "1" to the left of "binary point". That is what designers of IEEE 754 wanted. They wanted to use minimum exponent so with actual storage of all bits in significand. So no more assumed "1" to the left of binary point. This lets us have non-normalized fractions so that we can have much smaller numbers than normalized range would permit.

So, we now have a "0" to the left of binary point and "1" which was assumed before now has been shifted to the right of binary point. But this additional shift action must be compensated by adding 1 to it. Because shifting right means dividing significand by 2 and to compensate we add 1 to exponent. But that is going to make biased exponent 1 again! So in the special case of exponent bits all zeroes we must take the value of actual exponent as -126 (same as it would have been for minimum non-zero exponent). With this discovery we summarize single precision floating point values as follows:

## Definition of Single Precision Number in QBasic

1. First bit represents sign. "0" means positive, "1" means negative.
2. Next 8 bits is evaluated as unsigned number with value ranging from 0 to 255
3. For all exponent values except 0 (zero) and 255 the actual exponent is a biased value biased by 127. That is, actual exponent value is computed by subtracting 127 from unsigned value of 8 exponent bits.
4. For special exponent value 0 (zero) actual exponent is -126
5. For all exponent values except 0 (zero) and 255, remaining 23 bits represent a binary fraction with these 23 bits to the right of "binary point" and an assumed "1" to the left of binary point.
6. For special exponent value 0 (zero) remaining 23 bits represent a binary fraction with these 23 bits to the right of "binary point" and an assumed "0" to the left of binary point.
7. For special exponent value of 255 if the remaining 23 bits are all zeroes then the number represents infinity. It is plus infinity if sign bit is "0" and minus infinity if it is "1".
8. For special exponent value of 255 if the remaining 23 bits are not all zeroes then it is an invalid number (AKA "Not a Number"). Attempt to print a "Not a Number" will print NaN in QBasic.

We call our thinking through as discovery. Obviously there is no discovery. IEEE 754 existed before and we could have read it to find out this, but such thinking through is in the class of archeology. We find the language in standards document sometimes boring and we may miss important point. The thinking through makes us tread same paths which were traversed by original inventors and such re-invention of their wheels solidifies our understanding more strongly.

Similar definition for QBasic double precision numbers can be given. I will leave that to interested readers to work out from available documentation on IEEE 754-1985.

Interested readers should run SINGLE.BAS for 1.40129846e-45 and check what bit pattern it outputs in the output file SINGLE.TXT.

By picking up the entered value via a string we can see how many decimal digits we had entered and how many QBasic PRINT statement retains. For example, 1.40129846e-45 might be truncated by the PRINT statement to: 1.401298E-45. This is another reason why accepting input value via a string can be instructive. To illustrate this point instead of using 2.802597E-45 which the QBasic provides as minimum positive single-precision value, let us use calculator to calculate its its value. Unlike QBasic PRINT statement which truncates the number while printing, the Microsoft Windows calculator program does not do any truncation for this number. So let us calculate: 2(0-126) * 2-22= 2-148. Using the calculator we find this as: 2.8025969286496341418474591665798e-45. I ran SINGLE.BAS with this number and it created SINGLE.TXT out as follows:

```You had input the single-precision number= 2.802597E-45
You had input the string: 2.8025969286496341418474591665798E-45

Now we look at individual bytes that make
up the internal representation of number

0000 0000  0000 0000  0000 0000  0000 0010

```

## Reverse Operation

The SINGLE.BAS program can do reverse operation too. That is, a user can enter any bits whatsoever in the storage for a value and find out what is the value of number that is created by a specific bit pattern. We will illustrate this reverse operation now in next section: Example Runs for Bit Pattern.

## Example Runs for Bit Pattern

For illustrating the use of SINGLE.BAS program for accepting bit patterns we will use following bit pattern for a single precision number:

```0000 0000  0000 0000  0000 0000  0000 0001
```

First we start SINGLE.BAS program and enter option "2" which is the option for: "Enter a bit pattern". What we see is following menu:

```Enter Bits of a Single Precision Floating Point Number

Value of single precision number as of now is: 0

[1] (Bit 31) Sign = 0 ... Positive

[E] (Exponent Bit 30-23) 000 0000  0

(Biased) Exponent Value:  0

Bias:  127

Actual Exponent Value:  126

[2] (Bit 22-16) 000 0000

[3] (Bit 15-8) 0000 0000

[4] (Bit 7-0) 0000 0000

To modify select option in front of component

OR

Enter P to go back to previous menu

Enter Q to print report and end program

Enter X to end program

?
```

Please note that actual exponent is shown as -126 because in light of above discussion since exponent bits in this initial screen is all zeroes it should be -126. The program lets user enter any bits in any byte and it prints the value of number with latest change in bit pattern. All the calculation work for printing is done by QBasic PRINT statement. So we are nowhere using our knowledge of intricacy of how single precision internally works. We just enter bits and we see the resulting single precision value. We select option "4" because that is the byte we wish to modify. We see following screen:

```The byte being edited is: 0000 0000

To change byte enter new 8 bits

You can either enter bits or in hex
notation. Like in this example: you
can enter 1010 0100 or 10100100 or
you can enter: 0xa4. If you enter
more than 8 bits, extra most
significant bits must be zeroes

OR

Enter P to go back to previous menu
Enter X to end program
? 1```

We enter "1" and hit enter. We can enter up to 8 bits for this byte. We can either enter "00000001" or simply "1" or if we wish to enter in hex notation we can enter: "0x01". If we enter "0xAB" or "0XAB" then it will be taken as "10101011".

On entering "1" we are taken back to previous screen which now shows new bit pattern and new single precision number that has resulted because of this "edit".

```Enter Bits of a Single Precision Floating Point Number

Value of single precision number as of now is: 1.401298E-45

[1] (Bit 31) Sign = 0 ... Positive

[E] (Exponent Bit 30-23) 000 0000  0

(Biased) Exponent Value:  0

Bias:  127

Actual Exponent Value:  126

[2] (Bit 22-16) 000 0000

[3] (Bit 15-8) 0000 0000

[4] (Bit 7-0) 0000 0001

To modify select option in front of component

OR

Enter P to go back to previous menu

Enter Q to print report and end program

Enter X to end program

?

```

Most recent bit configuration can be output to the file SINGLE.TXT before ending the program by entering "Q" option on this screen:

```Value of single precision number:  1.401298E-45

Sign (Bit 31) = 0 ... Positive

Remaining bits:

0000 0000  0000 0000  0000 0000  0000 0001

(Exponent Bit 30-23) 000 0000  0

(Biased) Exponent Value:  0

Bias:  127

Actual Exponent Value:  126

(Bit 22-16) 000 0000

(Bit 15-8) 0000 0000

(Bit 7-0) 0000 0001```

0

2