'=========================================================================== ' Subject: CONVERSION BETWEEN BASES Date: 05-14-99 (11:49) ' Author: Judson McClendon Code: QB, QBasic, PDS ' Origin: comp.lang.basic.misc Packet: FAQS.ABC '=========================================================================== 'From: "Judson McClendon" 'Newsgroups: comp.lang.basic.misc 'Subject: Re: HELP WITH ASSIGNMENT!!!!! 'Date: Wed, 03 Feb 1999 11:05:00 GMT Clynton Nel wrote: >I have to write a program in Qbasic that will convert a decimal number to >it's binary equivalent. >Please help me cause I am really confused...... There is a simple underlying principle to all positional based notation systems, and once you get that, it is fairly straightforward to decode and convert numbers in any base. Starting with the units position, each position to the left is valued base times greater. For example, in base 10, the number 1234 is actually understood like this: 1234 = 1 * 10*10*10 = 1*1000 + 2 * 10+10 = 2* 100 + 3 * 10 = 3* 10 + 4 * 1 = 4* 1 Looking at it as powers of the base, the pattern is clearer: 1234 = 1 * 10^3 = 1*1000 + 2 * 10^2 = 2* 100 + 3 * 10^1 = 3* 10 + 4 * 10^0 = 4* 1 Any non zero real number 'n' to the 'zeroth' power (n^0) = 1, so the units position in any base is always valued at 1. The pattern is the same for every base. Consider 1234 base 8, octal: 1234 = 1 * 8^3 = 1*512 = 512 + 2 * 8^2 = 2* 64 = 128 + 3 * 8^1 = 3* 8 = 24 + 4 * 8^0 = 4* 1 = 4 ---- 668 decimal Now consider 1111 base 2, binary: 1111 = 1 * 2^3 = 1*8 = 8 + 1 * 2^2 = 1*4 = 4 + 1 * 2^1 = 1*2 = 2 + 1 * 2^0 = 1*1 = 1 -- 15 decimal Because each position to the left is exactly base times as large as the position to the right, we do not need a symbol = base. That value is represented by a 0 with a 1 to the left. For example, in base 10 we don't need a symbol with a value of 10, because we use a 0 with 1 in the position to the left: 10. The same is true for every base. In base 2 there is no symbol for 2, we use 10, in base 8 there is no symbol for 8, we use 10, in base 16 we have symbols for all the values 0 through 15, then we use 10 for the base size. In any base system, 10 is the way we write the 'base' number. Each position increases from 0 up to the value of base -1, then we carry. Base 2: 0 1 10 Base 3: 0 1 2 10 Base 4: 0 1 2 3 10 Base 5: 0 1 2 3 4 10 Base 8: 0 1 2 3 4 5 6 7 10 Base 10: 0 1 2 3 4 5 6 7 8 9 10 Base 16: 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 Base 20: 0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j 10 Because our decimal system has no numeric digit above 9, we borrow letters from the alphabet to represent the values > 9. Note that used in this way, the letters -do not- represent the alphabetic characters we normally use them for. They are simply familiar symbols used to represent single-digit values of 10 or more. This is much easier than having to learn a whole new set of unfamiliar symbols for bases > 10. The pattern above continues on into fractional values. Consider the number 1234.5678 in base 10, decimal: 1234.5678 = 1 * 10^3 = 1*1000 + 2 * 10^2 = 2* 100 + 3 * 10^1 = 3* 10 + 4 * 10^0 = 4* 1 + 5 * 10^-1 = 5* .1 + 6 * 10^-2 = 6* .01 + 7 * 10^-3 = 7* .001 + 8 * 10^-4 = 8* .0001 Or 1111.1111 in base 2, binary: 1111.1111 = 1 * 2^3 = 1* 8 = 8 + 1 * 2^2 = 1* 4 = 4 + 1 * 2^1 = 1* 2 = 2 + 1 * 2^0 = 1* 1 = 1 + 1 * 2^-1 = 1* 1/2 = .5 + 1 * 2^-2 = 1* 1/4 = .25 + 1 * 2^-3 = 1* 1/8 = .125 + 1 * 2^-4 = 1* 1/16 = .0625 ------- 15.9375 Note that the symbol '.' (or ',' for our European and UK friends), which we call a 'decimal point' in base 10 decimal, is called a 'binary point' in base 2 binary, a 'hexidecimal point' in base 16 hexidecimal and an 'octal point' in base 8 octal, etc. Any integer can be represented exactly in any base, but what about fractional values? Unfortunately, the answer is "no". Many values which can be represented exactly in one base result in an infinite series of repeating digits in other bases. For example, the decimal values .1 and .01 (and many others) cannot be exactly represented in binary. This has some unpleasant side effects. If you run this little BASIC program: FOR I = 0 TO 1 STEP .1 PRINT I; NEXT You will probably (not all BASICs use binary) get an output similar to this: 0 .1 .2 .3 .4 .5 .6 .7 .8000001 .9000001 Imagine your bank using math like that to calculate your bank balance. What happened is that .1 is rounded to the nearest binary fraction, which in this case is slightly greater than .1. The print function then rounds this back to decimal when printing. This rounding makes the result look okay for a while, until the cumulative error reaches the point when it rounds up or down to a different printable value for that precision. If we multiply imprecise rounded values, the error is even greater, and if we use them as powers, as in loan or statistical calculations, the error becomes literally 'exponential'. This is one reason why COBOL is, and will continue to be, so popular for business programming. COBOL supports scaled decimal math, thus avoiding this nasty little problem. The COBOL programmer still must be deal with normal roundoff errors, but COBOL's scaled decimal math avoids the binary/decimal roundoff issue entirely. Below is a program in BASIC which converts numbers from any base to any other base, where base = 2-36. The limit of 36 is because you need 'base' number of symbols to represent a number in a given base. There are 10 numeric digits plus 26 letters = 36 symbols. ' ************************************************** ' * * ' * BASECONV.BAS * ' * * ' * Convert Number from Any Base to Any Base * ' * * ' * Judson D. McClendon * ' * Sun Valley Systems * ' * 329 37th Court N.E. * ' * Birmingham, AL 35215 * ' * 205-853-8440 * ' * * ' ************************************************** ' CONST Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" DIM NbrLong AS LONG, NbrBase1 AS STRING, NbrBase2 AS STRING DIM Base1 AS LONG, Base2 AS LONG, P AS INTEGER, V AS INTEGER, EF AS INTEGER DO INPUT "Enter base1,base2 (2-36): ", Base1, Base2 LOOP WHILE (Base1 < 2 OR Base1 > 36 OR Base2 < 2 OR Base2 > 36) DO DO ' Input and validate NbrBase1 EF = 0 PRINT "Enter Number in Base"; Base1; INPUT "(0 to end): ", NbrBase1 NbrBase1 = UCASE$(LTRIM$(RTRIM$(NbrBase1))) FOR P = 1 TO LEN(NbrBase1) V = INSTR(Digits, MID$(NbrBase1, P, 1)) IF (V < 1 OR V > Base1) THEN PRINT "Digit "; MID$(NbrBase1, P, 1); " invalid" EF = 1 EXIT FOR END IF NEXT LOOP WHILE (EF = 1) IF (NbrBase1 = "0") THEN END END IF NbrLong = 0 ' Convert Base1 to Long FOR P = 1 TO LEN(NbrBase1) NbrLong = NbrLong * Base1 + (INSTR(Digits, MID$(NbrBase1, P, 1)) - 1) NEXT NbrBase2 = "" ' Convert Long to Base2 DO NbrBase2 = MID$(Digits, (NbrLong MOD Base2) + 1, 1) + NbrBase2 NbrLong = NbrLong \ Base2 LOOP WHILE (NbrLong) PRINT "Number in Base"; STR$(Base2); ": "; NbrBase2 PRINT LOOP END