mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-01 00:33:09 +00:00
cce5a349d9
consists mostly of changing sloppy K&R C code to slightly more disciplined K&R C code, and doing the usual things to shut gcc up. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@12877 91177308-0d34-0410-b5e6-96231b3b80d8
820 lines
13 KiB
C
820 lines
13 KiB
C
/* Copyright (c) 1988 Bellcore
|
|
** All Rights Reserved
|
|
** Permission is granted to copy or use this program, EXCEPT that it
|
|
** may not be sold for profit, the copyright notice must be reproduced
|
|
** on copies, and credit should be given to Bellcore where it is due.
|
|
** BELLCORE MAKES NO WARRANTY AND ACCEPTS NO LIABILITY FOR THIS PROGRAM.
|
|
*/
|
|
|
|
|
|
#ifndef lint
|
|
static char rcsid[]= "$Header$";
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include "misc.h"
|
|
#include "floatrep.h"
|
|
#include "float.h"
|
|
#include "strings.h"
|
|
|
|
#define _F_GETEND(x) (x + (strlen(x)-1))
|
|
|
|
/*
|
|
int floatcnt = 0;
|
|
*/
|
|
/*
|
|
** routines to convert strings to our internal floating point form
|
|
** isfloat just looks at the string
|
|
** to see if a conversion is reasonable
|
|
** it does look-ahead on when it sees an 'e' and such.
|
|
** atocf actually does the conversion.
|
|
** these two routines could probably be combined
|
|
*/
|
|
|
|
/*
|
|
** test to see if the string can reasonably
|
|
** be interpreted as floating point number
|
|
** returns 0 if string can't be interpreted as a float
|
|
** otherwise returns the number of digits that will be used in F_atof
|
|
*/
|
|
int
|
|
F_isfloat(str,need_decimal,allow_sign)
|
|
char *str;
|
|
int need_decimal; /* if non-zero, require that a decimal point be present
|
|
otherwise, accept strings like "123" */
|
|
int allow_sign; /* if non-zero, allow + or - to set the sign */
|
|
{
|
|
int man_length = 0; /* length of the fractional part (mantissa) */
|
|
int exp_length = 0; /* length of the exponential part */
|
|
int got_a_digit = 0; /* flag to set if we ever see a digit */
|
|
|
|
/*
|
|
** look for an optional leading sign marker
|
|
*/
|
|
if (allow_sign && ('+' == *str || '-' == *str))
|
|
{
|
|
str++; man_length++;
|
|
}
|
|
/*
|
|
** count up the digits on the left hand side
|
|
** of the decimal point
|
|
*/
|
|
while(isdigit(*str))
|
|
{
|
|
got_a_digit = 1;
|
|
str++; man_length++;
|
|
}
|
|
|
|
/*
|
|
** check for a decimal point
|
|
*/
|
|
if ('.' == *str)
|
|
{
|
|
str++; man_length++;
|
|
}
|
|
else
|
|
{
|
|
if (need_decimal)
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** collect the digits on the right hand
|
|
** side of the decimal point
|
|
*/
|
|
while(isdigit(*str))
|
|
{
|
|
got_a_digit = 1;
|
|
str++; man_length++;
|
|
}
|
|
|
|
if (!got_a_digit)
|
|
return(0);
|
|
|
|
/*
|
|
** now look ahead for an exponent
|
|
*/
|
|
if ('e' == *str ||
|
|
'E' == *str ||
|
|
'd' == *str ||
|
|
'D' == *str)
|
|
{
|
|
str++; exp_length++;
|
|
if ('+' == *str || '-' == *str)
|
|
{
|
|
str++; exp_length++;
|
|
}
|
|
|
|
if (!isdigit(*str))
|
|
{
|
|
/*
|
|
** look ahead went too far,
|
|
** so return just the length of the mantissa
|
|
*/
|
|
return(man_length);
|
|
}
|
|
|
|
while (isdigit(*str))
|
|
{
|
|
str++; exp_length++;
|
|
}
|
|
}
|
|
return(man_length+exp_length); /* return the total length */
|
|
}
|
|
|
|
/*
|
|
** routine to convert a string to our internal
|
|
** floating point representation
|
|
**
|
|
** similar to atof()
|
|
*/
|
|
F_float
|
|
F_atof(str,allflag)
|
|
char *str;
|
|
int allflag; /* require that exactly all the characters are used */
|
|
{
|
|
char *beg = str; /* place holder for beginning of the string */
|
|
char man[R_MANMAX]; /* temporary location to build the mantissa */
|
|
int length = 0; /* length of the mantissa so far */
|
|
int got_a_digit = 0; /* flag to set if we get a non-zero digit */
|
|
int i;
|
|
int resexp;
|
|
|
|
F_float res; /* where we build the result */
|
|
|
|
/*
|
|
floatcnt++;
|
|
*/
|
|
res = R_makefloat();
|
|
|
|
R_setsign(res,R_POSITIVE);
|
|
|
|
resexp = 0;
|
|
man[0] = '\0';
|
|
|
|
/*
|
|
** check for leading sign
|
|
*/
|
|
if ('+' == *str)
|
|
{
|
|
/*
|
|
** sign should already be positive, see above in this
|
|
** routine, so just skip the plus sign
|
|
*/
|
|
str++;
|
|
}
|
|
else
|
|
{
|
|
if ('-' == *str)
|
|
{
|
|
R_setsign(res,R_NEGATIVE);
|
|
str++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** skip any leading zeros
|
|
*/
|
|
while('0' == *str)
|
|
{
|
|
str++;
|
|
}
|
|
|
|
/*
|
|
** now snarf up the digits on the left hand side
|
|
** of the decimal point
|
|
*/
|
|
while(isdigit(*str))
|
|
{
|
|
got_a_digit = 1;
|
|
man[length++] = *str++;
|
|
man[length] = '\0';
|
|
resexp++;
|
|
}
|
|
|
|
/*
|
|
** skip the decimal point if there is one
|
|
*/
|
|
if ('.' == *str)
|
|
str++;
|
|
|
|
/*
|
|
** trim off any leading zeros (on the right hand side)
|
|
** if there were no digits in front of the decimal point.
|
|
*/
|
|
|
|
if (!got_a_digit)
|
|
{
|
|
while('0' == *str)
|
|
{
|
|
str++;
|
|
resexp--;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** now snarf up the digits on the right hand side
|
|
*/
|
|
while(isdigit(*str))
|
|
{
|
|
man[length++] = *str++;
|
|
man[length] = '\0';
|
|
}
|
|
|
|
if ('e' == *str ||
|
|
'E' == *str ||
|
|
'd' == *str ||
|
|
'D' == *str )
|
|
{
|
|
str++;
|
|
resexp += atoi(str);
|
|
}
|
|
|
|
if (allflag)
|
|
{
|
|
if ('+' == *str ||
|
|
'-' == *str)
|
|
{
|
|
str++;
|
|
}
|
|
while (isdigit(*str))
|
|
{
|
|
str++;
|
|
}
|
|
if ('\0' != *str)
|
|
{
|
|
(void) sprintf(Z_err_buf,
|
|
"didn't use up all of %s in atocf",
|
|
beg);
|
|
Z_fatal(Z_err_buf);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** check for special case of all zeros in the mantissa
|
|
*/
|
|
for (i=0;i<length;i++)
|
|
{
|
|
if (man[i] != '0')
|
|
{
|
|
/*
|
|
** the mantissa is non-zero, so return it unchanged
|
|
*/
|
|
S_trimzeros(man);
|
|
/*
|
|
** save a copy of the mantissa
|
|
*/
|
|
R_setfrac(res,man);
|
|
R_setexp(res,resexp);
|
|
return(res);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** the answer is 0, so . . .
|
|
*/
|
|
R_setzero(res);
|
|
return(res);
|
|
}
|
|
|
|
|
|
/*
|
|
** add s2 to s1
|
|
*/
|
|
static
|
|
void
|
|
_F_stradd(s1,s2)
|
|
char *s1,*s2;
|
|
{
|
|
char *end1 = s1 + (strlen(s1)-1);
|
|
char *end2 = s2 + (strlen(s2)-1);
|
|
|
|
static char result[R_MANMAX];
|
|
char *resptr = result+(R_MANMAX-1); /*point to the end of the array */
|
|
int carry = 0;
|
|
int tmp,val1,val2;
|
|
|
|
*resptr-- = '\0';
|
|
|
|
while ((end1 >= s1) || ( end2 >= s2))
|
|
{
|
|
if (end1 >= s1)
|
|
{
|
|
val1 = *end1 - '0';
|
|
--end1;
|
|
}
|
|
else
|
|
{
|
|
val1 = 0;
|
|
}
|
|
|
|
if (end2 >= s2)
|
|
{
|
|
val2 = *end2 - '0';
|
|
--end2;
|
|
}
|
|
else
|
|
{
|
|
val2 = 0;
|
|
}
|
|
|
|
tmp = val1 + val2 + carry;
|
|
if (tmp > 9)
|
|
{
|
|
carry = 1;
|
|
tmp -= 10;
|
|
}
|
|
else
|
|
{
|
|
carry = 0;
|
|
}
|
|
|
|
*resptr-- = tmp+'0';
|
|
}
|
|
if (carry)
|
|
{
|
|
*resptr = '1';
|
|
}
|
|
else
|
|
{
|
|
resptr++;
|
|
}
|
|
(void) strcpy(s1,resptr);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** add zero(s) onto the end of a string
|
|
*/
|
|
static void
|
|
addzeros(ptr,count)
|
|
char *ptr;
|
|
int count;
|
|
{
|
|
for(;count> 0;count--)
|
|
{
|
|
(void) strcat(ptr,"0");
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** subtract two mantissa strings
|
|
*/
|
|
F_float
|
|
F_floatsub(p1,p2)
|
|
F_float p1,p2;
|
|
{
|
|
static F_float result;
|
|
static int needinit = 1;
|
|
static char man1[R_MANMAX],man2[R_MANMAX],diff[R_MANMAX];
|
|
int exp1,exp2;
|
|
char *diffptr,*big,*small;
|
|
int man_cmp_val,i,borrow;
|
|
|
|
if (needinit)
|
|
{
|
|
result = R_makefloat();
|
|
needinit = 0;
|
|
}
|
|
|
|
man1[0] = '\0';
|
|
man2[0] = '\0';
|
|
|
|
exp1 = R_getexp(p1);
|
|
exp2 = R_getexp(p2);
|
|
|
|
/*
|
|
** line up the mantissas
|
|
*/
|
|
while (exp1 < exp2)
|
|
{
|
|
(void) strcat(man1,"0");
|
|
exp1++;
|
|
}
|
|
|
|
while(exp1 > exp2)
|
|
{
|
|
(void) strcat(man2,"0");
|
|
exp2++;
|
|
}
|
|
|
|
if (exp1 != exp2) /* boiler plate assertion */
|
|
{
|
|
Z_fatal("mantissas didn't get lined up properly in floatsub");
|
|
}
|
|
|
|
(void) strcat(man1,R_getfrac(p1));
|
|
(void) strcat(man2,R_getfrac(p2));
|
|
|
|
/*
|
|
** now that the mantissa are aligned,
|
|
** if the strings are the same, return 0
|
|
*/
|
|
if((man_cmp_val = strcmp(man1,man2)) == 0)
|
|
{
|
|
R_setzero(result);
|
|
return(result);
|
|
}
|
|
|
|
/*
|
|
** pad the shorter string with 0's
|
|
** when this loop finishes, both mantissas should
|
|
** have the same length
|
|
*/
|
|
if (strlen(man1)> strlen(man2))
|
|
{
|
|
addzeros(man2,strlen(man1)-strlen(man2));
|
|
}
|
|
else
|
|
{
|
|
if (strlen(man1)<strlen(man2))
|
|
{
|
|
addzeros(man1,strlen(man2)-strlen(man1));
|
|
}
|
|
}
|
|
|
|
if (strlen(man1) != strlen(man2)) /* pure boilerplate */
|
|
{
|
|
Z_fatal("lengths not equal in F_floatsub");
|
|
}
|
|
|
|
if (man_cmp_val < 0)
|
|
{
|
|
big = man2;
|
|
small = man1;
|
|
}
|
|
else
|
|
{
|
|
big = man1;
|
|
small = man2;
|
|
}
|
|
|
|
/*
|
|
** find the difference between the mantissas
|
|
*/
|
|
for(i=(strlen(big)-1),borrow=0,diff[strlen(big)] = '\0';i>=0;i--)
|
|
{
|
|
char from;
|
|
if (borrow)
|
|
{
|
|
if (big[i] == '0')
|
|
{
|
|
from = '9';
|
|
}
|
|
else
|
|
{
|
|
from = big[i]-1;
|
|
borrow = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(big[i]<small[i])
|
|
{
|
|
from = '9'+1;
|
|
borrow = 1;
|
|
}
|
|
else
|
|
{
|
|
from = big[i];
|
|
}
|
|
}
|
|
diff[i] = (from-small[i]) + '0';
|
|
}
|
|
|
|
/*
|
|
** trim the leading zeros on the difference
|
|
*/
|
|
diffptr = diff;
|
|
while('0' == *diffptr)
|
|
{
|
|
diffptr++;
|
|
exp1--;
|
|
}
|
|
|
|
R_setexp(result,exp1); /* exponents are equal at the point */
|
|
R_setfrac(result,diffptr);
|
|
R_setsign(result,R_POSITIVE);
|
|
return(result);
|
|
}
|
|
|
|
int
|
|
F_floatcmp(f1,f2)
|
|
F_float f1,f2;
|
|
{
|
|
static char man1[R_MANMAX],man2[R_MANMAX];
|
|
|
|
/*
|
|
** special case for zero
|
|
*/
|
|
if (R_zerofloat(f1))
|
|
{
|
|
if (R_zerofloat(f2))
|
|
{
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
return(-1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (R_zerofloat(f2))
|
|
{
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** to reach this point, both numbers must be non zeros
|
|
*/
|
|
if (R_getexp(f1) < R_getexp(f2))
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
if (R_getexp(f1) > R_getexp(f2))
|
|
{
|
|
return(1);
|
|
}
|
|
|
|
(void) strcpy(man1,R_getfrac(f1));
|
|
S_trimzeros(man1);
|
|
|
|
(void) strcpy(man2,R_getfrac(f2));
|
|
S_trimzeros(man2);
|
|
return(strcmp(man1,man2));
|
|
}
|
|
|
|
F_float
|
|
F_floatmul(f1,f2)
|
|
F_float f1,f2;
|
|
{
|
|
static char prod[R_MANMAX];
|
|
char *end;
|
|
int count1 = 0;
|
|
int count2 = 0;
|
|
int tmp,len;
|
|
char *end1;
|
|
char *end2;
|
|
static char man1[R_MANMAX],man2[R_MANMAX];
|
|
char *bigman,*smallman;
|
|
static F_float result;
|
|
static int needinit = 1;
|
|
|
|
if (needinit)
|
|
{
|
|
result = R_makefloat();
|
|
needinit = 0;
|
|
}
|
|
/*
|
|
** special case for a zero result
|
|
*/
|
|
if (R_zerofloat(f1) || R_zerofloat(f2))
|
|
{
|
|
R_setzero(result);
|
|
return(result);
|
|
}
|
|
|
|
(void) strcpy(man1,R_getfrac(f1));
|
|
(void) strcpy(man2,R_getfrac(f2));
|
|
|
|
end1 = _F_GETEND(man1);
|
|
end2 = _F_GETEND(man2);
|
|
|
|
/*
|
|
** decide which number will cause multiplication loop to go
|
|
** around the least
|
|
*/
|
|
while(end1 >= man1)
|
|
{
|
|
count1 += *end1 - '0';
|
|
end1--;
|
|
}
|
|
|
|
while(end2 >= man2)
|
|
{
|
|
count2 += *end2 - '0';
|
|
end2--;
|
|
}
|
|
|
|
|
|
if (count1 > count2)
|
|
{
|
|
bigman = man1;
|
|
smallman = man2;
|
|
}
|
|
else
|
|
{
|
|
bigman = man2;
|
|
smallman = man1;
|
|
}
|
|
S_trimzeros(bigman);
|
|
S_trimzeros(smallman);
|
|
len = strlen(bigman) + strlen(smallman);
|
|
|
|
end = _F_GETEND(smallman);
|
|
(void) strcpy(prod,"0");
|
|
|
|
/*
|
|
** multiplication by repeated addition
|
|
*/
|
|
while(end >= smallman)
|
|
{
|
|
for(tmp = 0;tmp<*end-'0';tmp++)
|
|
{
|
|
_F_stradd(prod,bigman);
|
|
}
|
|
addzeros(bigman,1);
|
|
end--;
|
|
}
|
|
|
|
R_setfrac(result,prod);
|
|
R_setexp(result,(((R_getexp(f1) + R_getexp(f2)) - len)+ strlen(prod)));
|
|
|
|
if (R_getsign(f1) == R_getsign(f2))
|
|
{
|
|
R_setsign(result,R_POSITIVE);
|
|
}
|
|
else
|
|
{
|
|
R_setsign(result,R_NEGATIVE);
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
int
|
|
_F_xor(x,y)
|
|
int x, y;
|
|
{
|
|
return(((x) && !(y)) || (!(x) && (y)));
|
|
}
|
|
#define _F_SAMESIGN(x,y) _F_xor((x<0),(y<0))
|
|
#define _F_ABSADD(x,y) (Z_ABS(x) + Z_ABS(y))
|
|
|
|
int
|
|
_F_ABSDIFF(x,y)
|
|
int x, y;
|
|
{
|
|
if (Z_ABS(x) < Z_ABS(y))
|
|
{
|
|
return(Z_ABS(y) - Z_ABS(x));
|
|
}
|
|
else
|
|
{
|
|
return(Z_ABS(x) - Z_ABS(y));
|
|
}
|
|
}
|
|
/*
|
|
** add two floats without regard to sign
|
|
*/
|
|
F_float
|
|
F_floatmagadd(p1,p2)
|
|
F_float p1,p2;
|
|
{
|
|
static F_float result;
|
|
static int needinit = 1;
|
|
|
|
static char man1[R_MANMAX],man2[R_MANMAX];
|
|
|
|
int digits; /* count of the number of digits needed to represent the
|
|
result */
|
|
int resexp; /* exponent of the result */
|
|
int len; /* length of the elements before adding */
|
|
char *diffptr;
|
|
|
|
if (needinit)
|
|
{
|
|
result = R_makefloat();
|
|
needinit = 0;
|
|
}
|
|
(void) strcpy(man1,"");
|
|
(void) strcpy(man2,"");
|
|
|
|
/*
|
|
** find the difference in the exponents number of digits
|
|
*/
|
|
if( _F_SAMESIGN(R_getexp(p1),R_getexp(p2)))
|
|
{
|
|
digits = _F_ABSDIFF(R_getexp(p1),R_getexp(p2));
|
|
}
|
|
else
|
|
{
|
|
digits = _F_ABSADD(R_getexp(p1),R_getexp(p2));
|
|
}
|
|
|
|
/*
|
|
** make sure that there is room to store the result
|
|
*/
|
|
if (digits>0)
|
|
{
|
|
if (R_getexp(p1) < R_getexp(p2))
|
|
{
|
|
/*
|
|
** leave room for terminator
|
|
*/
|
|
if (digits+strlen(R_getfrac(p1)) > (R_MANMAX-1))
|
|
{
|
|
(void) sprintf(Z_err_buf,
|
|
"numbers differ by too much in magnitude");
|
|
Z_fatal(Z_err_buf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** leave room for terminator
|
|
*/
|
|
if (digits+strlen(R_getfrac(p2)) > (R_MANMAX-1))
|
|
{
|
|
(void) sprintf(Z_err_buf,
|
|
"numbers differ by too much in magnitude");
|
|
Z_fatal(Z_err_buf);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** leave room for terminator and possible carry
|
|
*/
|
|
if (Z_MAX(strlen(R_getfrac(p1)),
|
|
strlen(R_getfrac(p2))) > (R_MANMAX-2))
|
|
{
|
|
(void) sprintf(Z_err_buf,
|
|
"numbers differ by too much in magnitude");
|
|
Z_fatal(Z_err_buf);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** pad zeroes on the front of the smaller number
|
|
*/
|
|
if (R_getexp(p1) < R_getexp(p2))
|
|
{
|
|
|
|
addzeros(man1,digits);
|
|
resexp = R_getexp(p2);
|
|
}
|
|
else
|
|
{
|
|
addzeros(man2,digits);
|
|
resexp = R_getexp(p1);
|
|
}
|
|
(void) strcat(man1,R_getfrac(p1));
|
|
(void) strcat(man2,R_getfrac(p2));
|
|
|
|
len = Z_MAX(strlen(man1),strlen(man2));
|
|
|
|
/*
|
|
** add the two values
|
|
*/
|
|
_F_stradd(man1,man2);
|
|
|
|
/*
|
|
** adjust the exponent to account for a
|
|
** possible carry
|
|
*/
|
|
resexp += strlen(man1) - len;
|
|
|
|
|
|
/*
|
|
** trim the leading zeros on the sum
|
|
*/
|
|
diffptr = man1;
|
|
while('0' == *diffptr)
|
|
{
|
|
diffptr++;
|
|
resexp--;
|
|
}
|
|
|
|
R_setfrac(result,diffptr);
|
|
R_setexp(result,resexp);
|
|
R_setsign(result,R_POSITIVE);
|
|
|
|
return(result);
|
|
}
|
|
|
|
/*
|
|
** useful debugging routine. we don't call it in the release,
|
|
** so it is commented out, but we'll leave it for future use
|
|
*/
|
|
|
|
/*
|
|
F_printfloat(fl)
|
|
F_float fl;
|
|
{
|
|
(void) printf("fraction = :%s: exp = %d sign = %c\n",
|
|
R_getfrac(fl),
|
|
R_getexp(fl),
|
|
((R_getsign(fl) == R_POSITIVE) ? '+': '-'));
|
|
|
|
}
|
|
*/
|