home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
MAGAZINE
/
DDJ9309.ZIP
/
FPALIB.ZIP
/
FALIB.C
next >
Wrap
C/C++ Source or Header
|
1993-05-12
|
32KB
|
993 lines
/* Extended IEEE Compatible Floating Point Arithmetic Library
**
** Version 1.0
** Copyright (C) 1990, by Fred Motteler
** All Rights Reserved
**
** This is a collection of routines to convert arbitrary precision float and
** integer values to and from ASCII strings.
**
** Each routine that returns a floating point result returns a condition code
** value:
**
** 0 0 0 0 N Z I n
** Where N = negative (FFNEG)
** Z = zero (FFZERO)
** I = infinite (FFINF)
** n = not a number (FFNAN)
**
** Each routine that returns a integer result returns a condition code
** value:
**
** 0 0 0 0 Z V S C
** Where Z = zero (ZERO)
** V = overflow (OVERFLOW)
** S = sign (SIGN)
** C = carry (CARRY)
**
** Note that these routines recognize zero and infinite input values. Not a
** number and denormalized input values are not recognized. The routines
** blindly assume that the arguments are valid floating point numbers.
**
** These routines will return valid zero, infinite, and not a number values.
*/
#include <stdio.h>
#ifndef MWC
#include <stdlib.h>
#endif
#include "imlib.h"
#include "ffmlib.h"
#include "fmlib.h"
#define SINGLEXP 8
#define SINGLEFRAC 23
#define SINGLETOT 4
static unsigned char log10of2AB[4] = {0x3e, 0x9a, 0x20, 0x9b};
#ifdef TEST
#define DOUBLEXP 11
#define DOUBLEFRAC 52
#define DOUBLETOT 8
#define EXTENDEXP 15
#define EXTENDFRAC 63
#define EXTENDTOT 10
unsigned char intval1AB[4] = {0x0, 0x0, 0x12, 0x34};
unsigned char intval2AB[4] = {0x12, 0x34, 0x56, 0x78};
unsigned char fltval1AB[4] = {0x3e, 0x9a, 0x20, 0x9b};
unsigned char dblval1AB[8] = {0x52, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
void
main()
{
unsigned char *strBP, *fltvalBP;
int i;
strBP = (unsigned char *) malloc(80);
fltvalBP = (unsigned char *) malloc(16);
printf("LONG to ASCII\n");
intostr(intval1AB, 4, strBP, 16, 10);
printf("intval1AB to ASCII: %s Should be 4660.\n",strBP);
printf("LONG to ASCII\n");
intostr(intval2AB, 4, strBP, 16, 10);
printf("intval2AB to ASCII: %s Should be 305419896.\n",strBP);
printf("SINGLE to ASCII\n");
fltostr(fltval1AB, SINGLEFRAC, SINGLEXP, strBP, 16);
printf("fltval1AB to ASCII: %s\n",strBP);
printf("DOUBLE to ASCII\n");
fltostr(dblval1AB, DOUBLEFRAC, DOUBLEXP, strBP, 32);
printf("dblval1AB to ASCII: %s\n",strBP);
printf("ASCII to LONG\n");
strtoint("1024",5, intval1AB, 4, 10);
printf("Should be 0 0 4 0:");
for (i = 0; i < 4; i++)
printf("%2x",intval1AB[i]);
printf("\n");
strtoint("305419896",10, intval1AB, 4, 10);
printf("Should be 12345678:");
for (i = 0; i < 4; i++)
printf("%2x",intval1AB[i]);
printf("\n");
printf("ASCII to FLOAT\n");
strtoflt("3.459e2", 9, fltvalBP, SINGLEFRAC, SINGLEXP);
for (i = 0; i < 4; i++)
printf("%2x",*(fltvalBP + i));
printf("\n");
fltostr(fltvalBP, SINGLEFRAC, SINGLEXP, strBP, 16);
printf("Conversion back to ASCII: %s\n",strBP);
printf("ASCII to DOUBLE\n");
strtoflt( "3.459e2", 9, fltvalBP, DOUBLEFRAC, DOUBLEXP);
for (i = 0; i < 8; i++)
printf("%2x",*(fltvalBP + i));
printf("\n");
fltostr(fltvalBP, DOUBLEFRAC, DOUBLEXP, strBP, 32);
printf("Conversion back ASCII: %s\n",strBP);
exit(0);
}
#endif
/* Function: unsigned char intostr(unsigned char *intvalBP,
** int intlenN,
** char *strBP,
** int slenN,
** int radixN)
**
** This function converts the integer value pointed to intvalBP to a decimal
** ASCII string representation of the value pointed to by strBP. intlenN is
** the length of the integer to convert in bytes. strBP is the length of the
** string buffer in bytes. radixN is the radix of the ASCII string value.
** Only radixes 2 thru 36 are supported.
*/
unsigned char
#ifdef PROTOTYPES
intostr(unsigned char *intvalBP, int intlenN, char *strBP, int slenN,
int radixN)
#else
intostr(intvalBP, intlenN, strBP, slenN, radixN)
unsigned char *intvalBP;
int intlenN;
char *strBP;
int slenN;
int radixN;
#endif
{
unsigned char condcodeB, digitB;
unsigned char *radixBP;
unsigned char *tempBP;
unsigned char *digitstackBP;
int digitindexN;
int i;
condcodeB = 0;
/* Check if the integer is zero. */
if (ucheckm(intvalBP, intlenN) == 0)
{
*strBP++ = '0';
*strBP = '\0';
return(ZERO);
}
/* Check if integer is negative. */
if ((*intvalBP & 0x80) != 0)
{
/* Change sign of the integer value */
inegm(intvalBP, intlenN);
/* Write out a minus (-) sign */
*strBP++ = '-';
slenN--;
condcodeB = SIGN;
}
/* Convert the radix value to multiple byte integer format. */
radixBP = FCALLOC(intlenN, 1, "INTOSTR1");
if (radixN > 36) radixN = 36;
if (radixN < 2) radixN = 2;
*(radixBP + intlenN - 1) = (unsigned char) radixN;
/* Allocate space for a digit stack. This is required because repeated
* division gives the least significant digit first, however ASCII string
* representations have the most significant digit first. */
digitstackBP = FCALLOC(slenN, 1, "INTOSTR2");
digitindexN = 0;
/* Convert the integer value to a string, one digit at a time. This
* starts with the least significant digits and works towards the most
* significant. */
tempBP = (unsigned char *) FMALLOC(intlenN, "INTOSTR3");
while (ucheckm(intvalBP, intlenN) != 0)
{
/* Copy the divisor the the correct place. */
for (i = 0; i < intlenN; i++)
*(tempBP + i) = *(radixBP + i);
/* Divide the integer value by the radix. */
udivm(intvalBP, tempBP, intlenN);
/* The quotient is in tempBP, the remainder is in intvalBP. */
digitB = *(intvalBP + intlenN - 1);
/* Copy the quotient back to the divisor place. */
for (i = 0; i < intlenN; i++)
*(intvalBP + i) = *(tempBP + i);
/* Convert the digit to ASCII */
if (digitB < 10)
digitB += 0x30; /* 0 thru 9 */
else
digitB += 0x57; /* a thru z */
/* Push the digit onto the digit stack */
*(digitstackBP + digitindexN++) = digitB;
if( digitindexN >= slenN )
{
FFREE(radixBP);
FFREE(digitstackBP);
FFREE(tempBP);
return(OVERFLOW);
}
}
/* Pop the digits off the stack and copy them to the result string. */
while( digitindexN > 0 )
{
*strBP++ = *(digitstackBP + (--digitindexN));
if( (slenN--) <= 0)
{
FFREE(radixBP);
FFREE(digitstackBP);
FFREE(tempBP);
return(OVERFLOW);
}
}
*strBP = '\0';
/* All done, clean up and return. */
FFREE(radixBP);
FFREE(digitstackBP);
FFREE(tempBP);
return(condcodeB);
}
/* Function: unsigned char fltostr(unsigned char *fltvalBP, int fracbitN,
** int expbitN, char *strBP, int slenN)
**
** This function converts the floating point value pointed to fltvalBP to a
** decimal ASCII string representation of the value pointed to by strBP.
** fracbitN is the length of the floating point mantissa in bits. expbitN
** is the length of the floating point exponent in bits. strBP is the
** length of the string buffer in bytes.
*/
unsigned char
#ifdef PROTOTYPES
fltostr(unsigned char *fltvalBP, int fracbitN, int expbitN,
char *strBP, int slenN)
#else
fltostr(fltvalBP, fracbitN, expbitN, strBP, slenN)
unsigned char *fltvalBP;
int fracbitN;
int expbitN;
char *strBP;
int slenN;
#endif
{
int expbyteN, fracbyteN;
unsigned char *expbiasBP;
unsigned char *exponeBP;
unsigned char *fltfracBP, *fltexpBP;
unsigned char *tempfltBP, *tempexpBP;
unsigned char *ptenfltBP, *onetenthBP, *oneBP;
unsigned char ptenccB;
unsigned char fltsignB;
unsigned char condcodeB;
int i, totalenN;
unsigned char minusoneB, zeroB;
unsigned int mantlenN;
unsigned char *mantintBP;
unsigned char *mantlenBP;
minusoneB = 0xff;
zeroB = 0;
/* Initialize the condition code byte to zero */
condcodeB = 0;
/* Determine the total byte length of the floating point number */
totalenN = fftotlen(expbitN, fracbitN);
/* Determine the number of bytes required to hold the mantissa and
* exponent. Allocate space for each... */
expbyteN = ffexplen(expbitN);
fracbyteN = ffraclen(fracbitN);
fltfracBP = (unsigned char *) FCALLOC(fracbyteN, 1, "FLTOSTR1");
fltexpBP = (unsigned char *) FMALLOC(expbyteN, "FLTOSTR2");
expbiasBP = (unsigned char *) FCALLOC(expbyteN, 1, "FLTOSTR3");
exponeBP = (unsigned char *) FCALLOC(expbyteN, 1, "FLTOSTR4");
/* Isolate the mantissas, exponents, and signs. Calling ffextall()
* also sets the implied ms bit of the mantissa to 1. */
ffextall(fltvalBP, totalenN, fracbitN, fracbyteN, expbitN, expbyteN,
fltfracBP, fltexpBP, &fltsignB);
/* Write sign bit and decimal point to the output string. */
if (fltsignB == 0)
{
*strBP++ = '+';
}
else
{
*strBP++ = '-';
condcodeB = FFNEG;
ffbitclr(fltvalBP, totalenN, (fracbitN + expbitN));
}
*strBP++ = '.';
*(exponeBP + (expbyteN - 1)) = 1;
/* Check the type of floating point number that we have: zero, infinity,
* or Not-A-Number. First check for zero value. */
if (ffchkzero(fltexpBP, expbyteN) == 0)
{
/* The exponent value is zero. Check if the mantissa is also zero.
* First clear the implied most significant mantissa bit. */
ffbitclr(fltfracBP, fracbyteN, fracbitN);
if (ffchkzero(fltfracBP, fracbyteN) == 0)
{
/* The mantissa value is also zero, we have a zero value. */
strcpy((char *) strBP, "0e+0");
FFREE(fltfracBP);
FFREE(fltexpBP);
FFREE(expbiasBP);
FFREE(exponeBP);
return((unsigned char) (condcodeB | FFZERO));
}
/* Set the implied most significant mantissa bit to 1 */
ffbitset(fltfracBP, fracbyteN, fracbitN);
}
/* Having the exponent bias is useful for the next step. */
ffgenbias(expbiasBP, expbyteN, expbitN);
/* Check if the exponent value is set to the maximum possible
* value. This is done by making a copy of the exponent bias,
* shifting it left once, and then setting the least significant
* bit to one. The result is compared with the exponent value. */
tempexpBP = (unsigned char *) FMALLOC(expbyteN, "FLTOSTR5");
for (i = 0; i < expbyteN; i++)
*(tempexpBP + i) = *(expbiasBP + i);
ushftlm(tempexpBP, expbyteN);
*(tempexpBP + expbyteN - 1) |= 1;
if (ucmpm(tempexpBP, fltexpBP, expbyteN) == 0)
{
/* The exponent value is set to its maximum value.
* First clear the implied most significant mantissa bit. */
ffbitclr(fltfracBP, fracbyteN, fracbitN);
if (ffchkzero(fltfracBP, fracbyteN) == 0)
{
/* The mantissa value is zero, we have an Infinite value. */
strcpy((char *) (--strBP), "Infinity");
condcodeB |= FFINF;
}
else
{
/* The mantissa value is non-zero, we have a Not-A-Number. */
strcpy((char *) (--strBP), "Not-A-Number");
condcodeB |= FFNAN;
}
FFREE(fltfracBP);
FFREE(fltexpBP);
FFREE(expbiasBP);
FFREE(exponeBP);
FFREE(tempexpBP);
return(condcodeB);
}
/* Ok floating point value. */
FFREE(tempexpBP);
/* Back to working on the exponent...
* Subtract off exponent bias, note that if the result is negative, the
* sign is properly extended. This is important since it allows
* exponent overflow and underflow to be detected much more easily. */
isubm(fltexpBP, expbiasBP, expbyteN);
/* Convert the power of 2 exponent into an approximate power of 10
* exponent. This is done by converting the exponent value into a float
* and then multiplying it by log10(2). The result is then converter
* back to a integer. */
tempfltBP = (unsigned char *) FMALLOC(SINGLETOT, "FLTOSTR6");
intoflt(fltexpBP, expbyteN, tempfltBP, SINGLEFRAC, SINGLEXP);
fmultm(tempfltBP, log10of2AB, SINGLEXP, SINGLEFRAC);
fltoint(tempfltBP, SINGLEFRAC, SINGLEXP, fltexpBP, expbyteN);
/* Add one to the power of 10 exponent */
iaddm(fltexpBP, exponeBP, expbyteN);
/* Convert the exponent power of ten into a float value */
ptenfltBP = (unsigned char *) FMALLOC(totalenN, "FLTOSTR7");
tempexpBP = (unsigned char *) FMALLOC(expbyteN, "FLTOSTR8");
for (i = 0; i < expbyteN; i++)
*(tempexpBP + i) = *(fltexpBP + i);
ptenccB = intopten(tempexpBP, expbyteN, ptenfltBP, fracbitN, expbitN);
/* Check if either an overflow or underflow occurred. */
if (((ptenccB & FFINF) == FFINF) || ((ptenccB & FFZERO) == FFZERO))
{
if ((ptenccB & FFINF) == FFINF)
{
/* The power of ten is a bit too big... */
isubm(fltexpBP, exponeBP, expbyteN);
}
else
{
/* The power of ten is a bit too small... */
iaddm(fltexpBP, exponeBP, expbyteN);
}
/* Re initialize temporary copy of exponent value, and recalculate
* the modified power of ten. */
for (i = 0; i < expbyteN; i++)
*(tempexpBP + i) = *(fltexpBP + i);
ptenccB = intopten(tempexpBP, expbyteN, ptenfltBP, fracbitN, expbitN);
}
FFREE(tempexpBP);
/* Divide the original float by the power of 10. */
fdivm(fltvalBP, ptenfltBP, expbitN, fracbitN);
/* Check if the result is less than 1/10. First generate
* 1/10 in the desired floating point format. */
onetenthBP = (unsigned char *) FMALLOC(totalenN, "FLTOSTR9");
intopten(&minusoneB, 1, onetenthBP, fracbitN, expbitN);
if ((i = fcmpm(fltvalBP, onetenthBP, expbitN, fracbitN)) < 0)
{
/* If so, divide the result by 1/10 (same as multiplying it by 10)
** and subtract 1 from the power of ten. */
fdivm(fltvalBP, onetenthBP, expbitN, fracbitN);
/* Subtract one from the power of 10 exponent */
isubm(fltexpBP, exponeBP, expbyteN);
}
else if (i == 0)
{
/* The result is equal to 1/10... This is a special boundary
* case that needs to be handled by brute force... */
strcpy((char *) strBP, "1e+1");
FFREE(fltfracBP);
FFREE(fltexpBP);
FFREE(expbiasBP);
FFREE(exponeBP);
FFREE(tempfltBP);
FFREE(ptenfltBP);
FFREE(onetenthBP);
return(condcodeB);
}
/* Check if the result is greater than 1. First generate 1 in the
* desired floating point format. */
oneBP = (unsigned char *) FMALLOC(totalenN, "FLTOSTR10");
intopten(&zeroB, 1, oneBP, fracbitN, expbitN);
if (fcmpm(fltvalBP, oneBP, expbitN, fracbitN) > 0)
{
/* If so, multiply the result by 1/10 and add 1 to the power
* of ten. */
fmultm(fltvalBP, onetenthBP, expbitN, fracbitN);
/* Add one to the power of 10 exponent */
iaddm(fltexpBP, exponeBP, expbyteN);
}
/* At this point, fltvalBP points to a floating point number between 1/10
* and 1. */
/* Convert binary length of the mantissa into decimal digit length.
* This gives the number of significant digits and determines the power
* of then to multiply the mantissa by to convert it to an integer. */
mantlenN = (fracbitN + 1);
/* Convert mantissa bit length from an int to a format compatible with
* two byte integers. */
mantlenBP = (unsigned char *) FMALLOC(2, "FLTOSTR11");
*(mantlenBP+1) = (unsigned char) mantlenN;
*mantlenBP = (unsigned char) (mantlenN >> 8);
/* Now do conversion from binary length to decimal digit length. */
intoflt(mantlenBP, 2, tempfltBP, SINGLEFRAC, SINGLEXP);
fmultm(tempfltBP, log10of2AB, SINGLEXP, SINGLEFRAC);
fltoint(tempfltBP, SINGLEFRAC, SINGLEXP, mantlenBP, 2);
FFREE(tempfltBP);
/* Convert result back to int */
mantlenN = (((unsigned int) (*mantlenBP)) << 8) +
(unsigned int) (*(mantlenBP+1));
mantlenN++;
/* And then back to a two byte integer */
*(mantlenBP+1) = (unsigned char) mantlenN;
*mantlenBP = (unsigned char) (mantlenN >> 8);
/* Calculate appropriate power of ten to multiply mantissa by and
* then multiply it. Convert the result to an int, and then to an
* ASCII string. */
tempfltBP = (unsigned char *) FMALLOC(totalenN, "FLTOSTR12");
intopten(mantlenBP, 2, tempfltBP, fracbitN, expbitN);
fmultm(fltvalBP, tempfltBP, expbitN, fracbitN);
mantlenN = mantlenN >> 1;
mantintBP = (unsigned char *) FMALLOC(mantlenN, "FLTOSTR13");
fltoint(fltvalBP, fracbitN, expbitN, mantintBP, mantlenN);
condcodeB = intostr(mantintBP, mantlenN, strBP, (slenN - 2), 10);
/* Free the temporary buffer for the two byte integer mantissa length */
FFREE(mantlenBP);
/* Add on exponent part */
strBP += strlen((char *) strBP);
slenN -= (2 + strlen((char *) strBP));
*strBP++ = 'e';
/* Determine the exponent sign. */
if (((*(fltexpBP + expbyteN - 1)) & 0x80) != 0x80)
*strBP++ = '+';
condcodeB = intostr(fltexpBP, expbyteN, strBP, slenN, 10);
FFREE(fltfracBP);
FFREE(fltexpBP);
FFREE(expbiasBP);
FFREE(exponeBP);
FFREE(tempfltBP);
FFREE(ptenfltBP);
FFREE(onetenthBP);
FFREE(oneBP);
FFREE(mantintBP);
return(condcodeB);
}
/* Function: unsigned char *intopten(unsigned char *fltexpBP, int expbyteN,
** unsigned char *ptenfltBP, int fracbitN,
** int expbitN)
**
** This function calulates 10 to the integer value pointed to by fltexpBP.
** fltexpBP points to an integer value that is expbyteN bytes long.
**
** The float result is written to the memory buffer pointed to by ptenfltBP.
** fracbitN and expbitN give the number of bits in the floating point's
** mantissa and exponent.
*/
unsigned char
#ifdef PROTOTYPES
intopten(unsigned char *fltexpBP, int expbyteN, unsigned char *ptenfltBP,
int fracbitN, int expbitN)
#else
intopten(fltexpBP, expbyteN, ptenfltBP, fracbitN, expbitN)
unsigned char *fltexpBP;
int expbyteN;
unsigned char *ptenfltBP;
int fracbitN;
int expbitN;
#endif
{
unsigned char condcodeB;
unsigned char *ptenBP;
unsigned char tenB;
unsigned char oneB;
int totalenN;
/* Initialize one and ten values */
oneB = 1;
tenB = 10;
/* Initialize the condition code byte to zero */
condcodeB = 0;
/* Determine the total byte length of the floating point number */
totalenN = fftotlen(expbitN, fracbitN);
/* Allocate space for the power of ten multiplier/divisor and initialize
* it to 10. */
ptenBP = (unsigned char *) FMALLOC(totalenN, "INTOPTEN");
intoflt(&tenB, 1, ptenBP, fracbitN, expbitN);
/* Initialize the result to 1. */
intoflt(&oneB, 1, ptenfltBP, fracbitN, expbitN);
/* Check the sign bit of the exponent */
if (((*fltexpBP) & 0x80) == 0)
{
/* Exponent is positive. Multiply result value by binary power of 10
* for each corresponding bit set in the exponent. Loop until the
* exponent value is zero. */
while (ucheckm(fltexpBP, expbyteN) != 0)
{
/* Check if the least significant bit is one. */
if (((*(fltexpBP + expbyteN - 1)) & 1) != 0)
{
/* If so, multiply in the power of ten. */
condcodeB = fmultm(ptenfltBP, ptenBP, expbitN, fracbitN);
/* Check if an overflow has occurred */
if ((condcodeB & FFINF) == FFINF)
{
FFREE(ptenBP);
return(condcodeB);
}
}
ushftrm(fltexpBP, expbyteN);
/* Generate the next binary power of 10 by squaring the previous
* result. */
fmultm(ptenBP, ptenBP, expbitN, fracbitN);
}
}
else
{
/* Exponent is negative. Change the sign of the exponent value and
* then divide the result value by binary power of 10 for each
* corresponding bit set in the exponent. Loop until the exponent
* value is zero. */
inegm(fltexpBP, expbyteN);
while (ucheckm(fltexpBP, expbyteN) != 0)
{
/* Check if the least significant bit is one. */
if (((*(fltexpBP + expbyteN - 1)) & 1) != 0)
{
/* If so, then divide the previous result by power of ten. */
fdivm(ptenfltBP, ptenBP, expbitN, fracbitN);
/* Check if an underflow has occurred */
if ((condcodeB & FFZERO) == FFZERO)
{
FFREE(ptenBP);
return(condcodeB);
}
}
ushftrm(fltexpBP, expbyteN);
/* Generate the next binary power of 10 by squaring the previous
* result. */
fmultm(ptenBP, ptenBP, expbitN, fracbitN);
}
}
/* Clean up and return. */
FFREE(ptenBP);
return(condcodeB);
}
/* Function: unsigned char *strtoint(char *strBP, int slenN,
** unsigned char *intvalBP, int intlenN,
** int radixN)
**
** This function converts the ASCII number string representation pointed to
** by strBP to a binary integer value. intlenN is the length of the integer
** result in bytes. strBP is the length of the string buffer in bytes.
** radixN is the radix of the input number. Any radix from 2 to 36 is
** valid. Valid input digits are 0 thru (radix - 1). For radixes greater
** than 10, alphabet characters are used starting with 'a'. Upper and lower
** case are treated the same.
*/
unsigned char
#ifdef PROTOTYPES
strtoint(char *strBP, int slenN, unsigned char *intvalBP, int intlenN,
int radixN)
#else
strtoint(strBP, slenN, intvalBP, intlenN, radixN)
char *strBP;
int slenN;
unsigned char *intvalBP;
int intlenN;
int radixN;
#endif
{
unsigned char *radixBP;
unsigned char *indigitBP;
int i;
unsigned char tempB, signB;
unsigned char condcodeB;
condcodeB = 0; /* Assume positive value */
/* Convert the radix value to multiple byte integer format. */
radixBP = FCALLOC(intlenN, 1, "STRTOINT1");
if (radixN > 36) radixN = 36;
if (radixN < 2) radixN = 2;
*(radixBP + intlenN - 1) = (unsigned char)radixN;
/* Get buffer to read each digit into. */
indigitBP = FCALLOC(intlenN, 1, "STRTOINT2");
/* Initialize the output value to zero. */
for (i = 0; i < intlenN; i++)
*(intvalBP + i) = 0;
/* Check for leading +/- character */
tempB = *strBP;
if (tempB == '+')
{
strBP++;
slenN--;
}
else if (tempB == '-')
{
strBP++;
slenN--;
condcodeB = SIGN;
}
/* Loop thru digits until either the end of the string, the output value
* overflows, or a non digit character is encountered. */
while ((slenN-- > 0) && (*strBP != '\0'))
{
/* Convert digits from ASCII to binary. */
tempB = *strBP++;
if ((tempB >= '0') && (tempB <= '9'))
{
tempB -= '0';
}
else if ((tempB >= 'A') && (tempB <= 'Z'))
{
tempB -= ('A' - (char)10);
}
else if ((tempB >= 'a') && (tempB <= 'z'))
{
tempB -= ('a' - (char)10);
}
else
{
FFREE(radixBP);
FFREE(indigitBP);
return(condcodeB);
}
/* If the converted digit is greater than the selected radix, return */
if (tempB >= radixN)
{
FFREE(radixBP);
FFREE(indigitBP);
return(condcodeB);
}
/* Convert the digit value to multiple byte integer format. */
*(indigitBP + intlenN - 1) = (unsigned char) tempB;
/* Multiply the result value by the radix and add in the new digit. */
if (((umultm(intvalBP, radixBP, intlenN) & (OVERFLOW | SIGN)) != 0) ||
((iaddm(intvalBP, indigitBP, intlenN) & OVERFLOW) != 0))
{
/* Overflow has occurred. */
FFREE(radixBP);
FFREE(indigitBP);
if (condcodeB == SIGN)
{
/* Negative overflow, return the most negative possible
* integer. */
if (*strBP == '\0')
{
/* Check if overflow is real, not just due to using
* unsigned arithmetic. Unsigned arithmetic causes
* problems with the minimum negative integer possible. */
for (i = 1; i < intlenN; i++)
{
if (*(intvalBP + i) != 0)
break;
}
if ((i == intlenN) && (*intvalBP == 0x80))
return( SIGN );
}
*intvalBP = 0x80;
for (i = 1; i < intlenN; i++)
*(intvalBP + i) = 0;
}
else
{
/* Positive overflow, return the most positive possible
* integer. */
*intvalBP = 0x7f;
for (i = 1; i < intlenN; i++)
*(intvalBP + i) = 0xff;
}
return((unsigned char) (condcodeB | OVERFLOW));
}
/* Reset the radix value after doing the multiply. */
*(radixBP + intlenN - 1) = (unsigned char)radixN;
}
FFREE(radixBP);
FFREE(indigitBP);
/* Change sign of result if the input value non-zero and was preceeded
* by a '-'. */
if (ucheckm(intvalBP, intlenN) == 0)
return(ZERO);
if ((condcodeB & SIGN) != 0)
inegm(intvalBP, intlenN);
return(condcodeB);
}
/* Function: unsigned char strtoflt(char *strBP, int slenN,
** unsigned char *fltvalBP, int fracbitN,
** int expbitN)
**
** This function converts the decimal ASCII string representation pointed
** to by strBP to a binary floating point value pointed to fltvalBP
** fracbitN is the length of the floating point mantissa in bits. expbitN
** is the length of the floating point exponent in bits. strBP is the
** length of the string buffer in bytes.
*/
unsigned char
#ifdef PROTOTYPES
strtoflt(char *strBP, int slenN, unsigned char *fltvalBP, int fracbitN,
int expbitN)
#else
strtoflt(strBP, slenN, fltvalBP, fracbitN, expbitN)
char *strBP;
int slenN;
unsigned char *fltvalBP;
int fracbitN;
int expbitN;
#endif
{
int i;
unsigned char tempB, signB;
unsigned char dpflagB;
unsigned char *tenBP, *tempBP;
unsigned char tenB;
int totalenN;
int expbyteN;
unsigned char *expintBP;
unsigned char *dpfactorBP;
unsigned char *ptenfltBP;
unsigned char condcodeB;
signB = 0; /* Assume positive value */
dpflagB = 0xff; /* Flag set to 0 when decimal point read in */
tenB = 10; /* Integer value of ten */
/* Initialize the condition code byte to zero */
condcodeB = 0;
/* Determine the total byte length of the floating point number */
totalenN = fftotlen(expbitN, fracbitN);
/* Allocate space for the power of ten multiplier/divisor and initialize
* it to 10. */
tenBP = (unsigned char *) FMALLOC(totalenN, "STRTOFLT1");
intoflt(&tenB, 1, tenBP, fracbitN, expbitN);
/* Initialize the result to 0. */
for (i = 0; i < totalenN; i++)
*(fltvalBP + i) = 0;
/* Check for leading +/- character */
tempB = *strBP;
if (tempB == '+')
{
strBP++;
slenN--;
}
else if (tempB == '-')
{
strBP++;
slenN--;
signB = 1;
condcodeB = FFNEG;
}
/* Loop thru digits until either the end of the string, the output value
* overflows, or a non digit character is encountered. This routine
* handles decimal '.' point characters. */
tempBP = (unsigned char *) FMALLOC(totalenN, "STRTOFLT2");
while ((slenN-- > 0) && (*strBP != '\0'))
{
/* Convert digits from ASCII to binary. */
tempB = *strBP++;
if ((tempB >= '0') && (tempB <= '9'))
{
/* Convert the digit from ASCII to binary. */
tempB -= '0';
/* If a decimal point has been encountered, use the flag to
* count the number of digits behind the decimal point. */
if (dpflagB != 0xff)
dpflagB++;
for (i = 0; i < totalenN; i++)
*(tempBP + i) = *(tenBP + i);
/* Multiply the previous result by 10, note that if the previous
* result overflows, then return an overflow. This should be
* a rather rare occurence, since even for single precision, the
* mantissa must more than 38 digits long! */
if ((fmultm(fltvalBP, tempBP, expbitN, fracbitN) & FFINF) != 0)
{
FFREE(tempBP);
FFREE(tenBP);
return((unsigned char) (condcodeB | FFINF));
}
/* Convert the digit to a float. */
intoflt(&tempB, 1, tempBP, fracbitN, expbitN);
/* Add the digit into the result */
if ((faddm(fltvalBP, tempBP, expbitN, fracbitN ) & FFINF) != 0)
{
FFREE(tempBP);
FFREE(tenBP);
return((unsigned char) (condcodeB | FFINF));
}
}
else if (tempB == '.')
dpflagB = 0; /* Flag we have hit the dec. pt. */
else if ((tempB == 'e') || (tempB == 'E'))
break; /* Done with mantissa */
else
{
FFREE(tempBP);
FFREE(tenBP);
return(condcodeB);
}
}
if (dpflagB == 0xff)
dpflagB = 0; /* Reset dec. pt. flag for no adjustment. */
/* The ASCII mantissa has been read in. Note that the above routine
* continue to multiply the previous mantissa value by 10, even for
* digits behind the decimal point. As a result, the mantissa value
* in fltvalPB probably too big. If so, it is too big by a factor
* of 10^(dpflagB). For now, read in the exponent (if any) first.
* The "decimal point" factor will be included when the exponent power
* of ten is multiplied in. (dbflagB will be subtracted from the value
* of the exponent read in. */
/* Determine the number of bytes required to hold the exponent.
* Allocate space for it and zero it it. */
expbyteN = ffexplen(expbitN);
expintBP = (unsigned char *) FCALLOC(expbyteN, 1, "STRTOFLT3");
if ((slenN > 0) && (*strBP != '\0'))
{
strtoint(strBP, slenN--, expintBP, expbyteN, 10);
}
/* The ASCII exponent has been read in (if any). Include the mantissa
* decimal point factor in the exponent. */
dpfactorBP = (unsigned char *) FCALLOC(expbyteN, 1, "STRTOFLT4");
*(dpfactorBP + expbyteN - 1) = dpflagB;
/* It is highly possible that the exponent value with the decimal point
* factor subtracted off will result in an underflow, yet the entire
* number is a valid floating point number. */
if ((isubm(expintBP, dpfactorBP, expbyteN) & SIGN) != 0)
{
/* The exponent is negative, and an underflow is possible. To
* avoid an unecessary underflow, divide the exponent value by
* two first, and then multiply the two halves into the mantissa
* value, one after the other. If an underflow occurs then, it
* is legitimate.
*
* Check if the exponent is odd, if so, then multiply the mantissa
* by 10 first. */
if ((*(expintBP + (expbyteN - 1)) & 1) != 0)
fmultm(fltvalBP, tenBP, expbitN, fracbitN);
/* Now divide the negative exponent by two. */
ushftrm(expintBP, expbyteN);
/* Remember to set the sign bit... */
*expintBP |= 0x80;
/* Convert the power of 10 exponent (divided by two) into a binary
* floating point value. */
ptenfltBP = (unsigned char *) FMALLOC(totalenN, "STRTOFLT5");
intopten(expintBP, expbyteN, ptenfltBP, fracbitN, expbitN);
/* Multiply the exponent float value times the mantissa float
* value to get a partial result. */
fmultm(fltvalBP, ptenfltBP, expbitN, fracbitN);
}
else
{
/* The exponent is positive, convert the power of 10 exponent into
* a binary floating point value. */
ptenfltBP = (unsigned char *) FMALLOC(totalenN, "STRTOFLT6");
condcodeB =
intopten(expintBP, expbyteN, ptenfltBP, fracbitN, expbitN);
}
if ((condcodeB & FFINF) == 0)
{
/* Multiply the exponent float value times the mantissa float value
* to get the final result, only if there has been no overflow. */
condcodeB = fmultm(fltvalBP, ptenfltBP, expbitN, fracbitN);
}
/* Set the sign bit if necessary. */
if (signB != 0)
{
ffbitset(fltvalBP, totalenN, (fracbitN + expbitN));
condcodeB |= FFNEG;
}
FFREE(ptenfltBP);
FFREE(dpfactorBP);
FFREE(expintBP);
FFREE(tempBP);
FFREE(tenBP);
return(condcodeB);
}