zoukankan      html  css  js  c++  java
  • 把一个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] = ''; 
          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] = ''; 
    #else 
        tmp1.u = temp.u; 
        tmp1.c[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] = ''; 
          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] = ''; 
          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 ; 
        } 
  • 相关阅读:
    关于二进制——lowbit运算
    代码风格
    焦作区域赛——反思及期望
    第一次参加acm区域赛
    0——1分数问题规划
    [FZYZOJ 1339] 修改密码
    [HDU 1856] More is better
    并查集小结
    [FZYZOJ 1031] 无线网络
    [FZYZOJ 1038] 隧道
  • 原文地址:https://www.cnblogs.com/speeding/p/3362769.html
Copyright © 2011-2022 走看看