/* * LIBML library - read, write and manipulate MATLAB MAT-files * Copyright (C) 1994 Michael J. Maurer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Michael Maurer * Durand Bldg - Room 232 * Stanford, CA 94305-4055 * (415) 723-1024 */ static char rcsid[]="$Id: ivcvt.c,v 1.1 1993/08/25 21:38:43 maurer Exp maurer $"; /****************************************************************************** ivcvt.c Function: Convert between IEEE-954 and VAX floating point formats. These routines currently only support IEEE Short, IEEE Long, VAX-F and VAX-D types. Summary of floating point data types: IEEE IEEE IEEE Short Long Temp VAX-F VAX-D VAX-G VAX-H ------------------------------------------------------ Total bits 32 64 80 32 64 64 128 Significant Digits 7 15 19 7 16 15 33 Exponent Bits 8 11 15 8 8 11 15 Exponent Bias 127 1023 16383 129 129 1025 16385 Mantissa Bits 23 52 64 23 55 53 112(?) Maximum Magnitude 3.4e38 1.8e308 1.7e38 1.7e38 Minimum Magnitude (Normal) 1.2e-38 2.2e-308 2.9e-39 2.9e-39 Minimum Magnitude (Denormal) 1.4e-45 4.9e-324 ------ ------ ******************************************************************************/ /* $Log: ivcvt.c,v $ * Revision 1.1 1993/08/25 21:38:43 maurer * Fixed byte order bug in d_vax2ieee(). * Added comments, changed (signed) to (int). * * Revision 1.0 1993/08/02 00:55:51 maurer * Initial revision * */ /****************************************************************************** swapb_2 Swap bytes in every 2-byte object, from order 12 to order 21. Converts n such 2-byte objects. ******************************************************************************/ void swapb_2(unsigned char *src, unsigned char *dst, unsigned int n) { unsigned char t; while (n-- > 0) { t = *src++; *dst++ = *src++; *dst++ = t; } } /****************************************************************************** swapb_4 Swap bytes in every 4-byte object, from order 1234 to 4321. Converts n such 4-byte objects. ******************************************************************************/ void swapb_4(unsigned char *src, unsigned char *dst, unsigned int n) { unsigned char t1, t2, t3; while (n-- > 0) { t1 = *src++; t2 = *src++; t3 = *src++; *dst++ = *src++; *dst++ = t3; *dst++ = t2; *dst++ = t1; } } /****************************************************************************** swapb_8 Swap bytes in every 8-byte object, from order 12345678 to 87654321. Converts n such 8-byte objects. ******************************************************************************/ void swapb_8(unsigned char *src, unsigned char *dst, unsigned int n) { unsigned char t1, t2, t3, t4, t5, t6, t7; while (n-- > 0) { t1 = *src++; t2 = *src++; t3 = *src++; t4 = *src++; t5 = *src++; t6 = *src++; t7 = *src++; *dst++ = *src++; *dst++ = t7; *dst++ = t6; *dst++ = t5; *dst++ = t4; *dst++ = t3; *dst++ = t2; *dst++ = t1; } } /****************************************************************************** f_vax2ieee Suggested prototype: void f_vax2ieee(void *src, void *dst, unsigned int n); Converts n VAX-F floating point numbers to IEEE-954 short floats. The VAX bytes are stored in order 2143, and IEEE bytes are stored in order 1234. Values within the range of both representations are converted exactly. Very small VAX values (|x| < 1.17e-38) will lose some precision and are converted to denormal IEEE floats. The largest possible VAX value (+-1.70e38) is converted to +-Infinity, even though this number can be represented exactly in the IEEE format (this preserves round-trip conversion of Infinities). VAX reserved operands are converted to quiet NaNs. Some improvement in speed (about 35%) would be possible at the expense of readability. ******************************************************************************/ void f_vax2ieee(unsigned char *src, unsigned char *dst, unsigned int n) { unsigned long s,e,m,f; for (; n>0; n--,src+=4,dst+=4) { s = src[1] & 0x80; e = ((src[1] & 0x7F) << 1) | ((src[0] & 0x80) >> 7); m = ((src[0] & 0x7F) << 16) | (src[3] << 8) | src[2]; if (e==0) { /* special value? */ if (s==0) { /* zero */ m = 0; } else { /* reserved op */ s = 0; e = 0xFF; /* NaN */ m |= 1<<22; /* set msb==1: quiet */ } } else if (e==1) { /* underflow */ e = 0; /* denormal */ m >>= 2; /* account for smaller exp */ m |= 1<<21; /* shift in hidden bit */ } else if (e==2) { /* underflow */ e = 0; /* denormal */ m >>= 1; /* account for smaller exp */ m |= 1<<22; /* shift in hidden bit */ } else if (e==0xFF && m==0x7FFFFF) { /* largest vax number */ m = 0; /* return +/- Infinity, even though number is representable */ } else /* regular number */ e -= 2; f = (s << 24) | (e << 23) | m; dst[0] = f >> 24; dst[1] = (f >> 16) & 0xFF; dst[2] = (f >> 8 ) & 0xFF; dst[3] = f & 0xFF; } } /****************************************************************************** f_ieee2vax Suggested prototype: void f_ieee2vax(void *src, void *dst, unsigned int n); Converts n IEEE-954 short floats to VAX-F format. The IEEE bytes are stored in order 1234, and VAX bytes are stored in order 2143. Values within the range of both representations are converted exactly. Infinities and numbers too large to be represented in VAX-F are converted to the largest available VAX-F number (+-1.70e38). Denormal numbers too small to be represented (|x| < 2.94e-39) are converted to zero. All NaNs are converted to VAX-F reserved operands. Some improvement in speed (about 35%) would be possible at the expense of readability. ******************************************************************************/ void f_ieee2vax(unsigned char *src, unsigned char *dst, unsigned int n) { unsigned long s,e,m,f; for (; n>0; n--,src+=4,dst+=4) { s = src[0] & 0x80; e = ((src[0] & 0x7F) << 1) | ((src[1] & 0x80) >> 7); m = ((src[1] & 0x7F) << 16) | (src[2] << 8) | src[3]; if (e==0xFF) { /* special value */ if (m==0) { /* infinity */ m = 0x7FFFFF; /* return largest vax value */ } else { /* NaN */ s = 1; /* return reserved op */ e = 0; } } else if (e==0xFE) { /* overflow */ e = 0xFF; m = 0x7FFFFF; /* return largest vax value */ } else if (e==0) { /* zero or denormal */ if (m==0) /* zero */ s = 0; else { /* denormal: try to represent */ if (m & (1<<22)) { m <<= 1; m &= 0x7FFFFF; e = 2; } else if (m & (1<<21)) { m <<= 2; m &= 0x7FFFFF; e = 1; } else /* we can't represent it */ s = 0; /* return zero */ } } else /* regular number */ e += 2; f = (s << 24) | (e << 23) | m; dst[1] = f >> 24; dst[0] = (f >> 16) & 0xFF; dst[3] = (f >> 8 ) & 0xFF; dst[2] = f & 0xFF; } } /****************************************************************************** d_vax2ieee Suggested prototype: void d_vax2ieee(void *src, void *dst, unsigned int n); Converts n VAX-D floating point numbers to IEEE-954 long floats. The VAX bytes are stored in order 21436587, and IEEE bytes are stored in order 12345678. Some precision is lost for all values, as the last three bits of the VAX mantissa are truncated. The largest possible VAX value (+-1.70e38) is converted to +-Infinity, even though this number can easily be represented in the IEEE format (this preserves round-trip conversion of Infinities). VAX reserved operands are converted to quiet NaNs. Some improvement in speed (about 35%) would be possible at the expense of readability. ******************************************************************************/ void d_vax2ieee(unsigned char *src, unsigned char *dst, unsigned int n) { unsigned long s,e,mu,ml,f; for (; n>0; n--,src+=8,dst+=8) { s = src[1] & 0x80; e = ((src[1] & 0x7F) << 1) | ((src[0] & 0x80) >> 7); mu = ((src[0] & 0x7F) << 16) | (src[3] << 8) | src[2]; ml = (src[5] << 24) | (src[4] << 16) | (src[7] << 8) | src[6]; if (e==0) { /* special value? */ if (s==0) { /* zero */ mu = ml = 0; } else { /* reserved op */ s = 0; e = 0x7FF; /* NaN */ mu = 1<<19; /* msb==1: quiet */ ml = 0; } } else if (e==0xFF && mu==0x007FFFFF && ml==0xFFFFFFFF) { /* largest VAX value */ e = 0x7FF; mu = ml = 0; /* return +-Infinity, even though we could represent */ } else { /* regular number */ e += (1023 - 129); ml >>= 3; /* IEEE has 3 fewer bits in m */ ml |= mu << 29; mu >>= 3; } f = (s << 24) | (e << 20) | mu; dst[0] = f >> 24; dst[1] = (f >> 16) & 0xFF; dst[2] = (f >> 8 ) & 0xFF; dst[3] = f & 0xFF; dst[4] = ml >> 24; dst[5] = (ml >> 16) & 0xFF; dst[6] = (ml >> 8 ) & 0xFF; dst[7] = ml & 0xFF; } } /****************************************************************************** d_ieee2vax Suggested prototype: void d_ieee2vax(void *src, void *dst, unsigned int n); Converts n IEEE-954 long floats to VAX-D format. The IEEE bytes are stored in order 12345678, and VAX bytes are stored in order 21436587. Values within the range of both representations are converted exactly. Infinities and numbers too large to be represented in VAX-F are converted to the largest available VAX-F number (+-1.70e38). Numbers too small to be represented (|x| < 2.94e-39) are converted to zero. All NaNs are converted to VAX-D reserved operands. Some improvement in speed (about 35%) would be possible at the expense of readability. ******************************************************************************/ void d_ieee2vax(unsigned char *src, unsigned char *dst, unsigned int n) { unsigned long s,e,mu,ml,f; for (; n>0; n--,src+=8,dst+=8) { s = src[0] & 0x80; e = ((src[0] & 0x7F) << 4) | ((src[1] & 0xF0) >> 4); mu = ((src[1] & 0x0F) << 16) | (src[2] << 8) | src[3]; ml = (src[4] << 24) | (src[5] << 16) | (src[6] << 8) | src[7]; if (e==0x7FF) { /* special value */ if (mu==0 && ml==0) { /* infinity */ e = 0xFF; /* return largest vax value */ mu = 0x007FFFFF; ml = 0xFFFFFFFF; } else { /* NaN */ s = 1; /* return reserved op */ e = 0; } } else if ((int)e-(1023-129)<=0) { /* underflow */ s = e = 0; } else if ((int)e-(1023-129)>0xFF) { /* overflow */ e = 0xFF; mu = 0x007FFFFF; /* return largest vax value */ ml = 0xFFFFFFFF; } else { /* regular number */ e -= (1023 - 129); mu <<= 3; mu |= ml >> 29; ml <<= 3; } f = (s << 24) | (e << 23) | mu; dst[1] = f >> 24; dst[0] = (f >> 16) & 0xFF; dst[3] = (f >> 8 ) & 0xFF; dst[2] = f & 0xFF; dst[5] = ml >> 24; dst[4] = (ml >> 16) & 0xFF; dst[7] = (ml >> 8 ) & 0xFF; dst[6] = ml & 0xFF; } }