home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
MAGAZINE
/
DDJ9309.ZIP
/
FPALIB.ZIP
/
FFMLIB.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-12
|
20KB
|
677 lines
/* Extended IEEE Compatible Floating Point Arithmetic Library
**
** Version 1.0
** Copyright (C) 1990, by Fred Motteler
** All Rights Reserved
**
** Floating point support routines. The routines below are used only
** by the floating point routines.
*/
#include <stdio.h>
#ifndef MWC
#include <stdlib.h>
#endif
#include "imlib.h"
#include "ffmlib.h"
#include "fmlib.h"
/*
** Function: unsigned char ffchkzero(unsigned char *resultPB, int totalenN)
**
** Check if the floating point value is zero. If so, then return zero.
** Otherwise return a non-zero value. Note that this routine works only
** if the floating point number has a length that is a byte multiple.
** (8, 16, 24, ... bits in length) or if the floating point number is
** padded with zeros out to the next byte boundary.
*/
unsigned char
#ifdef PROTOTYPES
ffchkzero(unsigned char *resultPB, int totalenN)
#else
ffchkzero(resultPB, totalenN)
unsigned char *resultPB;
int totalenN;
#endif
{
int i;
unsigned char bitorB;
bitorB = 0;
for (i = 0; i < totalenN; i++)
bitorB |= (*(resultPB + i));
return(bitorB);
}
/*
** Function: unsigned char ffexpchk(unsigned char *prodexpPB, int expbyteN,
** unsigned char *expbiasPB, int expbitN,
** unsigned char expccB );
**
** This function checks for exponent overflow (or underflow).
**
** Note that the integer addition/subtraction routines only catch overflows
** if the exponent size is a multiple of a byte, i.e.: 8, 16, 24, ...
** This routine catchs overflows when the exponent size is not a multiple
** of a byte.
*/
unsigned char
#ifdef PROTOTYPES
ffexpchk(unsigned char *prodexpPB, int expbyteN, unsigned char *expbiasPB,
int expbitN, unsigned char expccB)
#else
ffexpchk(prodexpPB, expbyteN, expbiasPB, expbitN, expccB)
unsigned char *prodexpPB;
int expbyteN;
unsigned char *expbiasPB;
int expbitN;
unsigned char expccB;
#endif
{
unsigned char *tempexpPB;
unsigned char tempccB;
int i;
/* Check if exponent size is a multiple of a byte. Return if so, since
* the integer add/subtract routine will have properly caught the
* overflow condition. */
if ((expbitN % 8) == 0)
return (expccB);
/* The exponent size is such that there are "extra" bits in the array
* used to keep the exponent. These extra bits prevent the integer
* add/subtract routine from catching the overflow condition. As
* a result, the overflow must be explicitly checked for. Initially
* allocate space for temporary results and initialize with the
* exponent value to test. */
tempexpPB = (unsigned char *) FMALLOC(expbyteN, "FFEXPCHK");
for (i = 0; i < expbyteN; i++)
*(tempexpPB + i) = *(prodexpPB + i);
/* Use the SIGN bit to determine if the resulting exponent was positive
* or negative. The SIGN bit should be valid in all cases since the
* sign bit is automatically extended by the integer add/subtract
* routines. Also note that the proper sign bits were initially
* generated when the exponent bias was subtracted off. */
if (expccB & SIGN)
{
/* Result is negative, check if it is less than the negative of
* the exponent bias. This is done by adding the exponent bias
* to the value and checking if the result is still negative. */
tempccB = iaddm(tempexpPB, expbiasPB, expbyteN);
if ((tempccB & SIGN) != 0)
expccB |= OVERFLOW;
}
else
{
/* Result is positive, check if it is greater than the exponent
* bias. This is done by subtracting the exponent bias and checking
* if the result is still positive. */
tempccB = isubm(tempexpPB, expbiasPB, expbyteN);
if ((tempccB & SIGN) == 0)
expccB |= OVERFLOW;
}
FFREE(tempexpPB);
return (expccB);
}
/*
** Function: unsigned char ffexpover(unsigned char *resultPB, int totalenN,
** unsigned char expccB,
** unsigned char *expbiasPB, int expbyteN,
** unsigned char *exponePB,
** unsigned char condcodeB, int fracbitN,
** int expbitN);
**
** This is a rather specialized function to deal with the overflow or
** underflow condition. Depending on the state of the "expccB" condition
** codes, either an overflow or underflow is assumed to have occurred. If
** an overflow has occurred, then infinity is written out to the result
** pointed to by resultPB. If an underflow has occurred, then zero is written
** out to the result. In either case, a modified version of the condition
** codes (initially in condcodeB) is returned.
**
** Note that the value of the exponent bias is modified to be be "all one's"
** in the exponent field.
*/
unsigned char
#ifdef PROTOTYPES
ffexpover(unsigned char *resultPB, int totalenN, unsigned char expccB,
unsigned char *expbiasPB, int expbyteN, unsigned char *exponePB,
unsigned char condcodeB, int fracbitN, int expbitN)
#else
ffexpover(resultPB, totalenN, expccB, expbiasPB, expbyteN, exponePB, condcodeB,
fracbitN, expbitN)
unsigned char *resultPB;
int totalenN;
unsigned char expccB;
unsigned char *expbiasPB;
int expbyteN;
unsigned char *exponePB;
unsigned char condcodeB;
int fracbitN;
int expbitN;
#endif
{
int i;
/* We have either a floating point overflow or underflow.
* Initially zero the result. */
for (i = 0; i < totalenN; i++)
*(resultPB + i) = 0;
/* Check for overflow or underflow. Note that when an over/underflow
* occurs, the sign of the result is opposite the expected result if no
* over/underflow had occurred. */
if ((expccB & SIGN) == 0)
{
/* We have floating point underflow, leave the result zero,
* and set the zero condition code. */
condcodeB |= FFZERO;
return(condcodeB);
}
/* We have floating point overflow, write out infinity. This
* requires setting the exponent to its maximum value. The
* maximum value is equal to twice the exponent bias plus 1. */
ushftlm(expbiasPB, expbyteN);
iaddm(expbiasPB, exponePB, expbyteN);
/* Stuff the maximum exponent value into the result field. */
ffbitins(expbiasPB, expbyteN, fracbitN, expbitN, resultPB, totalenN);
condcodeB |= FFINF;
return(condcodeB);
}
/*
** Function: unsigned char ffsetsign(unsigned char signoneB,
** unsigned char signtwoB,
** unsigned char *resultPB, int totalenN,
** int signposN, unsigned char condcodeB)
**
** This is a rather specialized function that sets the sign bit (if
** appropriate) in the result value pointed to by resultPB.
*/
unsigned char
#ifdef PROTOTYPES
ffsetsign(unsigned char signoneB, unsigned char signtwoB,
unsigned char *resultPB, int totalenN, int signposN,
unsigned char condcodeB)
#else
ffsetsign(signoneB, signtwoB, resultPB, totalenN, signposN, condcodeB)
unsigned char signoneB, signtwoB;
unsigned char *resultPB;
int totalenN;
int signposN;
unsigned char condcodeB;
#endif
{
if (signoneB == signtwoB)
{
/* pos. result if original signs the same */
ffbitclr(resultPB, totalenN, signposN);
}
else
{
/* neg. result if original signs different */
ffbitset(resultPB, totalenN, signposN);
condcodeB |= FFNEG;
}
return(condcodeB);
}
/*
** Function: void ffbitext(unsigned char *srcPB, int srclenN, int sbitN,
** int bitlenN, unsigned char *destPB, int destlenN)
**
** Extract a bit field from the source location to the destination.
**
** srcPB points to the first byte of
** the source.
** |
** |ssssssss|ssssssss|ssssssss|ssssssss|
** | |
** |---------------|
** | sbitN gives the starting bit of
** | the source field (starting with
** | ls bit of the last byte of the
** | source. (sbitN = 0 as shown.)
** |
** bitlenN gives the length of the source
** field in bits. (bitlenN = 23 as shown.)
**
** destPB points to the last byte of the destination.
**
** NOTE:
** 1) destlenN must be greater than or equal to (bitlenN >> 3) + 1.
** No explicit checking of lengths is done.
** 2) destPB and srcPB point to the first byte of the source and
** destination bit field arrays, but are immediately convertered to
** pointers that point to the LAST (least significant) byte of
** source and destination bit field arrays!!! This is totally unlike
** normal usage, but is required since bit fields are always
** referenced relative to the least significant bit.
*/
void
#ifdef PROTOTYPES
ffbitext(unsigned char *srcPB, int srclenN, int sbitN, int bitlenN,
unsigned char *destPB, int destlenN)
#else
ffbitext(srcPB, srclenN, sbitN, bitlenN, destPB, destlenN)
unsigned char *srcPB;
int srclenN;
int sbitN;
int bitlenN;
unsigned char *destPB;
int destlenN;
#endif
{
int stbyteN, stbitN, tranlenN, i;
int endbyteN, endbitN;
int clearbitN;
unsigned char *tempbufPB;
unsigned char *tempptrPB;
/* Convert the source pointer from most significant
* byte pointer format to least signficant byte pointer format. */
srcPB += (srclenN - 1);
/* Determine where the start bit is located at. */
stbyteN = sbitN >> 3;
stbitN = sbitN & 0x7;
/* Determine where the end bit is located at. Note that if bitlenN
* is 1, then the start and end bit are the same bit. */
endbyteN = (sbitN + bitlenN - 1) >> 3;
endbitN = (sbitN + bitlenN - 1) & 0x7;
/* Point at byte containing bit. */
srcPB -= stbyteN;
/* Determine the number of bytes to copy to destination. Note that
* things can get tricky if the start bit is not the least significant
* bit of the start byte, and the most significant bit is also not
* on a byte boundary. */
tranlenN = endbyteN - stbyteN + 1;
/* Allocate a temporary buffer for working on the value. Initialize
* working point one byte past where it would normally go. The
* reason for going one byte past is that the exract routine can
* go one byte too far in some circumstances. */
tempbufPB = (unsigned char *) FCALLOC((destlenN + 1), 1, "FFBITEXT");
tempptrPB = tempbufPB + destlenN;
/* Copy source bytes to temporary buffer destination. */
for (i = 0; i < tranlenN; i++)
{
*tempptrPB-- = *srcPB--;
}
tempptrPB++; /* Point to msb of temporary buffer */
/* Figure out how much of the ms bits of the ms byte of the
* destination must be cleared, and then clear it */
clearbitN = (sbitN + bitlenN) % 8;
*tempptrPB &= ffclearmaskAB[clearbitN];
/* Shift the destination bits into the proper place */
for (i = 0; i < stbitN; i++)
ushftrm(tempptrPB, tranlenN);
/* Copy the result from the temporary buffer back into the destination
* buffer. */
tempptrPB = tempbufPB + 1;
for (i = 0; i < destlenN; i++)
*(destPB + i) = *tempptrPB++;
FFREE(tempbufPB);
return;
}
/*
** Function: void ffbitins(unsigned char *srcPB, int srclenN, int dbitN,
** int bitlenN, unsigned char *destPB,
** int destlenN)
**
** Insert a bit field to the destination from the source location.
**
** destPB points to the first byte of
** the destination.
** |
** |dddddddd|dddddddd|dddddddd|dddddddd|
** | |
** |---------------|
** | dbitN gives the starting bit of
** | the destination field (starting
** | with ls bit of the last byte of
** | the destination. (dbitN = 0 as
** | shown.)
** |
** bitlenN gives the length of the destination
** field in bits. (bitlenN = 23 as shown.)
**
** srcPB points to the first byte of the destination.
**
** NOTE:
** 1) destlenN must be greater than or equal to (bitlenN >> 3) + 1.
** No explicit checking of lengths is done.
** 2) destPB and srcPB point to the first (most significant) byte
** of the source and destination bit field arrays, but are
** immediately converted to point to the LAST (least significant)
** byte... This is totally unlike
** normal usage, but is required since bit fields are always
** referenced relative to the least significant bit. (And by doing
** this, these routines don't care how long the actual source and
** destination fields are...)
*/
void
#ifdef PROTOTYPES
ffbitins(unsigned char *srcPB, int srclenN, int dbitN, int bitlenN,
unsigned char *destPB, int destlenN)
#else
ffbitins(srcPB, srclenN, dbitN, bitlenN, destPB, destlenN)
unsigned char *srcPB;
int srclenN;
int dbitN;
int bitlenN;
unsigned char *destPB;
int destlenN;
#endif
{
int stbyteN, stbitN, bitoN, i;
/* Convert the source and destination pointers from most significant
* byte pointer format to least signficant byte pointer format. */
srcPB += (srclenN - 1);
destPB += (destlenN - 1);
/* Determine where the start bit is located at. */
stbyteN = dbitN >> 3;
stbitN = dbitN & 0x7;
/* Point at byte containing first destination bit. */
destPB -= stbyteN;
/* Loop thru the source bits, stuffing one at a time into the destination.
* This is done one at a time so as to not disturb the other bits.
* If there is a better way to do this, let me know!!! */
i = 0; /* Start with low bit of source */
bitoN = 0;
while (i < bitlenN)
{
if ((*srcPB & ffsetmaskAB[bitoN]) == 0)
*destPB &= ffclrmaskAB[stbitN];
else
*destPB |= ffsetmaskAB[stbitN];
i++;
/* Check if at end of current source and destination bytes */
if (bitoN++ == 7)
{
bitoN = 0;
srcPB--;
}
if (stbitN++ == 7)
{
stbitN = 0;
destPB--;
}
}
return;
}
/*
** Function: void ffbitset(unsigned char *srcPB, int srclenN, int nbitN)
**
** Set the "nbitN" of the value pointed to by srcPB.
**
** As with the ffbitext() function above, srcPB points to the FIRST (most
** significant) byte of the value to set the nth bit of.
*/
void
#ifdef PROTOTYPES
ffbitset(unsigned char *srcPB, int srclenN, int nbitN)
#else
ffbitset(srcPB, srclenN, nbitN)
unsigned char *srcPB;
int srclenN;
int nbitN;
#endif
{
int stbyteN, stbitN;
/* Convert the source pointer from most significant
* byte pointer format to least signficant byte pointer format. */
srcPB += (srclenN - 1);
/* Determine where the bit to set is located at. */
stbyteN = nbitN >> 3;
stbitN = nbitN & 0x7;
/* Point at byte containing bit. */
srcPB -= stbyteN;
/* Set the appropriate bit */
*srcPB |= ffsetmaskAB[stbitN];
return;
}
/*
** Function: void ffbitclr(unsigned char *srcPB, int srclenN, int nbitN)
**
** Clear the "nbitN" of the value pointed to by srcPB.
**
** As with the ffbitext() function above, srcPB points to the FIRST (most
** significant) byte of the value to clear the nth bit of.
*/
void
#ifdef PROTOTYPES
ffbitclr(unsigned char *srcPB, int srclenN, int nbitN)
#else
ffbitclr(srcPB, srclenN, nbitN)
unsigned char *srcPB;
int srclenN;
int nbitN;
#endif
{
int stbyteN, stbitN;
/* Convert the source pointer from most significant
* byte pointer format to least signficant byte pointer format. */
srcPB += (srclenN - 1);
/* Determine where the bit to set is located at. */
stbyteN = nbitN >> 3;
stbitN = nbitN & 0x7;
/* Point at byte containing bit. */
srcPB -= stbyteN;
/* Set the appropriate bit */
*srcPB &= ffclrmaskAB[stbitN];
return;
}
/*
** Function: unsigned char fftstbit(unsigned char *srcPB, int srclenN,
** int nbitN )
**
** Test the "nbitN" of the value pointed to by srcPB.
**
** As with the ffbitext() function above, srcPB points to the FIRST (most
** significant) byte of the value to test the nth bit of.
*/
unsigned char
#ifdef PROTOTYPES
fftstbit(unsigned char *srcPB, int srclenN, int nbitN)
#else
fftstbit(srcPB, srclenN, nbitN)
unsigned char *srcPB;
int srclenN;
int nbitN;
#endif
{
int stbyteN, stbitN;
/* Convert the source pointer from most significant
* byte pointer format to least signficant byte pointer format. */
srcPB += (srclenN - 1);
/* Determine where the bit to set is located at. */
stbyteN = nbitN >> 3;
stbitN = nbitN & 0x7;
/* Point at byte containing bit. */
srcPB -= stbyteN;
/* Test the appropriate bit */
if ((*srcPB & ffsetmaskAB[stbitN]) == 0)
return(0);
return(1);
}
/*
** Function: int fftotlen(int expbitN, int fracbitN)
**
** Calculate the total byte length of a floating point number given its
** exponent bit length and its mantissa exponent length.
*/
int
#ifdef PROTOTYPES
fftotlen(int expbitN, int fracbitN)
#else
fftotlen(expbitN, fracbitN)
int expbitN;
int fracbitN;
#endif
{
int totalenN;
totalenN = (((expbitN + fracbitN + 1) % 8) == 0) ? 0 : 1;
totalenN += ((expbitN + fracbitN + 1) >> 3);
return(totalenN);
}
/*
** Function: int ffexplen(int expbitN)
**
** Calculate the total byte length of the exponent field of a floating point
** number given its exponent bit length.
*/
int
#ifdef PROTOTYPES
ffexplen(int expbitN)
#else
ffexplen(expbitN)
int expbitN;
#endif
{
int expbyteN;
expbyteN = ((expbitN % 8) == 0) ? 0 : 1;
expbyteN += (expbitN >> 3);
return(expbyteN);
}
/*
** Function: int ffraclen(int fracbitN)
**
** Calculate the total byte length of the mantissa field of a floating point
** number given its mantissa bit length.
*/
int
#ifdef PROTOTYPES
ffraclen(int fracbitN)
#else
ffraclen(fracbitN)
int fracbitN;
#endif
{
int fracbyteN;
fracbyteN = (((fracbitN + 1) % 8) == 0) ? 0 : 1;
fracbyteN += ((fracbitN + 1) >> 3);
return(fracbyteN);
}
/*
** Function: void ffgenbias(int expbyteN, int expbitN)
**
** Generate exponent bias values.
*/
void
#ifdef PROTOTYPES
ffgenbias(unsigned char *expbiasPB, int expbyteN, int expbitN)
#else
ffgenbias(expbiasPB, expbyteN, expbitN)
unsigned char *expbiasPB;
int expbyteN;
int expbitN;
#endif
{
int i;
*(expbiasPB + (expbyteN - 1)) = 1; /* Set the ls bit to 1 */
for (i = 0; i < (expbitN - 2); i++)
{
ushftlm( expbiasPB, expbyteN );
*(expbiasPB + (expbyteN - 1)) |= 1; /* Set next ls bit to 1 */
}
return;
}
/*
** Function: void ffextall(unsigned char *fltPB, int totalenN,
** int fracbitN, int fracbyteN, int expbitN,
** int expbyteN, unsigned char *fltfracPB,
** unsigned char *fltexpPB,
** unsigned char *fltsignPB)
**
** Extract the mantissa, exponent, and sign from the floating point number
** pointed to by by fltPB.
**
** totalenN gives the total byte length of the floating point number.
**
** fracbitN and fracbyteN give the total bit and byte length of the mantissa
** portion respectively.
**
** expbitN and expbyteN give the total bit and byte length of the exponent
** portion respectively.
**
** fltfracPB, fltexpPB, and fltsignPB point to where the extracted mantissa,
** exponent, and sign values are to be put.
**
** Memory for each extracted value must be allocated prior to calling this
** routine.
*/
void
#ifdef PROTOTYPES
ffextall(unsigned char *fltPB, int totalenN, int fracbitN, int fracbyteN,
int expbitN, int expbyteN, unsigned char *fltfracPB,
unsigned char *fltexpPB, unsigned char *fltsignPB)
#else
ffextall(fltPB, totalenN, fracbitN, fracbyteN, expbitN, expbyteN, fltfracPB,
fltexpPB, fltsignPB)
unsigned char *fltPB;
int totalenN;
int fracbitN;
int fracbyteN;
int expbitN;
int expbyteN;
unsigned char *fltfracPB;
unsigned char *fltexpPB;
unsigned char *fltsignPB;
#endif
{
/* Isolate the mantissa. */
ffbitext(fltPB, totalenN, 0, fracbitN, fltfracPB, fracbyteN);
/* Isolate the exponent. */
ffbitext(fltPB, totalenN, fracbitN, expbitN, fltexpPB, expbyteN);
/* Isolate the sign, note that only one byte is required for this. */
ffbitext(fltPB, totalenN, (fracbitN + expbitN), 1, fltsignPB, 1);
/* Set the implied most significant mantissa bit to 1 */
ffbitset(fltfracPB, fracbyteN, fracbitN);
return;
}