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

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

 

在这个网页上有古老的IBM370浮点格式的说明。

 

image

 

        // 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
        }

 

在这段C代码的基础上修改的

 

/* 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; 

}

 

 

另外找到的一些C代码放在这里以后备用

#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  申龙斌的程序人生  阅读(2543)  评论(0编辑  收藏  举报