Morgan - Numerical Methods (523161), страница 27
Текст из файла (страница 27)
Assume we need to convert 8cH to a decimalfraction. The converted digit is produced as the overflow from the data type, in thiscase a byte. We multiply 8cH by 0aH, again using binary arithmetic, to get 578H (thefive is the overflow). This conversion may actually occur between the low byte andhigh byte of a word register, such as the AX register in the 8086. We remove the firstdigit, 5, from the calculation and place it in an accumulator as the most significantdigit. Next, we multiply 78H by 0aH, for a result of 4b0H. Before placing this digitin the accumulator, we shift the accumulator four bits to make room for it.
Thisprocedure continues until the required precision is reached or until the initial binaryvalue is exhausted.Round with care and only if you must. There are two ways to round a number.One is to truncate the conversion at the desired precision plus one digit, n-k+1' wheren is a converted digit and k is positional notation. A one is then added to the leastsignificant digit plus one, n-k, if the least significant digit n-k+1, is greater than onehalf of n-k. This propagates any carries that might occur in the conversion. The othermethod involves rounding the fraction in the source base and then converting, butthis can lead to error if the original fraction cannot be represented exactly.To use this procedure, we must create certain registers or variables.
First, wecreate the working variable bfrac to hold the binary fraction to be converted. Becausemultiplication requires a result register as wide as the sum of the bits of themultiplicand and multiplier, we need a variable as wide as the original fraction plusfour bits. If the original fraction is a byte, as above, a word variable or register is morethan sufficient. Next, we create dfrac to accumulate the result starting with the most172INPUT, OUTPUT, AND CONVERSIONsignificant decimal digit (the one closest to the radix point).
This variable needs tobe as large as the desired precision.1. Clear dfrac and load bfrac with the binary fraction we’re converting.2. Check bfrac to see if it’s exhausted or if we’ve reached our desired precision.If either is true, we’re done.3. Multiply bfrac by the base to which we’re converting (in this case, 0aH).4.Take the upper byte of bfrac as the result of the conversion and place it indfrac as the next less significant digit. Zero the upper byte of bfrac.5. Continue from step 2.The following routine accepts a pointer to a 32-bit binary fraction and a pointerto a string.
The converted decimal numbers will be placed in that string as ASCIIcharacters.bfc_dc: Algorithm1.Point to the output string, load the binary fraction in DX:BX, set theloop counter to eight (the maximum length of the string), and initializethe string with a period.2. Check the binary fraction for zero.If it's zero, exit through step 3.If not, clear AX to receive the overflow. Multiply the binary fractionby 10, using AX for overflow. Coerce AX to ASCII and write it to thestring.
Decrement the loop counter.If the counter is zero, leave through step 3.Otherwise, clear the overflow variable and continue with step 2.3. Exit with the carry clear.bfc-dc: Listing; *****; bfc_dc - a conversion routine that converts a binary fraction; (doubleword) to decimal ASCII representation pointed to by the string173NUMERICAL METHODS;pointer decptr. Set for eight digits, but it could be longer.bfc dc proclocalsva:word, svb:word, svd:wordmovmovmovdi,word ptr decptrbx,word ptr fractiondx,word ptr fraction[2]movsubcx, 8ax,ax;digit countermovincbyte ptr [di], '.'di;to begin the ASCII fract ionax,dxax,bxwork doneax,ax;check for zero operand;check for zero operandshlrclrclmovmovmovbx,1dx,1ax,1word ptr svb,bxword ptr svd,dxword ptr sva,ax;multiply fraction by 10shlrclrclbx,1dx,1ax,1shlrclrclbx,1dx,1ax,1addadcadcbx,word ptr svbdx,word ptr svdax,word ptr svadecimal conversion:ororjzsub174uses bx cx dx si di bp, fraction:dword, decptr:word;point to ASCII output string;get fractional part;times 2 multiple;multiply by 10;the converted value is;placed in ALINPUT, OUTPUT, AND CONVERSIONormovincsubloopwork done:movclcretbfc_dc endpal,'0´byte ptr [di],aldiax,axdecimal conversion;this result is ASCIIized and;placed in a stringbyte ptr [di],al;end string with a nullFraction Conversion by DivisionLike conversion of integers by multiplication, this procedure is performed as apolynomial evaluation.
With this method, base A (10) is converted to base B (2) bysuccessively dividing of the accumulated value by base A using the arithmetic ofbase B. This is the reverse of the procedure we just discussed.For example, lets convert .66D to binary. We use a word variable to perform theconversion and place the decimal value into the upper byte, one digit at a time,starting with the least significant.
We then divide by the base from which we’reconverting. Starting with the least significant decimal digit, we divide 6.00H (theradix point defines the division between the upper and lower bytes) by 0aH to get.99H. This fraction is concatenated with the next most significant decimal digit,yielding 6.99H. We divide this number by 0aH, for a result of .a8H. Both divisionsin this example resulted in remainders; the first was less than one-half the LSB andcould be forgotten, but the second was more than one-half the LSB and could havebeen used for rounding.Create a fixed-point representation large enough to contain the fraction, with aninteger portion large enough to hold a decimal digit. In the previous example, a bytewas large enough to contain the result of the conversion (log10 256 is approximately2.4) with four bits for each decimal digit.
Based on that, the variable bfrac should beat least 12 bits wide. Next, a byte variable dfrac is necessary to hold the two decimaldigits. Finally, a counter (dcntr) is set to the number of decimal digits to be converted.175NUMERICAL METHODS1.Clear bfrac and load dcntr with the number of digits to be converted.2. Check to see that dcntr is not yet zero and that there are digits yet to convert.If not, the conversion is done.3.Shift the least significant digit of dfrac into the position of the leastsignificant integer in the fixed-point fraction bfrac.4.Divide bfrac by 0aH, clear the integer portion to zero, and continue with step 2.The following example takes a string of ASCII decimal characters and convertsthem to an equivalent binary fraction. An invisible radix point is assumed to existimmediately preceding the start of the string.Dfc_bn: Algorithm1.Find least significant ASCII BCD digit.
Point to the binary fractionvariable and clear it. Clear DX to act as the MSW of the dividend andset the loop counter to eight (the maximum number of characters toconvert).2.Put the MSW of the binary result variable in AX and the least significantASCII BCD digit in DL. Check to see if the latter is a decimal digit.If not, exit through step 6.If so, force it to binary. Decrement the string pointer and check thedividend (32-bit) for zero.If it's zero, go to step 3.Otherwise, divide DX:AX by 10.3.Put AX in the MSW of the binary result variable and get the LSW. CheckDX:AX for zero.If it's zero, go to step 4.Otherwise, divide DX:AX by 10.4.Put AX in the LSW of the binary result variable.
Clear DX for the nextconversion. Decrement the loop variable and check for zero.If it's zero, go to step 5.Otherwise,continue with step 2.5.Exit with the carry clear.6.Exit with the carry set.176INPUT, OUTPUT, AND CONVERSIONDfc-bn: Listing;*****; dfc_bn - A conversion routine that converts an ASCII decimal fraction;to binary representation. decptr points to the decimal string to be;converted. The conversion will produce a doubleword result. The;fraction is expected to be padded to the right if it does not fill eight;digits.dfc_bn procuses bx cx dx si di, decptr:word, fraction:wordpushfcldmovsubmovrepnedecdecdi, word ptr decptrax,axcx, 9scasbdidimovsi,dimovmovmovdi, word ptr fractionword ptr [di], axword ptr [di][2], ax;point of binary fractionmovcx, 8;maximum number of;characterssubdx, dxbinary_conversion:movax, word ptr [di][2]movdl, byte ptr [si]cmPjbcmpjadl, '0'oopsdl, '9'oopsxordl, '0';point to decimal string;find end of string;point to least significant;byte;get high word of result;variable;concatenate ASCII input;with binary fraction;check for decimal digit;if it gets past here,;it must be OK;deASCIIize177NUMERICAL METHODSdecsisubororjzdivno_div0:movbx,bxbx,dxbx,axno_div0itenmovsubororjzdivno_divl:movax,word ptr [di]bx,bxbx,dxbx,axno_div1itensubloopwork_done:subclcret;prevent a divide by zero;divide by 10word ptr [di][2],ax;prevent a divide by zeroword ptr [di],axdx,dxbinary-conversion;loop will terminate;automaticallyax,ax;no carry =success!oops:movstcretdfc_bn endpax,-1;bad characterAs you may have noticed from the fractional conversion techniques, truncatingor rounding your results may introduce errors.
You can, however, continue theconversion as long as you like. Given a third argument representing allowable error,you could write an algorithm that would produce the exact number of digits requiredto represent your fraction to within that error margin. This facility may or may notbe necessary in your application.178INPUT, OUTPUT, AND CONVERSIONTable-Driven ConversionsTables are often used to convert from one type to another because they often offerbetter speed and code size over computational methods. This chapter covers thesimpler lookup table conversions used to move between bases and formats, such asASCII to binary.