4.4BSD/usr/src/old/as.tahoe/bignum.c

Compare this file to the similar file:
Show the results in this format:

/*
 *	Copyright (c) 1982 Regents of the University of California
 */
#ifndef lint
static char sccsid[] = "@(#)bignum1.c 4.4 6/30/83";
#endif not lint

#include <errno.h>
#include <stdio.h>
#include "as.h"

Bignum	Znumber;

/*
 *	Construct an integer.
 */

Bignum as_atoi(ccp, radix, ovfp)
	reg	char	*ccp;		/* character cp */
		int	radix;
		Ovf	*ovfp;
{
	reg	chptr	bcp;
		chptr	tcp;
	reg	int	i;
		int	val;
		Bignum	n_n;
		Bignum	t_n;
		int	sign;
		Ovf	ovf;

	ovf = 0;
	sign = 0;
	for (; *ccp; ccp++){
		switch(*ccp){
		case '0':
		case '+':	continue;
		case '-':	sign ^= 1;
				continue;
		}
		break;
	}

	n_n = Znumber;
	t_n = Znumber;
	bcp = CH_FIELD(n_n); (void)numclear(bcp);
	tcp = CH_FIELD(t_n); (void)numclear(tcp);
	for (; *ccp; ccp++){
		switch(*ccp){
		case '8': case '9':
			if (radix < 10)
				goto done;
			/*FALLTHROUGH*/
		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7':
			val = *ccp - '0';
			break;
		case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
			if (radix < 16)
				goto done;
			val = *ccp - 'A' + 10;
			break;
		case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
			if (radix < 16)
				goto done;
			val = *ccp - 'a' + 10;
			break;
		default:
			goto done;
		}
		switch(radix){
		case 8:
			ovf |= numshift(3, bcp, bcp);
			break;
		case 16:
			ovf |= numshift(4, bcp, bcp);
			break;
		case 10:
			ovf |= numshift(1, tcp, bcp);
			ovf |= numshift(3, bcp, bcp);
			ovf |= numaddv(bcp, tcp, bcp);
			break;
		}
		ovf |= numaddd(bcp, bcp, val);
	}
  done: ;
	ovf |= posovf(bcp);
	if (sign){
		if (ovf & OVF_MAXINT) {
			ovf &= ~(OVF_MAXINT | OVF_POSOVF);
		} else {
			ovf |= numnegate(bcp, bcp);
		}
	}
	/*
	 *	find the highest set unit of the number
	 */
	val = sign ? -1 : 0;
	for (i = 0; i < CH_N; i++){
		if (bcp[i] == val)
			break;
	}
	{
		static u_char tagtab[4][8] = {
		{	TYPB,
			TYPW,
			TYPL, TYPL,
			TYPQ, TYPQ, TYPQ, TYPQ },
		{	TYPW,
			TYPL,
			TYPQ, TYPQ },
		{   0   },
		{	TYPL,
			TYPQ }
		};
		/*
		 *	i indexes to the null chunk; make it point to the
		 *	last non null chunk
		 */
		i -= 1;
		if (i < 0)
			i = 0;
		n_n.num_tag = tagtab[HOC][i];
		assert(n_n.num_tag != 0, " Botch width computation");
	}
	*ovfp = ovf;
	return(n_n);
}

Bignum as_atof (numbuf, radix)
	char *numbuf;
{
	double atof ();
	Bignum number;

	number = Znumber;
	number.num_tag = radix;
	switch (radix)
	{
	   case TYPD:
		number.num_num.numFd_float.Fd_value = atof (numbuf);
		break;
	   case TYPF:
		number.num_num.numFf_float.Ff_value = atof (numbuf);
		break;
	}

	return (number);
}

Ovf posovf(src)
	reg	chptr	src;
{
	reg	int	i;
	Ovf	overflow = 0;

	if (src[HOC] & SIGNBIT)
		overflow = OVF_POSOVF;
	if (src[HOC] == SIGNBIT){
		for (i = HOC - 1; i >= 0; --i){
			if (src[i] != 0)
				return(overflow);
		}
		overflow |= OVF_MAXINT;
	}
	return(overflow);
}

/*
 *	check if the number is clear
 */
int isclear(dst)
	reg	chptr	dst;
{
	return(!isunequal(dst, CH_FIELD(Znumber)));
}

int isunequal(src1, src2)
	reg	chptr	src1, src2;
{
	reg	int	i;

	i = CH_N;
	do{
		if (*src1++ != *src2++)
			return(i);
	}while(--i);
	return(0);
}

Ovf numclear(dst)
	reg	chptr	dst;
{
	reg	int	i;
	i = CH_N;
	do{
		*dst++ = 0;
	}while(--i);
	return(0);
}

Ovf numshift(n, dst, src)
		int	n;
	reg	chptr	dst, src;
{
	reg	int	i;
	reg	u_int	carryi, carryo;
	reg	u_int	mask;
	reg	u_int	value;

	i = CH_N;
	if (n == 0){
		do{
			*dst++ = *src++;
		} while(--i);
		return(0);
	}

	carryi = 0;
	mask = ONES(n);

	if (n > 0){
		do{
			value = *src++;
			carryo = (value >> (CH_BITS - n)) & mask; 
			value <<= n;
			value &= ~mask;
			*dst++ = value | carryi;
			carryi = carryo;
		} while (--i);
		return(carryi ? OVF_LSHIFT : 0);
	} else {
		n = -n;
		src += CH_N;
		dst += CH_N;
		do{
			value = *--src;
			carryo = value & mask; 
			value >>= n;
			value &= ONES(CH_BITS - n);
			*--dst = value | carryi;
			carryi = carryo << (CH_BITS - n);
		} while (--i);
		return(carryi ? OVF_LSHIFT : 0);
	}
}

Ovf numaddd(dst, src1, val)
	chptr	dst, src1;
	int	val;
{
	static	Bignum	work;

	work.num_uchar[3] = val;
	return (numaddv(dst, src1, CH_FIELD(work)));
}

Ovf numaddv(dst, src1, src2)
	reg	chptr	dst, src1, src2;
{
	reg	int	i;
	reg	int	carry;
	reg	u_int	A,B,value;

	carry = 0;
	i = CH_N;
	do{
		A = *src1++;
		B = *src2++;
		value = A + B + carry;
		*dst++ = value;
		carry = 0;
		if (value < A || value < B)
			carry = 1;
	} while (--i);
	return(carry ? OVF_ADDV : 0);
}

Ovf numnegate(dst, src)
	chptr	dst, src;
{
	Ovf	ovf;

	ovf = num1comp(dst, src) ;
	ovf |= numaddd(dst, dst, 1);
	return(ovf);
}

Ovf num1comp(dst, src)
	reg	chptr	dst, src;
{
	reg	int	i;
	i = CH_N;
	do{
		*dst++ = ~ *src++;
	}while (--i);
	return(0);
}

bignumprint(number)
	Bignum	number;		/* number presented */
{
	switch (num_type)
	{
		case TYPQ:
			printf ("val[msd] = 0x%x, val[lsd] = 0x%x.",
			number.num_num.numIq_int.Iq_ulong[1],
			number.num_num.numIq_int.Iq_ulong[0]);
			break;
		case TYPF:
			printf ("value %20.17f",
			number.num_num.numFf_float.Ff_value);
			break;
		case TYPD:
			printf ("value %20.17f",
			number.num_num.numFd_float.Fd_value);
			break;
		default:
			break;
	}
}