ArtsAutosBooksBusinessEducationEntertainmentFamilyFashionFoodGamesGenderHealthHolidaysHomeHubPagesPersonal FinancePetsPoliticsReligionSportsTechnologyTravel

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

Comments

    0 of 8192 characters used
    Post Comment

    No comments yet.

    Click to Rate This Article