Morgan - Numerical Methods (523161), страница 29
Текст из файла (страница 29)
That would have required long and awkward decimal additions, however, and would hardly have been worth the effort.The idea is to divide the input argument by successively smaller powers of 10,converting the quotient of every division to ASCII and writing it to a string. This is187NUMERICAL METHODSdone until the routine reaches the end of the table. To use the same table and keepthe arithmetic binary, take the integer portion of the binary part of the fixed-pointvariable to be converted and, beginning at the top of the table, compare each entryuntil you find one that’s less than the integer you’re trying to convert.
This is whereyou start. Successively subtract that entry from the integer, counting as you go untilyou get an underflow indicating you’ve gone too far. You then add the table entryback into the number and decrease the counter. This is called restoring division; itwas chosen over other forms because some of the divisors would be two words long.That would mean using a division routine that would take more time than the simplesubtraction here. The number of times the table entry could divide the input variableis forced to ASCII and written to the next location in the string.Tb-bndc is an example of how this might be done.tb_bndc: Algorithm1.Point to the fixed-point variable, the output ASCII string, and the topof the table. Clear the leading-zeros flag.2.Test the MSB of the fixed-point variable for sign.
If it's negative, setthe sign flag and two's-complement the fixed-point variable.3.Get the integer portion of the fixed-point variable. Compare the integerportion to that of the current table entry.If the integer is larger than the table entry, continue with step 5.If the integer is less than the table entry, check the leading-zeros flag.If it's nonzero, output a zero to the string and continue with step 4.If it's zero, continue with step 4.4.Increment the string pointer, increment the table pointer by the sizeof the data type, and compare the table pointer with the offset offractab, l0o.If the table pointer is greater than or equal to the offset of fractab,continue with step 3.If the table pointer is less than the offset of fractab, continue withstep 6.5.188Increment the leading-zeros flag, call step 10, and continue with stepINPUT, OUTPUT, AND CONVERSION4 upon return.6.If the leading-zeros flag is clear, write a zero to the string, incrementthe string pointer, issue a period, increment the string pointer again,and get the fractional portion of the fixed-point variable.7.Load the fractional portion into the DX:AX registers.7a.Compare the current table entry with DX:AX.If the MSW of the fractional portion is greater, continue with step 9.If the MSW of the fractional portion is less, continue with step 8.8.Write a zero to the string.8a.
Increment the string and table pointers and test for the end of the table.If it's the end, continue with step 11.If it's not the end, continue with step 7a.9.Call step 10 and continue with step 8a.10. Subtract the table entry from the remaining fraction, counting eachsubtraction. When an underflow occurs, add the table entry back in anddecrement the count. Convert the count to an ASCII character and writeit to the string. Return to the caller.11. Write a NULL to the next location in the string and exit.tb_bndc: Listing;; converts binary to ASCII decimaltb_bndcprocuses bx cx dx si disptr:word, fxptr:wordlocal1eading_zeros:bytemovsi, word ptr fxptrmovleadi, word ptr sptrbx, word ptr int tab;point to input fixed-point;argument;point to ASCII string;point into tablesubmovax,axbyte ptr leading_zeros, al;assume positivemovorjnsax, word ptr [si][6]ax,axpositive;test for sign189NUMERICAL METHODSmovbyte ptr [di],'-'incnotnotnotnegjcaddadcadcdiword ptr [si][6]word ptr [si][41word ptr [si] [2]word ptr [si][0]positiveword ptr [si] [2],1word ptr [si][4],0word ptr [si][6],0positive:movmovsubwalk_tab:cmpjajbcmpjaepushptr:cmpjemovdx, word ptr [si][6]ax, word ptr [si][4]cx, cxdx, word ptr [bx] [2]gotnumberpushptrax, word ptr [bx]gotnumberbyte ptr cl, leading_zeros;write hyphen to output;string;two's complement;get integer portion;find table entry smaller;than integer;entry smaller;integer smaller;have we written a number;yet?skip_zeroword ptr count : [di],'O';write a '0' to the stringdi;next charactercntnu:incskip_zero:incincincinccmpjaejmpbx;next table entrybxbxbxbx, offset word ptr frac_tab ;done with integers?handle-fraction;yes, do fractionsshort walk_tabgotnumber:subinccx, cxleading zeros190;shut off leading zeros bypassINPUT, OUTPUT, AND CONVERSIONcnvrt_int:calljmphandle_fraction:cmpjnemovincdo_frac:movincget_frac:movsubwalk_tabl:cmpjajbcmpjaepushptrl:movskip_zero1:incincincincinccmpjaejmpsmall_enuf:subsmall_enufl:calljmpnear ptr indexshort cntnu;calculate and write to stringbyte ptr leading_zeros,0do fracbyte ptr [di],'O'di;written anything yet?word ptr [di],'.'di;put decimal pointdx, word ptr [si][2]ax, word ptr [si][O]cx, cx;move fraction to registersdx, word ptr [bx] [2]small_enufpushptr1ax, word ptr [bx]small_enuf;find suitable table entrybyte ptr [di],'0';write '0'dibxbxbxbxbx, offset word ptr tab_endexitshort walk_tab1;next character;next entrycx, cxnear ptr indexshort skip_zero1;calculate and writeexit:incdi191NUMERICAL METHODSsubmovretcl,clbyte ptr [si],cl;put NULL at;end of stringcxax, word ptr [bx]dx, word ptr [bx] [2]indexcxax, word ptr [bx]dx, word ptr [bx][2]cl,'0'byte ptr [di],cl;count subtractionsindex:incsubsbbjncdecaddadcormovretntb_bndcFloating-Point;subtract until a carry;put it back;make it ascii;write to stringendpConversionsThis next group of conversion routines involves converting ASCII and fixedpoint to floating point and back again.
These are specialized routines, but you’llnotice that they employ many of the same techniques just covered, both table-drivenand computational.The conversions discussed in this section are ASCII to single-precision float,single-precision float to ASCII, fixed point to single-precision floating point, andsingle-precision floating point to fixed point.You can convert ASCII numbers to single-precision floating point by firstconverting from ASCII to a fixed-point value, normalizing that number, andcomputing the shifts for the exponent, or you can do the conversion in floating point.This section gives examples of both; the next routine uses floating point to do theconversion.ASCII to Single-Precision FloatSimply put, each ASCII character is converted to hex and used as a pointer to atable of extended-precision floating-point equivalents for the decimal digits 0through 10.
As each equivalent is retrieved, a floating point accumulator is multiplied by 10, and the equivalent is added, similar to the process described earlier forinteger conversion by multiplication.192INPUT, OUTPUT, AND CONVERSIONThe core of the conversion is simple. We need three things: a place to put ourresult flaccum, a flag indicating that we have passed a decimal point dpflag, and acounter for the number of decimal places encountered dpcntr.1.Clear flaccum and dpcntr.2. Multiply flaccum by 10.0.3.Fetch the next character.If it‘s a decimal point, set dpflag and continue with step 3.If dpflag is set, increment dpcntr.If it's a number, convert it to binary and use it as an index intoa table of extended floats to get its appropriate equivalent.4.Add the number retrieved from the table to flaccum.5.See if any digits remain to be converted.
If so, continue from step 2.6.If dpflag is set, divide flaccum by 10.0 dpcntr times.7.Exit with the result in flaccum.The routine atf performs the conversion described in the pseudocode. Itwill convert signed numbers complete with signed exponents.atf: Algorithm1.Clear the floating-point variable, point to the input ASCI1 string, clearlocal variables associated with the conversion, and set the digit counterto 8.2.Get a character from the string and check for a hyphen.If the character is a hyphen, complement numsin and get the nextcharacter.
Go to step 3.If not, see if the character is "+."If not, go to step 3.If so, get the next character and go to step 3.3.See if the next character is "."If so, test dp, the decimal-point flag.If it's negative, we have gone beyond the end; go to step 7.If not, invert dp, get the next character, and go to to step 4.If not, go to step 4.193NUMERICAL METHODS4.See if the character is an ASCII decimal digit.If it isn't, we may be done; go to step 5.If it is, multiply the floating-point accumulator by 10 to make room forthe new digit.Force the digit to binary.Multiply the result by eight to form a pointer into a table of extendedfloats.Add this new floating-point digit to the accumulator.Check dp_flag to determine whether we have passed a decimal point andshould be decrementing dp to count the fractional digits. If so,decrement dp.Decrement the digit counter, digits.Get the next character.Return to the beginning of step 3.5.Get the next character and force it to lowercase.Check to see whether it's an "e"; if not, go to step 7.Otherwise, get the next character and check it to see whether it's ahyphen.If so, complement expsin, the exponent sign, and go to step 6.Otherwise, check for a "+."If it's not a "+," go to step 6a.If it is, go to step 6.6.
Get the next character.6a. See if the character is a decimal digit.If not, go to step 7.Otherwise, multiply the exponent by 10 and save the result.Subtract 30H from the character to force it to binary and OR itwith the exponent.Continue with step 6.7.See if expsin is negative.If it is, subtract exponent from dp and leave the result in the CLregister.If not, add exponent to dp and leave the result in CL.8.194If the sign of the number, numsin, is negative, force the extended floatINPUT, OUTPUT, AND CONVERSIONto negative.If the sign of the number in CL is positive, go to step 10.Otherwise, two's-complement CL and go to step 9.9.Test CL for zero.If it's zero, go to step 11.If not, increment a loop counter.