- Add wxVector::assign() (Jonas Rydberg).
- Add wx[F]File{Input,Output}Stream::GetFile() (troelsk).
- Add wxSocketBase::GetSocket() (Laurent Poujoulat).
+- Add IEEE 754 single/double precision support to wxDataStream classes (net147).
- Add Nepali translation (Him Prasad Gautam).
All (GUI):
@itemdef{wxUSE_ARTPROVIDER_STD, Use standard low quality icons in wxArtProvider.}
@itemdef{wxUSE_ARTPROVIDER_TANGO, Use Tango icons in wxArtProvider.}
@itemdef{wxUSE_ANY, Use wxAny class.}
-@itemdef{wxUSE_APPLE_IEEE, IEEE Extended to/from double routines; see src/common/extended.c file.}
+@itemdef{wxUSE_APPLE_IEEE, IEEE Extended to/from double routines, see wxDataOutputStream.}
@itemdef{wxUSE_ARCHIVE_STREAMS, Enable streams for archive formats.}
@itemdef{wxUSE_AUI, Use AUI (dockable windows) library.}
@itemdef{wxUSE_BASE64, Enables Base64 support.}
public:
void BigEndianOrdered(bool be_order) { m_be_order = be_order; }
+ // By default we use extended precision (80 bit) format for both float and
+ // doubles. Call this function to switch to alternative representation in
+ // which IEEE 754 single precision (32 bits) is used for floats and double
+ // precision (64 bits) is used for doubles.
+ void UseBasicPrecisions()
+ {
+#if !wxUSE_APPLE_IEEE
+ m_useExtendedPrecision = false;
+#endif // !wxUSE_APPLE_IEEE
+ }
+
+ // UseExtendedPrecision() is not very useful as it corresponds to the
+ // default value, only call it in your code if you want the compilation
+ // fail with the error when using wxWidgets library compiled without
+ // extended precision support.
+#if wxUSE_APPLE_IEEE
+ void UseExtendedPrecision()
+ {
+ m_useExtendedPrecision = true;
+ }
+#endif // wxUSE_APPLE_IEEE
+
#if wxUSE_UNICODE
void SetConv( const wxMBConv &conv );
wxMBConv *GetConv() const { return m_conv; }
bool m_be_order;
+#if wxUSE_APPLE_IEEE
+ bool m_useExtendedPrecision;
+#endif // wxUSE_APPLE_IEEE
+
#if wxUSE_UNICODE
wxMBConv *m_conv;
#endif
wxUint16 Read16();
wxUint8 Read8();
double ReadDouble();
+ float ReadFloat();
wxString ReadString();
#if wxHAS_INT64
void Read16(wxUint16 *buffer, size_t size);
void Read8(wxUint8 *buffer, size_t size);
void ReadDouble(double *buffer, size_t size);
+ void ReadFloat(float *buffer, size_t size);
wxDataInputStream& operator>>(wxString& s);
wxDataInputStream& operator>>(wxInt8& c);
void Write16(wxUint16 i);
void Write8(wxUint8 i);
void WriteDouble(double d);
+ void WriteFloat(float f);
void WriteString(const wxString& string);
#if wxHAS_INT64
void Write16(const wxUint16 *buffer, size_t size);
void Write8(const wxUint8 *buffer, size_t size);
void WriteDouble(const double *buffer, size_t size);
+ void WriteFloat(const float *buffer, size_t size);
wxDataOutputStream& operator<<(const wxString& string);
wxDataOutputStream& operator<<(wxInt8 c);
@class wxDataOutputStream
This class provides functions that write binary data types in a portable
- way. Data can be written in either big-endian or little-endian format,
- little-endian being the default on all architectures.
+ way.
+
+ Data can be written in either big-endian or little-endian format,
+ little-endian being the default on all architectures but BigEndianOrdered()
+ can be used to change this. The default format for the floating point types
+ is 80 bit "extended precision" unless @c wxUSE_APPLE_IEEE was turned off
+ during the library compilation, in which case extended precision is not
+ available at all. You can call UseBasicPrecisions() to change this and
+ use the standard IEEE 754 32 bit single precision format for floats and
+ standard 64 bit double precision format for doubles. This is recommended
+ for the new code for better interoperability with other software that
+ typically uses standard IEEE 754 formats for its data, the use of extended
+ precision by default is solely due to backwards compatibility.
If you want to write data to text files (or streams) use wxTextOutputStream
instead.
*/
void SetConv( const wxMBConv &conv );
+ /**
+ Disables the use of extended precision format for floating point
+ numbers.
+
+ This method disables the use of 80 bit extended precision format for
+ the @c float and @c double values written to the stream, which is used
+ by default (unless @c wxUSE_APPLE_IEEE was set to @c 0 when building
+ the library, in which case the extended format support is not available
+ at all and this function does nothing).
+
+ After calling it, @c float values will be written out in one of IEEE
+ 754 "basic formats", i.e. 32 bit single precision format for floats and
+ 64 bit double precision format for doubles.
+
+ @since 2.9.5
+ */
+ void UseBasicPrecisions();
+
+ /**
+ Explicitly request the use of extended precision for floating point
+ numbers.
+
+ This function allows the application code to explicitly request the use
+ of 80 bit extended precision format for the floating point numbers.
+ This is the case by default but using this function explicitly ensures
+ that the compilation of code relying on producing the output stream
+ using extended precision would fail when using a version of wxWidgets
+ compiled with @c wxUSE_APPLE_IEEE==0 and so not supporting this format
+ at all.
+
+ @since 2.9.5
+ */
+ void UseExtendedPrecision();
+
/**
Writes the single byte @a i8 to the stream.
*/
void Write64(const wxUint64* buffer, size_t size);
/**
- Writes the double @a d to the stream using the IEEE format.
+ Writes the float @a f to the stream.
+
+ If UseBasicPrecisions() had been called, the value is written out using
+ the standard IEEE 754 32 bit single precision format. Otherwise, this
+ method uses the same format as WriteDouble(), i.e. 80 bit extended
+ precision representation.
+
+ @since 2.9.5
+ */
+ void WriteFloat(float f);
+
+ /**
+ Writes an array of float to the stream. The number of floats to write is
+ specified by the @a size variable.
+
+ @since 2.9.5
+ */
+ void WriteFloat(const float* buffer, size_t size);
+
+ /**
+ Writes the double @a d to the stream.
+
+ The output format is either 80 bit extended precision or, if
+ UseBasicPrecisions() had been called, standard IEEE 754 64 bit double
+ precision.
*/
void WriteDouble(double d);
+
/**
Writes an array of double to the stream. The number of doubles to write is
specified by the @a size variable.
@class wxDataInputStream
This class provides functions that read binary data types in a portable
- way. Data can be read in either big-endian or little-endian format,
- little-endian being the default on all architectures.
+ way.
+
+ Please see wxDataOutputStream for the discussion of the format expected by
+ this stream on input, notably for the floating point values.
If you want to read data from text files (or streams) use wxTextInputStream
instead.
void Read64(wxUint64* buffer, size_t size);
/**
- Reads a double (IEEE encoded) from the stream.
+ Reads a float from the stream.
+
+ Notice that if UseBasicPrecisions() hadn't been called, this function
+ simply reads a double and truncates it to float as by default the same
+ (80 bit extended precision) representation is used for both float and
+ double values.
+
+ @since 2.9.5
+ */
+ float ReadFloat();
+
+ /**
+ Reads float data from the stream in a specified buffer.
+
+ The number of floats to read is specified by the @a size variable.
+
+ @since 2.9.5
+ */
+ void ReadFloat(float* buffer, size_t size);
+
+ /**
+ Reads a double from the stream.
+
+ The expected format is either 80 bit extended precision or, if
+ UseBasicPrecisions() had been called, standard IEEE 754 64 bit double
+ precision.
*/
double ReadDouble();
+
/**
- Reads double data (IEEE encoded) from the stream in a specified buffer.
+ Reads double data from the stream in a specified buffer.
The number of doubles to read is specified by the @a size variable.
*/
Sets the text conversion class used for reading strings.
*/
void SetConv( const wxMBConv &conv );
+
+ /**
+ Disables the use of extended precision format for floating point
+ numbers.
+
+ This method disables the use of 80 bit extended precision format for
+ the @c float and @c double values read from the stream, which is used
+ by default (unless @c wxUSE_APPLE_IEEE was set to @c 0 when building
+ the library, in which case the extended format support is not available
+ at all and this function does nothing).
+
+ After calling it, @c float values will be expected to appear in one of
+ IEEE 754 "basic formats", i.e. 32 bit single precision format for
+ floats and 64 bit double precision format for doubles in the input.
+
+ @since 2.9.5
+ */
+ void UseBasicPrecisions();
+
+ /**
+ Explicitly request the use of extended precision for floating point
+ numbers.
+
+ This function allows the application code to explicitly request the use
+ of 80 bit extended precision format for the floating point numbers.
+ This is the case by default but using this function explicitly ensures
+ that the compilation of code relying on reading the input containing
+ numbers in extended precision format would fail when using a version of
+ wxWidgets compiled with @c wxUSE_APPLE_IEEE==0 and so not supporting
+ this format at all.
+
+ @since 2.9.5
+ */
+ void UseExtendedPrecision();
};
#include "wx/math.h"
#endif //WX_PRECOMP
+namespace
+{
+
+// helper unions used to swap bytes of floats and doubles
+union Float32Data
+{
+ wxFloat32 f;
+ wxUint32 i;
+};
+
+union Float64Data
+{
+ wxFloat64 f;
+ wxUint32 i[2];
+};
+
+} // anonymous namespace
+
// ----------------------------------------------------------------------------
// wxDataStreamBase
// ----------------------------------------------------------------------------
wxUnusedVar(conv);
m_be_order = false;
+
+ // For compatibility with the existing data files, we use extended
+ // precision if it is available, i.e. if wxUSE_APPLE_IEEE is on.
+#if wxUSE_APPLE_IEEE
+ m_useExtendedPrecision = true;
+#endif // wxUSE_APPLE_IEEE
}
#if wxUSE_UNICODE
double wxDataInputStream::ReadDouble()
{
#if wxUSE_APPLE_IEEE
- char buf[10];
+ if ( m_useExtendedPrecision )
+ {
+ char buf[10];
- m_input->Read(buf, 10);
- return wxConvertFromIeeeExtended((const wxInt8 *)buf);
-#else
- return 0.0;
-#endif
+ m_input->Read(buf, 10);
+ return wxConvertFromIeeeExtended((const wxInt8 *)buf);
+ }
+ else
+#endif // wxUSE_APPLE_IEEE
+ {
+ Float64Data floatData;
+
+ if ( m_be_order == (wxBYTE_ORDER == wxBIG_ENDIAN) )
+ {
+ floatData.i[0] = Read32();
+ floatData.i[1] = Read32();
+ }
+ else
+ {
+ floatData.i[1] = Read32();
+ floatData.i[0] = Read32();
+ }
+
+ return static_cast<double>(floatData.f);
+ }
+}
+
+float wxDataInputStream::ReadFloat()
+{
+#if wxUSE_APPLE_IEEE
+ if ( m_useExtendedPrecision )
+ {
+ return (float)ReadDouble();
+ }
+ else
+#endif // wxUSE_APPLE_IEEE
+ {
+ Float32Data floatData;
+
+ floatData.i = Read32();
+ return static_cast<float>(floatData.f);
+ }
}
wxString wxDataInputStream::ReadString()
}
}
+void wxDataInputStream::ReadFloat(float *buffer, size_t size)
+{
+ for (wxUint32 i=0; i<size; i++)
+ {
+ *(buffer++) = ReadFloat();
+ }
+}
+
wxDataInputStream& wxDataInputStream::operator>>(wxString& s)
{
s = ReadString();
wxDataInputStream& wxDataInputStream::operator>>(float& f)
{
- f = (float)ReadDouble();
+ f = ReadFloat();
return *this;
}
void wxDataOutputStream::WriteDouble(double d)
{
- char buf[10];
+#if wxUSE_APPLE_IEEE
+ if ( m_useExtendedPrecision )
+ {
+ char buf[10];
+
+ wxConvertToIeeeExtended(d, (wxInt8 *)buf);
+ m_output->Write(buf, 10);
+ }
+ else
+#endif // wxUSE_APPLE_IEEE
+ {
+ Float64Data floatData;
+ floatData.f = (wxFloat64)d;
+
+ if ( m_be_order == (wxBYTE_ORDER == wxBIG_ENDIAN) )
+ {
+ Write32(floatData.i[0]);
+ Write32(floatData.i[1]);
+ }
+ else
+ {
+ Write32(floatData.i[1]);
+ Write32(floatData.i[0]);
+ }
+ }
+}
+
+void wxDataOutputStream::WriteFloat(float f)
+{
#if wxUSE_APPLE_IEEE
- wxConvertToIeeeExtended(d, (wxInt8 *)buf);
-#else
- wxUnusedVar(d);
-#if !defined(__VMS__) && !defined(__GNUG__)
-#ifdef _MSC_VER
-# pragma message("wxDataOutputStream::WriteDouble() not using IeeeExtended - will not work!")
-#else
-# pragma warning "wxDataOutputStream::WriteDouble() not using IeeeExtended - will not work!"
-#endif
-#endif
- buf[0] = '\0';
-#endif
- m_output->Write(buf, 10);
+ if ( m_useExtendedPrecision )
+ {
+ WriteDouble((double)f);
+ }
+ else
+#endif // wxUSE_APPLE_IEEE
+ {
+ Float32Data floatData;
+
+ floatData.f = (wxFloat32)f;
+ Write32(floatData.i);
+ }
}
#if wxHAS_INT64
}
}
+void wxDataOutputStream::WriteFloat(const float *buffer, size_t size)
+{
+ for (wxUint32 i=0; i<size; i++)
+ {
+ WriteFloat(*(buffer++));
+ }
+}
+
wxDataOutputStream& wxDataOutputStream::operator<<(const wxString& string)
{
WriteString(string);
wxDataOutputStream& wxDataOutputStream::operator<<(float f)
{
- WriteDouble((double)f);
+ WriteFloat(f);
return *this;
}
CPPUNIT_TEST( PseudoTest_UseBigEndian );
CPPUNIT_TEST( FloatRW );
CPPUNIT_TEST( DoubleRW );
+ // Only test standard IEEE 754 formats if we're using IEEE extended
+ // format by default, otherwise the tests above already covered them.
+#if wxUSE_APPLE_IEEE
+ CPPUNIT_TEST( PseudoTest_UseIEEE754 );
+ CPPUNIT_TEST( FloatRW );
+ CPPUNIT_TEST( DoubleRW );
+ // Also retest little endian version with standard formats.
+ CPPUNIT_TEST( PseudoTest_UseLittleEndian );
+ CPPUNIT_TEST( FloatRW );
+ CPPUNIT_TEST( DoubleRW );
+#endif // wxUSE_APPLE_IEEE
CPPUNIT_TEST_SUITE_END();
wxFloat64 TestFloatRW(wxFloat64 fValue);
void NaNRW();
void PseudoTest_UseBigEndian() { ms_useBigEndianFormat = true; }
+ void PseudoTest_UseLittleEndian() { ms_useBigEndianFormat = false; }
+#if wxUSE_APPLE_IEEE
+ void PseudoTest_UseIEEE754() { ms_useIEEE754 = true; }
+#endif // wxUSE_APPLE_IEEE
static bool ms_useBigEndianFormat;
+#if wxUSE_APPLE_IEEE
+ static bool ms_useIEEE754;
+#endif // wxUSE_APPLE_IEEE
DECLARE_NO_COPY_CLASS(DataStreamTestCase)
};
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( DataStreamTestCase, "DataStreamTestCase" );
bool DataStreamTestCase::ms_useBigEndianFormat = false;
+#if wxUSE_APPLE_IEEE
+bool DataStreamTestCase::ms_useIEEE754 = false;
+#endif // wxUSE_APPLE_IEEE
DataStreamTestCase::DataStreamTestCase()
{
if ( ms_useBigEndianFormat )
pDataOutput.BigEndianOrdered(true);
+#if wxUSE_APPLE_IEEE
+ if ( ms_useIEEE754 )
+ pDataOutput.UseBasicPrecisions();
+#endif // wxUSE_APPLE_IEEE
+
pDataOutput << fValue;
}
if ( ms_useBigEndianFormat )
pDataInput.BigEndianOrdered(true);
+#if wxUSE_APPLE_IEEE
+ if ( ms_useIEEE754 )
+ pDataInput.UseBasicPrecisions();
+#endif // wxUSE_APPLE_IEEE
+
wxFloat64 fInFloat;
pDataInput >> fInFloat;