📄 ibmieee.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 ; } /*********************************************************************//* Fortran interfaces */ void ibm2iei_( int *n, char *ibm, char *ieee ) { ibm_ieee_i( *n, ibm, ieee ); } void ie2ibmi_( int *n, char *ieee, char *ibm ) { ieee_ibm_i( *n, ieee, ibm ); } void ibm2ief_(int *n, char *ibm, char *ieee ) { ibm_ieee_f( *n, (VAL *)ibm, (VAL *)ieee ); } void ie2ibmf_( int *n, char *ieee, char *ibm ) { ieee_ibm_f( *n, (VAL *)ieee, (VAL *)ibm ); } void ibm_ieee_float(void *ibm, void *ieee, int n) { ibm_ieee_f( n, (VAL *)ibm, (VAL *)ieee ); } void ieee_ibm_float(void *ieee, void *ibm, int n) { ieee_ibm_f( n, (VAL *)ieee, (VAL *)ibm ); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -