📄 atof.s
字号:
/* @(#)atof.s 4.1 ULTRIX 7/3/90 */#include "DEFS.h"/************************************************************************ * * * Copyright (c) 1984, 1988 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * * Modification History * * Andy Gadsby, 27-Nov-86 * INTL Added code to allow change of radix character. * * Stephen Reilly, 14-May-84 * 003- Change the symbol MVAXI to GFLOAT to reflect the meaning of the * code * Stephen Reilly, 04-Apr-84 * 002- Change the symbol MicroVAX to MVAXI * * Stephen Reilly, 04-Oct-83: * 001 - Added code to handle gfloat conversions for MicroVax * ************************************************************************//* The range is a limit for the exponent of the converted number * SLR001*/#ifdef GFLOAT# define range 400#else# define range 100#endif/* * atof: convert ascii to floating * * C usage: * * double atof (s) * char *s; * * Register usage: * * r0-1: value being developed * r2: first section: pointer to the next character * second section: binary exponent * r3: flags * r4: first section: the current character * second section: scratch * r5: the decimal exponent * r6-7: scratch * * Flag definitions */ .set msign,0 # mantissa has negative sign .set esign,1 # exponent has negative sign .set decpt,2 # decimal point encountered .align 2# ifdef GFLOATtwo31: .word 0x4200 # slr001 2**31 in gfloat# elsetwo31: .word 0x5000 # 2 ** 31 or double# endif .word 0 # (=2147483648) .word 0 # in floating-point .word 0 # (so atof doesn't have to convert it) .globl __lc_radix # INTL international radix character /* * Entry point */ENTRY(atof) pushl r6 pushl r7/* * Initialization */ clrl r3 # All flags start out false movl 4(ap),r2 # Address the first character clrl r5 # Clear starting exponent/* * Skip leading white space */sk0: movzbl (r2)+,r4 # Fetch the next (first) character cmpb $' ,r4 # Is it blank? jeql sk0 # ...yes cmpb r4,$8 # 8 is lowest of white-space group jlss sk1 # Jump if char too low to be white space cmpb r4,$13 # 13 is highest of white-space group jleq sk0 # Jump if character is white spacesk1:/* * Check for a sign */ cmpb $'+,r4 # Positive sign? jeql cs1 # ... yes cmpb $'-,r4 # Negative sign? jneq cs2 # ... no bisb2 $1<msign,r3 # Indicate a negative mantissacs1: movzbl (r2)+,r4 # Skip the charactercs2:/* * Accumulate digits, keeping track of the exponent */ clrq r0 # Clear the accumulatorad0: cmpb r4,$'0 # Do we have a digit? jlss ad4 # ... no, too small cmpb r4,$'9 jgtr ad4 # ... no, too large/* * We got a digit. Accumulate it */ cmpl r1,$214748364 # Would this digit cause overflow? jgeq ad1 # ... yes/* * Multiply (r0,r1) by 10. This is done by developing * (r0,r1)*2 in (r6,r7), shifting (r0,r1) left three bits, * and adding the two quadwords. */ ashq $1,r0,r6 # (r6,r7)=(r0,r1)*2 ashq $3,r0,r0 # (r0,r1)=(r0,r1)*8 addl2 r6,r0 # Add low halves adwc r7,r1 # Add high halves/* * Add in the digit */ subl2 $'0,r4 # Get the digit value addl2 r4,r0 # Add it into the accumulator adwc $0,r1 # Possible carry into high half jbr ad2 # Join common code/* * Here when the digit won't fit in the accumulator */ad1: incl r5 # Ignore the digit, bump exponent/* * If we have seen a decimal point, decrease the exponent by 1 */ad2: jbc $decpt,r3,ad3 # Jump if decimal point not seen decl r5 # Decrease exponentad3:/* * Fetch the next character, back for more */ movzbl (r2)+,r4 # Fetch jbr ad0 # Try again/* * Not a digit. Could it be a decimal point? */ad4: cmpb r4, __lc_radix # INTL If it's not a decimal point, either it's jneq ad5 # the end of the number or the start of # the exponent. jbcs $decpt,r3,ad3 # If it IS a decimal point, we record that # we've seen one, and keep collecting # digits if it is the first one./* * Check for an exponent */ad5: clrl r6 # Initialize the exponent accumulator cmpb r4,$'e # We allow both lower case e jeql ex1 # ... and ... cmpb r4,$'E # upper-case E jneq ex7/* * Does the exponent have a sign? */ex1: movzbl (r2)+,r4 # Get next character cmpb r4,$'+ # Positive sign? jeql ex2 # ... yes ... cmpb r4,$'- # Negative sign? jneq ex3 # ... no ... bisb2 $1<esign,r3 # Indicate exponent is negativeex2: movzbl (r2)+,r4 # Grab the next character/* * Accumulate exponent digits in r6 */ex3: cmpb r4,$'0 # A digit is within the range jlss ex4 # '0' through cmpb r4,$'9 # '9', jgtr ex4 # inclusive. cmpl r6,$214748364 # Exponent outrageously large already? jgeq ex2 # ... yes moval (r6)[r6],r6 # r6 *= 5 movaw -'0(r4)[r6],r6 # r6 = r6 * 2 + r4 - '0' jbr ex2 # Go 'round againex4:/* * Now get the final exponent and force it within a reasonable * range so our scaling loops don't take forever for values * that will ultimately cause overflow or underflow anyway. * A tight check on over/underflow will be done by ldexp. */ jbc $esign,r3,ex5 # Jump if exponent not negative mnegl r6,r6 # If sign, negate exponentex5: addl2 r6,r5 # Add given exponent to calculated exponent cmpl r5,$-range # slr001 Absurdly small? jgtr ex6 # ... no movl $-range,r5 # slr001 ... yes, force within limitex6: cmpl r5,$range # slr001 Absurdly large? jlss ex7 # ... no movl $range,r5 # slr001 ... yes, force within boundsex7:/* * Our number has now been reduced to a mantissa and an exponent. * The mantissa is a 63-bit positive binary integer in r0,r1, * and the exponent is a signed power of 10 in r5. The msign * bit in r3 will be on if the mantissa should ultimately be * considered negative. * * We now have to convert it to a standard format floating point * number. This will be done by accumulating a binary exponent * in r2, as we progressively get r5 closer to zero. * * Don't bother scaling if the mantissa is zero */ movq r0,r0 # Mantissa zero? jeql exit # ... yes clrl r2 # Initialize binary exponent tstl r5 # Which way to scale? jleq sd0 # Scale down if decimal exponent <= 0/* * Scale up by "multiplying" r0,r1 by 10 as many times as necessary, * as follows: * * Step 1: Shift r0,r1 right as necessary to ensure that no * overflow can occur when multiplying. */su0: cmpl r1,$429496729 # Compare high word to (2**31)/5 jlss su1 # Jump out if guaranteed safe ashq $-1,r0,r0 # Else shift right one bit incl r2 # bump exponent to compensate jbr su0 # and go back to test again./* * Step 2: Multiply r0,r1 by 5, by appropriate shifting and * double-precision addition */su1: ashq $2,r0,r6 # (r6,r7) := (r0,r1) * 4 addl2 r6,r0 # Add low-order halves adwc r7,r1 # and high-order halves/* * Step 3: Increment the binary exponent to take care of the final * factor of 2, and go back if we still need to scale more. */ incl r2 # Increment the exponent sobgtr r5,su0 # and back for more (maybe) jbr cm0 # Merge to build final value/* * Scale down. We must "divide" r0,r1 by 10 as many times * as needed, as follows: * * Step 0: Right now, the condition codes reflect the state * of r5. If it's zero, we are done. */sd0: jeql cm0 # If finished, build final number/* * Step 1: Shift r0,r1 left until the high-order bit (not counting * the sign bit) is nonzero, so that the division will preserve * as much precision as possible. */ tstl r1 # Is the entire high-order half zero? jneq sd2 # ...no, go shift one bit at a time ashq $30,r0,r0 # ...yes, shift left 30, subl2 $30,r2 # decrement the exponent to compensate, # and now it's known to be safe to shift # at least once more.sd1: ashq $1,r0,r0 # Shift (r0,r1) left one, and decl r2 # decrement the exponent to compensatesd2: jbc $30,r1,sd1 # If the high-order bit is off, go shift/* * Step 2: Divide the high-order part of (r0,r1) by 5, * giving a quotient in r1 and a remainder in r7. */sd3: movl r1,r6 # Copy the high-order part clrl r7 # Zero-extend to 64 bits ediv $5,r6,r1,r7 # Divide (cannot overflow)/* * Step 3: Divide the low-order part of (r0,r1) by 5, * using the remainder from step 2 for rounding. * Note that the result of this computation is unsigned, * so we have to allow for the fact that an ordinary division * by 5 could overflow. We make allowance by dividing by 10, * multiplying the quotient by 2, and using the remainder * to adjust the modified quotient. */ addl3 $2,r0,r6 # Dividend is low part of (r0,r1) plus adwc $0,r7 # 2 for rounding plus # (2**32) * previous remainder ediv $10,r6,r0,r6 # r0 := quotient, r6 := remainder. addl2 r0,r0 # Make r0 result of dividing by 5 cmpl r6,$5 # If remainder is 5 or greater, jlss sd4 # increment the adjustted quotient. incl r0/* * Step 4: Increment the decimal exponent, decrement the binary * exponent (to make the division by 5 into a division by 10), * and back for another iteration. */sd4: decl r2 # Binary exponent aoblss $0,r5,sd2/* * We now have the following: * * r0: low-order half of a 64-bit integer * r1: high-order half of the same 64-bit integer * r2: a binary exponent * * Our final result is the integer represented by (r0,r1) * multiplied by 2 to the power contained in r2. * We will transform (r0,r1) into a floating-point value, * set the sign appropriately, and let ldexp do the * rest of the work. * * Step 1: if the high-order bit (excluding the sign) of * the high-order half (r1) is 1, then we have 63 bits of * fraction, too many to convert easily. However, we also * know we won't need them all, so we will just throw the * low-order bit away (and adjust the exponent appropriately). */cm0: jbc $30,r1,cm1 # jump if no adjustment needed ashq $-1,r0,r0 # lose the low-order bit incl r2 # increase the exponent to compensate/* * Step 2: split the 62-bit number in (r0,r1) into two * 31-bit positive quantities */cm1: ashq $1,r0,r0 # put the high-order bits in r1 # and a 0 in the bottom of r0 rotl $-1,r0,r0 # right-justify the bits in r0 # moving the 0 from the ashq # into the sign bit./* * Step 3: convert both halves to floating point */#ifdef GFLOAT cvtlg r0,r6 # slr001 low-order part in r6-r7 cvtlg r1,r0 # slr001 high-order part in r0-r1#else cvtld r0,r6 # low-order part in r6-r7 cvtld r1,r0 # high-order part in r0-r1#endif/* * Step 4: multiply the high order part by 2**31 and combine them */#ifdef GFLOAT mulg2 two31,r0 # slr001 multiply addg2 r6,r0 # slr001 combine#else muld2 two31,r0 # multiply addd2 r6,r0 # combine#endif/* * Step 5: if appropriate, negate the floating value */ jbc $msign,r3,cm2 # Jump if mantissa not signed#ifdef GFLOAT mnegg r0,r0 # slr001 If negative, make it so#else mnegd r0,r0 # slr001 If negative, make it so#endif/* * Step 6: call ldexp to complete the job */cm2: pushl r2 # Put exponent in parameter list#ifdef GFLOAT movg r0,-(sp) # slr001 and also mantissa#else movd r0,-(sp) # slr001 and also mantissa#endif calls $3,_ldexp # go combine themexit: movl (sp)+,r7 movl (sp)+,r6 ret
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -