xref: /csrg-svn/old/as.vax/natof.c (revision 19839)
15805Srrh /*
2*19839Sdist  * Copyright (c) 1982 Regents of the University of California.
3*19839Sdist  * All rights reserved.  The Berkeley software License Agreement
4*19839Sdist  * specifies the terms and conditions for redistribution.
55805Srrh  */
6*19839Sdist 
75805Srrh #ifndef lint
8*19839Sdist static char sccsid[] = "@(#)natof.c	5.1 (Berkeley) 04/30/85";
95805Srrh #endif not lint
105805Srrh 
115805Srrh #include <stdio.h>
125805Srrh #include <ctype.h>
135805Srrh #include <errno.h>
145805Srrh 
155805Srrh #include "as.h"
165805Srrh 
bigatof(str,radix)175805Srrh Bignum bigatof(str, radix)
185805Srrh 	reg	char	*str;		/* r11 */
195805Srrh 		int	radix;		/* TYPF ... TYPH */
205805Srrh {
215805Srrh 		int	msign;
225805Srrh 		int	esign;
235805Srrh 		int	decpt;
245805Srrh 	reg	chptr	temp;		/* r10 */
255805Srrh 	reg	u_int	quotient;	/* r9 */	/* must be here */
265805Srrh 	reg	u_int	remainder;	/* r8 */	/* must be here */
275805Srrh 	reg	chptr	acc;
285805Srrh 	reg	int	dividend;	/* for doing division */
295805Srrh 	reg	u_int	i;
305805Srrh 		short	*sptr;		/* for doing division */
315805Srrh 		int	ch;
325805Srrh 		int	dexponent;	/* decimal exponent */
335805Srrh 		int	bexponent;	/* binary exponent */
345805Srrh 		Bignum	Acc;
355805Srrh 		Bignum	Temp;
365805Srrh 	static	Bignum	znumber;
375805Srrh 		Ovf	ovf;
385805Srrh 		u_int	j;
395805Srrh 	extern	int	errno;
405805Srrh 		u_int	ediv();
415805Srrh 
425805Srrh #ifdef lint
435805Srrh 	quotient = 0;
445805Srrh 	remainder = 0;
455805Srrh #endif lint
465805Srrh 	msign = 0;
475805Srrh 	esign = 0;
485805Srrh 	decpt = 0;
495805Srrh 	dexponent = 0;
505805Srrh 	Acc = znumber;
515805Srrh 	Acc.num_tag = radix;
525805Srrh 	acc = CH_FIELD(Acc);
535805Srrh 	temp = CH_FIELD(Temp);
545805Srrh 
555805Srrh 	do{
565805Srrh 		ch = *str++;
575805Srrh 	} while(isspace(ch));
585805Srrh 
595805Srrh 	switch(ch){
605805Srrh 	case '-':
615805Srrh 		msign = -1;
625805Srrh 		/* FALLTHROUGH */
635805Srrh 	case '+':
645805Srrh 		ch = *str++;
655805Srrh 		break;
665805Srrh 	}
675805Srrh   dofract:
685805Srrh 	for(; isdigit(ch); ch = *str++){
695805Srrh 		assert(((acc[HOC] & SIGNBIT) == 0), "Negative HOC");
705805Srrh 		if (acc[HOC] < MAXINT_10){
715805Srrh 			ovf = numshift(3, temp, acc);
725805Srrh 			ovf |= numshift(1, acc, acc);
735805Srrh 			ovf |= numaddv(acc, temp, acc);
745805Srrh 			ovf |= numaddd(acc, acc, ch - '0');
755805Srrh 			assert(ovf == 0, "Overflow building mantissa");
765805Srrh 		} else {
775805Srrh 			/*
785805Srrh 			 *	Then, the number is too large anyway
795805Srrh 			 */
805805Srrh 			dexponent++;
815805Srrh 		}
825805Srrh 		if (decpt)
835805Srrh 			dexponent--;
845805Srrh 	}
855805Srrh 	switch(ch){
865805Srrh 	case '.':
875805Srrh 		if (decpt == 0){
885805Srrh 			decpt++;
895805Srrh 			ch = *str++;
905805Srrh 			goto dofract;
915805Srrh 		}
925805Srrh 		break;
935805Srrh 	/*
945805Srrh 	 *	only 'e' and 'E' are recognized by atof()
955805Srrh 	 */
965805Srrh 	case 'e':
975805Srrh 	case 'E':
985805Srrh 	/*
995805Srrh 	 *	we include the remainder for compatability with as formats
1005805Srrh 	 *	in as, the radix actual paramater agrees with the character
1015805Srrh 	 *	we expect; consequently, no checking is done.
1025805Srrh 	 */
1035805Srrh 	case 'd':
1045805Srrh 	case 'D':
1055805Srrh 	case 'g':
1065805Srrh 	case 'G':
1075805Srrh 	case 'h':
1085805Srrh 	case 'H':
1095805Srrh 		j = 0;
1105805Srrh 		ch = *str++;
1115805Srrh 		esign = 0;
1125805Srrh 		switch(ch){
1135805Srrh 		case '-':
1145805Srrh 			esign = 1;
1155805Srrh 			/* FALLTHROUGH */
1165805Srrh 		case '+':
1175805Srrh 			ch = *str++;
1185805Srrh 		}
1195805Srrh 		for(; isdigit(ch); ch = *str++){
1205805Srrh 			if (j < MAXINT_10){
1215805Srrh 				j *= 10;
1225805Srrh 				j += ch - '0';
1235805Srrh 			} else {
1245805Srrh 				/*
1255805Srrh 				 *	outrageously large exponent
1265805Srrh 				 */
1275805Srrh 				 /*VOID*/
1285805Srrh 			}
1295805Srrh 		}
1305805Srrh 		if (esign)
1315805Srrh 			dexponent -= j;
1325805Srrh 		else
1335805Srrh 			dexponent += j;
1345805Srrh 		/*
1355805Srrh 		 *	There should be a range check on dexponent here
1365805Srrh 		 */
1375805Srrh 	}
1385805Srrh 	/*
1395805Srrh 	 *	The number has now been reduced to a mantissa
1405805Srrh 	 *	and an exponent.
1415805Srrh 	 *	The mantissa is an n bit number (to the precision
1425805Srrh 	 *	of the extended words) in the acc.
1435805Srrh 	 *	The exponent is a signed power of 10 in dexponent.
1445805Srrh 	 *	msign is on if the resulting number will eventually
1455805Srrh 	 *	be negative.
1465805Srrh 	 *
1475805Srrh 	 *	We now must convert the number to standard format floating
1485805Srrh 	 *	number, which will be done by accumulating
1495805Srrh 	 *	a binary exponent in bexponent, as we gradually
1505805Srrh 	 *	drive dexponent towards zero, one count at a time.
1515805Srrh 	 */
1525805Srrh 	if (isclear(acc)){
1535805Srrh 		return(Acc);
1545805Srrh 	}
1555805Srrh 	bexponent = 0;
1565805Srrh 
1575805Srrh 	/*
1585805Srrh 	 *	Scale the number down.
1595805Srrh 	 *	We must divide acc by 10 as many times as needed.
1605805Srrh 	 */
1615805Srrh 	for (; dexponent < 0; dexponent++){
1625805Srrh 		/*
1635805Srrh 		 *	Align the number so that the most significant
1645805Srrh 		 *	bits are aligned in the most significant
1655805Srrh 		 *	bits of the accumulator, adjusting the
1665805Srrh 		 *	binary exponent as we shift.
1675805Srrh 		 *	The goal is to get the high order bit (NOT the
1685805Srrh 		 *	sign bit) set.
1695805Srrh 		 */
1705805Srrh 		assert(((acc[HOC] & SIGNBIT) == 0), "Negative HOC");
1715805Srrh 		ovf = 0;
1725805Srrh 
1735805Srrh 		for (j = 5; j >= 1; --j){
1745805Srrh 			i = 1 << (j - 1); 		/* 16, 8, 4, 2, 1 */
1755805Srrh 			quotient = ONES(i);
1765805Srrh 			quotient <<= (CH_BITS - 1) - i;
1775805Srrh 			while((acc[HOC] & quotient) == 0){
1785805Srrh 				ovf |= numshift((int)i, acc, acc);
1795805Srrh 				bexponent -= i;
1805805Srrh 			}
1815805Srrh 		}
1825805Srrh 		/*
1835805Srrh 		 *	Add 2 to the accumulator to effect rounding,
1845805Srrh 		 *	and get set up to divide by 5.
1855805Srrh 		 */
1865805Srrh 		ovf = numaddd(acc, acc, 2);
1875805Srrh 		assert(ovf == 0, "Carry out of left rounding up by 2");
1885805Srrh 		/*
1895805Srrh 		 *	Divide the high order chunks by 5;
1905805Srrh 		 *	The last chunk will be divided by 10,
1915805Srrh 		 *	(to see what the remainder is, also to effect rounding)
1925805Srrh 		 *	and then multipiled by 2 to effect division by 5.
1935805Srrh 		 */
1945805Srrh 		remainder = 0;
1955805Srrh #if DEBUGNATOF
1965805Srrh 		printf("Dividing: ");
1975805Srrh 		bignumprint(Acc);
1985805Srrh 		printf("\n");
1995805Srrh #endif DEBUGNATOF
2005805Srrh 		sptr = (short *)acc;
2015805Srrh 		for (i = (CH_N * 2 - 1); i >= 1; --i){
2025805Srrh 			/*
2035805Srrh 			 *	Divide (remainder:16).(acc[i]:16)
2045805Srrh 			 *	by 5, putting the quotient back
2055805Srrh 			 *	into acc[i]:16, and save the remainder
2065805Srrh 			 *	for the next iteration.
2075805Srrh 			 */
2085805Srrh 			dividend = (remainder << 16) | (sptr[i] & ONES(16));
2095805Srrh 			assert(dividend >= 0, "dividend < 0");
2105805Srrh 			quotient = dividend / 5;
2115805Srrh 			remainder = dividend - (quotient * 5);
2125805Srrh 			sptr[i] = quotient;
2135805Srrh 			remainder = remainder;
2145805Srrh 		}
2155805Srrh 		/*
2165805Srrh 		 *	Divide the lowest order chunk by 10,
2175805Srrh 		 *	saving the remainder to decide how to round.
2185805Srrh 		 *	Then, multiply by 2, making it look as
2195805Srrh 		 *	if we divided by 10.
2205805Srrh 		 *	This multiply fills in a 0 on the least sig bit.
2215805Srrh 		 */
2225805Srrh 		dividend = (remainder << 16) | (sptr[0] & ONES(16));
2235805Srrh 		assert(dividend >= 0, "dividend < 0");
2245805Srrh 		quotient = dividend / 10;
2255805Srrh 		remainder = dividend - (quotient * 10);
2265805Srrh 		sptr[0] = quotient + quotient;
2275805Srrh 
2285805Srrh 		if (remainder >= 5)
2295805Srrh 			ovf = numaddd(acc, acc, 1);
2305805Srrh 		/*
2315805Srrh 		 *	Now, divide by 2, effecting division by 10,
2325805Srrh 		 *	merely by adjusting the binary exponent.
2335805Srrh 		 */
2345805Srrh 		bexponent--;
2355805Srrh 	}
2365805Srrh 	/*
2375805Srrh 	 *	Scale the number up by multiplying by 10 as
2385805Srrh 	 *	many times as necessary
2395805Srrh 	 */
2405805Srrh 	for (; dexponent > 0; dexponent--){
2415805Srrh 		/*
2425805Srrh 		 *	Compare high word to (2**31)/5,
2435805Srrh 		 *	and scale accordingly
2445805Srrh 		 */
2455805Srrh 		while ( ((unsigned)acc[HOC]) > MAXINT_5){
2465805Srrh 			(void)numshift(-1, acc, acc);
2475805Srrh 			bexponent++;
2485805Srrh 		}
2495805Srrh 		/*
2505805Srrh 		 *	multiply the mantissa by 5,
2515805Srrh 		 *	and scale the binary exponent by 2
2525805Srrh 		 */
2535805Srrh 		ovf = numshift(2, temp, acc);
2545805Srrh 		ovf |= numaddv(acc, acc, temp);
2555805Srrh 		assert(ovf == 0, "Scaling * 10 of manitissa");
2565805Srrh 		bexponent++;
2575805Srrh 	}
2585805Srrh 	/*
2595805Srrh 	 *	We now have:
2605805Srrh 	 *	a CH_N chunk length binary integer, right
2615805Srrh 	 *		justified (in native format).
2625805Srrh 	 *	a binary exponent.
2635805Srrh 	 *
2645805Srrh 	 *	Now, we treat this large integer as an octa word
2655805Srrh 	 *	number, and unpack it into standard unpacked
2665805Srrh 	 *	format.  That unpacking will give us yet
2675805Srrh 	 *	another binary exponent, which we adjust with
2685805Srrh 	 *	the accumulated binary exponent.
2695805Srrh 	 */
2705805Srrh 	Acc.num_tag = TYPO;
2715805Srrh #if DEBUGNATOF
2725805Srrh 	printf("Octal number: ");
2735805Srrh 	bignumprint(Acc);
2745805Srrh 	printf("\n");
2755805Srrh #endif DEBUGNATOF
2765805Srrh 	Acc = bignumunpack(Acc, &ovf);
2775805Srrh 
2785805Srrh 	if (ovf)
2795805Srrh 		errno = ERANGE;
2805805Srrh #if DEBUGNATOF
2815805Srrh 	printf("Unpacked octal number: ");
2825805Srrh 	bignumprint(Acc);
2835805Srrh 	printf("bexponent == %d\n", bexponent);
2845805Srrh #endif DEBUGNATOF
2855805Srrh 	Acc.num_exponent += bexponent;
2865805Srrh 	assert(Acc.num_sign == 0, "unpacked integer is < 0");
2875805Srrh 	Acc.num_sign = msign;
2885805Srrh 	/*
2895805Srrh 	 *	We now pack the number back into a radix format number.
2905805Srrh 	 *	This checks for overflow, underflow,
2915805Srrh 	 *	and rounds by 1/2 ulp.
2925805Srrh 	 */
2935805Srrh 	ovf = 0;
2945805Srrh 	Acc = bignumpack(Acc, radix, &ovf);
2955805Srrh 	if (ovf)
2965805Srrh 		errno = ERANGE;
2975805Srrh #if DEBUGNATOF
2985805Srrh 	printf("packed number: ");
2995805Srrh 	bignumprint(Acc);
3005805Srrh 	printf("\n");
3015805Srrh #endif DEBUGNATOF
3025805Srrh 	return(Acc);
3035805Srrh }
3045805Srrh #if 0
3055805Srrh /*
3065805Srrh  *	Unfortunately, one can't use the ediv instruction to do
3075805Srrh  *	division on numbers with > 64 bits.
3085805Srrh  *	This is because ediv returns signed quantities;
3095805Srrh  *	if the quotient is an unsigned number > 2^31,
3105805Srrh  *	ediv sets integer overflow.
3115805Srrh  */
3125805Srrh unsigned int ediv(high, low, divisor, qp, i)
3135805Srrh 	register	unsigned int	high;		/* r11 */
3145805Srrh 	register	unsigned int	low;		/* r10 */
3155805Srrh 	register	unsigned int	divisor;	/* r9 */
3165805Srrh 			unsigned int	*qp;
3175805Srrh {
3185805Srrh 	register	unsigned int	remainder;	/* r8 */
3195805Srrh 	register	unsigned int	quotient;	/* r7 */
3205805Srrh 
3215805Srrh 	asm("ediv r9, r10, r7, r8	# Divide.  q->r7, r->r8 (discarded)");
3225805Srrh 	*qp = quotient;
3235805Srrh 	return(remainder);
3245805Srrh }
3255805Srrh #endif 0
326