- HubPages»
- Technology»
- Computers & Software»
- Computer Science & Programming
QBasic Numeric Limits
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
- First bit represents sign. "0" means positive, "1" means negative.
- Next 8 bits is evaluated as unsigned number with value ranging from 0 to 255
- 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.
- For special exponent value 0 (zero) actual exponent is -126
- 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.
- 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.
- 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".
- 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
No comments yet.