# 把一个IEEE754浮点数转换为IBM370浮点数的C#代码

        // http://en.wikipedia.org/wiki/IBM_Floating_Point_Architecture
// float2ibm(-118.625F) == 0xC276A000
// 1 100 0010    0111 0110 1010 0000 0000 0000
// IBM/370 single precision, 4 bytes
// xxxx.xxxx xxxx.xxxx xxxx.xxxx xxxx.xxxx
// s|-exp--| |--------fraction-----------|
//    (7)          (24)
// value = (-1)**s * 16**(e - 64) * .f   range = 5E-79 ... 7E+75
static int float2ibm(float from)
{
byte[] bytes = BitConverter.GetBytes(from);
int fconv = (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8)| bytes[0];

if (fconv == 0) return 0;
int fmant = (0x007fffff & fconv) | 0x00800000;
int t = (int)((0x7f800000 & fconv) >> 23) - 126;
while (0 != (t & 0x3)) { ++t; fmant >>= 1; }
fconv = (int)(0x80000000 & fconv) | (((t >> 2) + 64) << 24) | fmant;
return fconv; // big endian order
}

/* Assumes sizeof(int) == 4 */
static void float_to_ibm(int from[], int to[], int n, int endian)
/**********************************************************************
float_to_ibm - convert between 32 bit IBM and IEEE floating numbers
***********************************************************************
Input:
from       input vector
n          number of floats in vectors
endian     =0 for little endian machine, =1 for big endian machines

Output:
to         output vector, can be same as input vector

***********************************************************************
Notes:
Up to 3 bits lost on IEEE -> IBM

IBM -> IEEE may overflow or underflow, taken care of by
substituting large number or zero

Only integer shifting and masking are used.
***********************************************************************
Credits:     CWP: Brian Sumner
***********************************************************************/
{
register int fconv, fmant, i, t;

for (i=0;i<n;++i) {
fconv = from[i];
if (fconv) {
fmant = (0x007fffff & fconv) | 0x00800000;
t = (int) ((0x7f800000 & fconv) >> 23) - 126;
while (t & 0x3) { ++t; fmant >>= 1; }
fconv = (0x80000000 & fconv) | (((t>>2) + 64) << 24) | fmant;
}
if(endian==0)
fconv = (fconv<<24) | ((fconv>>24)&0xff) |
((fconv&0xff00)<<8) | ((fconv&0xff0000)>>8);

to[i] = fconv;
}
return;

}

#include "ibmieee.h"

/*---------------------------------------------------------------------
*
*   FILE: ./ibmieee.c
*
*----------------------------------------------------------------------
*
*   DESCRIPTION:
*     Conversion from IBM to IEEE format
*     Byte order is detected and accounted for using
*     define constant 'L_ENDIAN'
*
*----------------------------------------------------------------------
*   ROUTINES DEFINED IN THIS MODULE:
*----------------------------------------------------------------------
*
*
*  Convert IBM to IEEE integer:
*
*   ibm_ieee_i( n, ibm, ieee)
*   int n;
*   int *ibm;
*   int *ieee;
*
*  Convert IEEE to IBM integer:
*
*   ieee_ibm_i( n, ieee, ibm)
*   int n;
*   int *ieee;
*   int *ibm;
*
*  Convert IBM to IEEE short floating point:
*
*   ibm_ieee_f( n, ibm, ieee)
*   int n;
*   char *ibm;
*   float *ieee;
*
*  Convert IEEE to IBM floating point:
*
*   ieee_ibm_f( n, ieee, ibm)
*   int n;
*   float *ieee;
*   char *ibm;
*
*---------------------------------------------------------------------*/

