IEEEFloat32.cpp

Go to the documentation of this file.
00001 
00015 #include <algorithm>
00016 #include <cmath>
00017 #include <sstream>
00018 
00019 #include <dlrNumeric/IEEEFloat32.h>
00020 
00021 namespace dlr {
00022 
00023   namespace numeric {
00024     
00025     // Default constructor initializes to 0.0;
00026     IEEEFloat32::
00027     IEEEFloat32()
00028       : m_value(),
00029         m_bytes()
00030     {
00031       this->checkTypes();
00032       this->setValue(0.0);
00033     }
00034 
00035 
00036     // This constructor initializes the IEEEFloat32 instance to the value
00037     // specified by its argument.
00038     IEEEFloat32::
00039     IEEEFloat32(FloatType value)
00040       : m_value(),
00041         m_bytes()
00042     {
00043       this->checkTypes();
00044       this->setValue(value);
00045     }
00046 
00047 
00048     // This constructor initializes the IEEEFloat32 instance using its
00049     // 32 bit binary representation.
00050     IEEEFloat32::
00051     IEEEFloat32(unsigned char byte0,
00052                 unsigned char byte1,
00053                 unsigned char byte2,
00054                 unsigned char byte3)
00055       : m_value(),
00056         m_bytes()
00057     {
00058       this->checkTypes();
00059       this->setValue(byte0, byte1, byte2, byte3);
00060     }
00061 
00062 
00063     // This is the copy constructor.  It deep copies its argument.
00064     IEEEFloat32::
00065     IEEEFloat32(const IEEEFloat32& source)
00066       : m_value(source.m_value),
00067         m_bytes()
00068     {
00069       std::copy(&(source.m_bytes[0]), &(source.m_bytes[0]) + 4, &(m_bytes[0]));
00070     }
00071 
00072 
00073     // This member function returns the requested 8 bits byte from the
00074     // IEEE floating point representation.
00075     unsigned char
00076     IEEEFloat32::
00077     getByte(size_t index0)
00078     {
00079       // Check argument.
00080       if(index0 >= 4) {
00081         std::ostringstream message;
00082         message << "Index value, " << index0 << ", is out of bounds.";
00083         DLR_THROW(IndexException, "IEEEFloat32::getByte(size_t)",
00084                   message.str().c_str());
00085       }
00086       return m_bytes[index0];
00087     }
00088 
00089 
00090     // This member function sets the IEEEFloat32 instance to the value
00091     // specified by its argument.
00092     void
00093     IEEEFloat32::
00094     setValue(FloatType value)
00095     {
00096       // Copy the input argument.
00097       m_value = value;
00098 
00099       // Handle special cases.
00100       // Note that this || is redundant.  x == 0.0 should imply x == -0.0.
00101       if((value == 0.0) || (value == -0.0)) {
00102         m_bytes[0] = 0x00;
00103         m_bytes[1] = 0x00;
00104         m_bytes[2] = 0x00;
00105         m_bytes[3] = 0x00;
00106       } else {
00107         // Do the conversion.
00108         this->floatToBinary(
00109           value, m_bytes[0], m_bytes[1], m_bytes[2], m_bytes[3]);
00110       }
00111     }
00112 
00113 
00114     // This member function sets the IEEEFloat32 instance using the
00115     // 32 bit binary representation.
00116     void
00117     IEEEFloat32::
00118     setValue(unsigned char byte0,
00119              unsigned char byte1,
00120              unsigned char byte2,
00121              unsigned char byte3)
00122     {
00123       // Remember the input arguments.
00124       m_bytes[0] = byte0;
00125       m_bytes[1] = byte1;
00126       m_bytes[2] = byte2;
00127       m_bytes[3] = byte3;
00128 
00129       // Handle special cases.
00130       if((byte0 == 0x00)
00131          && (byte1 == 0x00)
00132          && (byte2 == 0x00)
00133          && (byte3 == 0x00)) {
00134         m_value = 0.0;
00135       } else if((byte0 == 0x80)
00136                 && (byte1 == 0x00)
00137                 && (byte2 == 0x00)
00138                 && (byte3 == 0x00)) {
00139         // Treat -0.0 just like 0.0.
00140         m_bytes[0] = 0x00;
00141         m_value = 0.0;
00142       } else {
00143         // Do the conversion.
00144         this->binaryToFloat(byte0, byte1, byte2, byte3, m_value);
00145       }
00146     }
00147 
00148     
00149 
00150     // This private member function implements the actual conversion
00151     // from binary representation to float.
00152     void
00153     IEEEFloat32::
00154     binaryToFloat(unsigned char byte0,
00155                   unsigned char byte1,
00156                   unsigned char byte2,
00157                   unsigned char byte3,
00158                   IEEEFloat32::FloatType& value)
00159     {
00160       // Start by calculating the mantissa using an int.  We'll divide
00161       // by 2^23 later.  Remember that the 2^0 bit is set by the IEEE
00162       // floating point definition.
00163       int mantissaByte0 = static_cast<int>(byte1 | 0x80);
00164       int mantissaByte1 = static_cast<int>(byte2);
00165       int mantissaByte2 = static_cast<int>(byte3);
00166       int mantissaAsInt =
00167         (mantissaByte0 << 16) | (mantissaByte1 << 8) | mantissaByte2;
00168 
00169       // Now include the sign.
00170       if(byte0 & 0x80) {
00171         mantissaAsInt *= -1;
00172       }
00173 
00174       // Recover the exponent.
00175       int exponentByte0 = static_cast<int>(byte0 & 0x7f);
00176       int exponentByte1 = static_cast<int>(byte1 & 0x80);
00177       int exponentAsInt = (exponentByte0 << 1) | (exponentByte1 >> 7);
00178       // Remember that IEEE format requires us to offset the exponent.
00179       exponentAsInt -= 127;
00180 
00181       // Now convert to floating point.  Hope that FloatType has enough
00182       // precision to do this without roundoff errors (true as long as
00183       // FloatType has at least as many bits as IEEE 32 bit float for both
00184       // exponent and mantissa).  We explicitly divide by 2^23 (rather
00185       // than simply subtracting 23 from the exponent) in case the local
00186       // representation of FloatType has only 8 exponent bits.
00187       FloatType mantissa =
00188         static_cast<FloatType>(mantissaAsInt)
00189         / static_cast<FloatType>(std::pow(2.0, 23.0));
00190       value = mantissa * static_cast<FloatType>(
00191         std::pow(2.0, static_cast<double>(exponentAsInt)));
00192     }
00193 
00194 
00195 
00196     // This private member function verifies that the compiler
00197     // built-in types have sufficient precision to implement the math
00198     // in this class.
00199     void
00200     IEEEFloat32::
00201     checkTypes()
00202     {
00203       if(sizeof(FloatType) < 4) {
00204         DLR_THROW(RunTimeException, "IEEEFloat32::checkTypes()",
00205                   "FloatType has insufficient precision.");
00206       }
00207 
00208       // Probably need some more checking here.
00209     }
00210   
00211   
00212     // This private member function implements the actual conversion
00213     // from float to binary representation.
00214     void
00215     IEEEFloat32::
00216     floatToBinary(FloatType value,
00217                   unsigned char& byte0,
00218                   unsigned char& byte1,
00219                   unsigned char& byte2,
00220                   unsigned char& byte3)
00221     {
00222       // Extract the sign bit.
00223       if(value < 0.0) {
00224         byte0 = 0x80;
00225         value *= -1;
00226       } else {
00227         byte0 = 0x00;
00228       }
00229 
00230       // Extract the exponent.
00231       int exponentAsInt = 0;
00232       while(value >= 2.0) {
00233         value /= 2.0;
00234         exponentAsInt += 1;
00235       }
00236       while(value < 1.0) {
00237         value *= 2.0;
00238         exponentAsInt -= 1;
00239       }
00240 
00241       // Remember the offset required by IEEE format.
00242       exponentAsInt += 127;
00243     
00244       // Now we know the mantissa (it's what's left in value).
00245       int mantissaAsInt = static_cast<int>(value * pow(2.0, 23));
00246 
00247       // Go ahead and assign the bytes.
00248       byte0 |= ((exponentAsInt & 0xfe) >> 1);
00249       byte1 = ((exponentAsInt & 0x01) << 7) | ((mantissaAsInt & 0x7f0000) >> 16);
00250       byte2 = ((mantissaAsInt & 0x00ff00) >> 8);
00251       byte3 = (mantissaAsInt & 0x0000ff);
00252     }
00253 
00254   } // namespace numeric
00255 
00256 } // namespace dlr

Generated on Wed Nov 25 00:42:42 2009 for dlrUtilities Utility Library by  doxygen 1.5.8