void ibm_ieee_i( int n, char *ibm, char *ieee )
/*
Convert from IBM to IEEE integer, possibly in-place
*/
#ifdef L_ENDIAN
{
int j;
char temp;

/* Reverse byte order on little endian machines */
for (j=0; j<4*n; j+=4) {
temp=ibm[j];
ieee[j]=ibm[j+3];
ieee[j+3]=temp;
temp=ibm[j+1];
ieee[j+1]=ibm[j+2];
ieee[j+2]=temp;
}

#else

{
int j;

/* Move words if not same location */

if (ibm != ieee)
for (j=0; j<n; j++)
ieee[j] = ibm[j];

#endif /* L_ENDIAN */

return ;

}

/*********************************************************************/

void ieee_ibm_i( int n, char *ibm, char *ieee )
/*
Convert from IEEE to IBM integer, possibly in-place
*/

#ifdef L_ENDIAN
{
int j;
char temp;

/* Reverse byte order on little endian machines */
for (j=0; j<4*n; j+=4) {
temp=ieee[j];
ibm[j]=ieee[j+3];
ibm[j+3]=temp;
temp=ieee[j+1];
ibm[j+1]=ieee[j+2];
ibm[j+2]=temp;
}

#else
{
int j;

/* Move words if not same location */

if (ibm != ieee)
for (j=0; j<n; j++)
ibm[j] = ieee[j];

#endif /* L_ENDIAN */
return ;

}

/*---------------------------------------------------------------------
*
*  Convert from IBM short real to IEEE short real
*
*
*  Bit formats for Big Endian processors (i.e. 68020, SPARC, RS6000):
*
*              0         1        2        3         Byte Offset
*          --------------------------------------
*  IBM     !S! EXP   !   MH   !   MM   !   ML   !
*          --------------------------------------
*           0 1     7 8     15 16    23 24    31     bit number
*
*              0         1        2        3         Byte Offset
*          --------------------------------------
*  IEEE    !S! EXP    !  MH   !   MM   !   ML   !
*          --------------------------------------
*           0 1      8 9    15 16    23 24    31     bit number
*
*
*  Bit formats for Little Endian processors (i.e. Intel 80x86):
*
*              3         2        1        0         byte offset
*          --------------------------------------
*  IBM     !   ML   !   MH   !   MH   !S!  EXP  !
*          --------------------------------------
*           31    24 23    16 15     8 7 6     0     bit number
*
*              3         2        1        0         byte offset
*          --------------------------------------
*  IEEE    !S!  EXP  !!  MH   !   MM   !   ML   !
*          --------------------------------------
*          31 30    23 22   16 15     8 7      0     bit number
*
*
*  ML, MM, and MH refer to the low, middle, and high order mantissa
*  bytes.  S is the sign bit, EXP is the exponent.  Bits and bytes
*  are numbered in order of increasing address in memory.  The fields
*  are shown in the order that a Hex constant in C would be used as
*  a mask for accessing bits.
*
*
* A floating point number in the IBM format is defined to be:
*
*      (sign) 0.(significand) * 16**(exponent-64)
*
* In the IEEE format, a floating point number is:
*
*      (sign) 1.(significand) * 2**(exponent-127)
*
* The differences are:
*
*       1. IBM assumes a 0 to left of decimal point,
*          IEEE assumes a 1 to left of decimal point.
*          Since the IBM format has 1 more bit for the significand,
*          they both have the same precision: 24 binary digits.
*
*       2. The base for the exponent is 16 for IBM, 2 for IEEE
*
*       3. The bias for the exponent is 64 for IBM, 127 for IEEE
*
*       4. The exponent is 7 bits for IBM, 8 for IEEE. The exponent
*          range is then -64 to +63 for IBM, -127 to +128 for IEEE.
*
*       5. Since the IBM format has base 16, the decimal exponent
*          range for IBM is about twice that for IEEE:
*          IBM:  0.1H * 16**(-64)  to  0.FFFFFFH * 16**(+63)
*            =   5.4 * 10**(-79)   to   7.2 * 10**(+75)
*          IEEE: 1.0H * 2**(-127)  to  1.FFFFFFH * 2**(+128)
*            =   5.9 * 10**(-39)   to   6.8 * 10**(+38)
*
* To convert IBM to IEEE:
*
*       1. Multiply IBM exponent by 4 to convert base from 16 to 2,
*          subtract 129 to adjust for difference in bias (16*4-127).
*
*       2. Shift the IBM significand left 1 bit and subtract 1 from
*          the exponent. If the significand MSB is still 0, repeat.
*
*       3. If the exponent overflows, set result to +-infinity. If
*          it underflows, set to +-zero.
*
*       4. Move the converted sign, significand, and exponent into
*          the appropriate fields for the IEEE format.
*
*
* To convert IEEE to IBM:
*
*       1. Get IEEE mantissa (bits 0-22). OR in a 1 in bit 23 to
*          account for assumed leading '1'.
*
*       2. Get IEEE exponent.  Add 1 to exponent to place the decimal
*          point before the '1' in the mantissa.  Subtract IEEE bias
*          of 127 to yield true base 2 exponent.
*
*       3. Divide IEEE exponent by 4 to convert to base 16 exponent:
*            0.X * 2**Y = 0.X * 16**(Y/4)
*          Save remainder from division.  If remainder is not zero:
*            0.X * 16**(I+1/4) = 2*(0.X) * 16**I = (1/8)0.X * 16**(I+1)
*            0.X * 16**(I+2/4) = 4*(0.X) * 16**I = (1/4)0.X * 16**(I+1)
*            0.X * 16**(I+3/4) = 8*(0.X) * 16**I = (1/2)0.X * 16**(I+1)
*          I.E., add 1 to exponent, shift mantissa right by
*          (4 - remainder).  Add IBM bias of 64 to exponent.
*
*       4. Move the converted sign, significand, and exponent into
*          the appropriate fields for the IBM format.
*
*
*---------------------------------------------------------------------*/

void  ibm_ieee_f( int n, VAL *ibm, VAL *ieee )

{
int i,iret;
VAL tmp1,tmp2,temp;
int exp;

iret = 0;

for (i=0; i<n; i++) {

/* Move IBM word to properly aligned temp location */
temp.c[0] = ibm[i].c[0];
temp.c[1] = ibm[i].c[1];
temp.c[2] = ibm[i].c[2];
temp.c[3] = ibm[i].c[3];

/* check for true zero */
if (temp.u == 0) {
ieee[i].c[0] = ieee[i].c[1] = ieee[i].c[2] =
ieee[i].c[3] = '\0';
continue;
}
/* extract mantissa */
#ifdef L_ENDIAN
tmp1.c[0] = temp.c[3];
tmp1.c[1] = temp.c[2];
tmp1.c[2] = temp.c[1];
tmp1.c[3] = '\0';
#else
tmp1.u = temp.u;
tmp1.c[0] = '\0';
#endif

/* Extract exponent */
/* remove sign bit, multiply by 4, subtract bias difference */
exp = ((temp.c[0] & 0x7F) << 2 ) - 129;

/* Shift mantissa up 1 bit until there is a 1 in the MSB */
while ( (tmp1.u & 0x800000) == 0 ) {
exp--;
tmp1.u = tmp1.u << 1;
};
/* Discard MSB and decrement exponent 1 more */
tmp1.u = tmp1.u & 0x007FFFFF;
exp--;

/* Check for exponent overflow or underflow */
if (exp & 0xFF00) {
if (exp < 0)
/* Underflow */
ieee[i].c[0] = ieee[i].c[1] = ieee[i].c[2] =
ieee[i].c[3] = '\0';
else {
/* Overflow */
#ifdef L_ENDIAN
ieee[i].c[3] = 0x7F;
ieee[i].c[2] = 0x80;
ieee[i].c[1] = 0x00;
ieee[i].c[0] = 0x00;
#else
ieee[i].c[0] = 0x7F;
ieee[i].c[1] = 0x80;
ieee[i].c[2] = 0x00;
ieee[i].c[3] = 0x00;
#endif
}
iret = 1;
continue;
}

/* Move exponent into proper field and set sign bit */
tmp2.u = 0;
#ifdef L_ENDIAN
tmp2.c[3] = (char)exp;
tmp2.u = tmp2.u >> 1;
if (temp.u & 0x00000080)
tmp2.u = tmp2.u | 0x80000000;
else
tmp2.u = tmp2.u & 0x7fffffff;
#else
tmp2.c[0] = (char)exp;
tmp2.u = tmp2.u >> 1;
tmp2.u = tmp2.u | (temp.u & 0x80000000);
#endif
/* Set output value */
temp.u = tmp1.u | tmp2.u;
ieee[i].c[0] = temp.c[0];
ieee[i].c[1] = temp.c[1];
ieee[i].c[2] = temp.c[2];
ieee[i].c[3] = temp.c[3];
}
return ;
}

/*********************************************************************/

void    ieee_ibm_f( int n, VAL *ieee, VAL *ibm )

{
int i;
VAL temp,tmp1,tmp2;
int exp,rem;

for (i=0; i<n; i++) {

/* Move to properly aligned location */
temp.c[0] = ieee[i].c[0];
temp.c[1] = ieee[i].c[1];
temp.c[2] = ieee[i].c[2];
temp.c[3] = ieee[i].c[3];
/* check for true zero */
if (temp.u == 0) {
ibm[i].c[0] = ibm[i].c[1] = ibm[i].c[2] =
ibm[i].c[3] = '\0';
continue;
}
/* extract mantissa, OR in leading '1' */
tmp1.u = (temp.u & 0x007FFFFF) | 0x00800000;

/* Extract exponent */
/* remove sign bit, shift up one bit */
tmp2.u = (temp.u & 0x7F800000) << 1;
/* Add 1 for mantissa shift, subtract 127 for IEEE bias */
#ifdef L_ENDIAN
exp = (unsigned)tmp2.c[3] - 126;
#else
exp = (unsigned)tmp2.c[0] - 126;
#endif

/* Divide exponent by 4, save remainder, add IBM bias of 64 */
rem = exp & 0x03;
exp = (exp >> 2) + 64;
/* Normalize mantissa by shifting by (4-remainder) */
if (rem) {
tmp1.u = tmp1.u >> (4-rem);
exp = exp + 1;
}

/* Move exponent and mantissa bytes into IBM locations */
#ifdef L_ENDIAN
tmp2.u = 0;
tmp2.c[0] = (char)exp;
tmp2.c[1] = tmp1.c[2];
tmp2.c[2] = tmp1.c[1];
tmp2.c[3] = tmp1.c[0];
/* Set sign bit */
if (temp.u & 0x80000000) tmp2.u = tmp2.u | 0x00000080;
#else
tmp2.u = tmp1.u;
tmp2.c[0] = (char)exp;
/* Set sign bit */
if (temp.u & 0x80000000) tmp2.u = tmp2.u | 0x80000000;
#endif

/* Set output value */
ibm[i].c[0] = tmp2.c[0];
ibm[i].c[1] = tmp2.c[1];
ibm[i].c[2] = tmp2.c[2];
ibm[i].c[3] = tmp2.c[3];
}
return ;
} 
posted @ 2013-10-11 10:00  申龙斌的程序人生  阅读(2573)  评论(0编辑  收藏  举报