www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Comparing double and float values

reply Abid H. Mujtaba <abid.naqvi83 gmail.com> writes:
I am working through "The D Programming Language" by Andrei
Alexandrescu and one of the examples compared an array of doubles
with an array of floats in a unittest (pg. 143 while discussing
function overloading). The unittest failed when I compiled the file
using rdmd. I simplified the problem and the following code will not
compile:

// Code in file test.d

unittest
{
   double x = 3.2 ;
   float y = 3.2 ;

   assert( x == y ) ;
}

Running 'rdmd --main -unittest test.d' results in:

core.exception.AssertError test(6): unittest failure
May 12 2011
parent reply Alexander <aldem+dmars nk7.net> writes:
On 12.05.2011 10:03, Abid H. Mujtaba wrote:

 unittest
 {
    double x = 3.2 ;
    float y = 3.2 ;
 
    assert( x == y ) ;
 }

Quite OK, IMHO: x-y = -4.76837e-08 Just regular rounding error, and we are comparing values stored with different precision. Float values quite rarely can store *exact* values. /Alexander
May 12 2011
next sibling parent reply Matthew Ong <ongbp yahoo.com> writes:
Hi Alexander,

Is there anyway to ensure the comparison of float/double to be done with the raw
bits like in Java
Double.doubleToRawLongBits(double value)

http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Double.html#doubleToRawLongBits%28double%29

when it comes to financial data and percentage computation, that seems to be
rather important.

Thanks in advance.

Matthew Ong
May 12 2011
next sibling parent Matthew Ong <ongbp yahoo.com> writes:
Hi jen,

If you really want to to compare bit by bit it should be possible to
cast the floating point values and then perform the comparison.

Please see the URL:
http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Double.html#doubleToRawLongBits%28double%29

Casting does that looses the value decimal point value?

The most important
Returns a representation of the specified floating-point value according to the
IEEE 754 floating-point "double format" bit layout, preserving Not-a-Number
(NaN)
values.

underneath the source code, it is just C code:

union {
    double dval;
    long lval;
}

They fill dval to get lval and vs.

That is important if u use that for searching within a Hashtable like:

double[string] myvals; // look for the key string using double?
May 12 2011
prev sibling next sibling parent reply Alexander <aldem+dmars nk7.net> writes:
On 12.05.2011 12:08, Matthew Ong wrote:

 Is there anyway to ensure the comparison of float/double to be done with the
raw
 bits like in Java
 Double.doubleToRawLongBits(double value)

The problem is that not every decimal value may be stored with the same bits in float or double, again, due to rounding and other errors. Try it for yourself: http://babbage.cs.qc.edu/IEEE-754/Decimal.html Sure, for simple cases, when no operations are performed and values are simply stored, doubles/floats *may* be sufficient, but anything more important - and errors will accumulate very quickly.
 when it comes to financial data and percentage computation, that seems to be
rather important.

When it comes to financial data, where you really need *exact* calculations within given precision, forget about standard floating point formats. Instead, you should use something like http://www.mpfr.org/#intro - with exact and guaranteed precision. Alternatively, you may use something like std.bignum in Phobos with artificial fixed point position (if you need the fast way to go with D). /Alexander
May 12 2011
parent Matthew Ong <ongbp yahoo.com> writes:
Hi Alex,


Coming from a Java 1.6 environment and ex-CPP.

http://www.prowiki.org/wiki4d/wiki.cgi?JavaToD
I read this here. About 80-bit floats, I hoped that was about handling
decimal point number without the use of a library like other language.

Avoiding runtime error like:
d1=func1(); // returns -0.0i;
d2=func2(); // return 0.0i;

if(d1==d2)... // some time that failed.
May 12 2011
prev sibling parent reply Don <nospam nospam.com> writes:
Matthew Ong wrote:
 Hi Alexander,
 
 Is there anyway to ensure the comparison of float/double to be done with the
raw
 bits like in Java
 Double.doubleToRawLongBits(double value)
 
 http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Double.html#doubleToRawLongBits%28double%29
 
 when it comes to financial data and percentage computation, that seems to be
 rather important.
 
 Thanks in advance.
 
 Matthew Ong

std.math.isIdentical(). I doubt it would ever be appropriate to use this in a financial context, it's more for precise testing of math functions. Note that, for example, isIdentical(-0.0, +0.0) returns false.
May 13 2011
parent Matthew Ong <ongbp yahoo.com> writes:
On 5/13/2011 3:12 PM, Don wrote:
 std.math.isIdentical().
 I doubt it would ever be appropriate to use this in a financial context,
 it's more for precise testing of math functions.
 Note that, for example, isIdentical(-0.0, +0.0) returns false.

Hmm.. That is main reason that I can see that why Java provided that function. Thanks. I will keep that in mind. In Java and most C/C++ does not have problem for <,>, for double/float type comparison. But when it comes to <=,>=,== we need to be very careful and need to somehow solve that with some sort of raw bits method. I cannot remember, there is one programming language(old one) does not have issue when it comes to financial data computation and also logical comparison. To handle that I have written some API in Java, looks like I need to port that over also. But let me bounce that off other to see if there is someone that have solved this before. -- Matthew Ong email: ongbp yahoo.com
May 16 2011
prev sibling next sibling parent Jens Mueller <jens.k.mueller gmx.de> writes:
Matthew Ong wrote:
 Hi Alexander,
 
 Is there anyway to ensure the comparison of float/double to be done with the
raw
 bits like in Java
 Double.doubleToRawLongBits(double value)
 
 http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Double.html#doubleToRawLongBits%28double%29
 
 when it comes to financial data and percentage computation, that seems to be
 rather important.
 
 Thanks in advance.

That's sounds a bit odd to me. I thought that in application code you should never compare floating points regarding equality. I only know of something similar in testing code where you compare equality within some number of ulps (unit of least precision). So your use case sounds interesting. Can you elaborate a bit? If you really want to to compare bit by bit it should be possible to cast the floating point values and then perform the comparison. Jens
May 12 2011
prev sibling parent reply Abid H. Mujtaba <abid.naqvi83 gmail.com> writes:
Thanks for the answer. I guess the correct technique would be to
define an "equality" function with a tolerance within 1e-08. I guess I
should head over to the TDLP errata section and point out that the
example code needs to be fixed to allow for this possibility.
May 12 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/12/11 11:00 AM, Abid H. Mujtaba wrote:
 Thanks for the answer. I guess the correct technique would be to
 define an "equality" function with a tolerance within 1e-08. I guess I
 should head over to the TDLP errata section and point out that the
 example code needs to be fixed to allow for this possibility.

Thanks for considering adding to the errata. Which particular example on page 143 fails? Andrei
May 12 2011
parent reply Abid H. Mujtaba <abid.naqvi83 gmail.com> writes:
Section 5.5 Overloading on page 142 it defines the following example
of a "find" function which searches for slices within slices:

T1[] find( T1, T2 )( T1[] longer, T2[] shorter )
   if( is( typeof( longer[ 0 .. 1 ] == shorter ) : bool ) )
{
   while ( longer.length >= shorter.length ) {
      if ( longer[0 .. shorter.length] == shorter ) break ;
   }

   return longer ;
}

On page 143 it defines the following unittest :

unittest {

   double[] d1 = [ 6.0, 1.5, 2.4, 3 ] ;
   float[] d2 = [ 1.5, 2.4 ] ;

   assert( find(d1,d2) == d1[1 .. $] ;
}

It is the assert() that fails since the comparison longer[0 ..
shorter.length] == shorter fails because the comparison between the
double and float values fails due to bit precision and
representation issues.
May 12 2011
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/12/11 11:21 AM, Abid H. Mujtaba wrote:
 Section 5.5 Overloading on page 142 it defines the following example
 of a "find" function which searches for slices within slices:

 T1[] find( T1, T2 )( T1[] longer, T2[] shorter )
     if( is( typeof( longer[ 0 .. 1 ] == shorter ) : bool ) )
 {
     while ( longer.length>= shorter.length ) {
        if ( longer[0 .. shorter.length] == shorter ) break ;
     }

     return longer ;
 }

 On page 143 it defines the following unittest :

 unittest {

     double[] d1 = [ 6.0, 1.5, 2.4, 3 ] ;
     float[] d2 = [ 1.5, 2.4 ] ;

     assert( find(d1,d2) == d1[1 .. $] ;
 }

 It is the assert() that fails since the comparison longer[0 ..
 shorter.length] == shorter fails because the comparison between the
 double and float values fails due to bit precision and
 representation issues.

I see. Thanks! I updated the errata with credit: http://erdani.com/tdpl/errata Andrei
May 12 2011
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/12/11 11:00 AM, Abid H. Mujtaba wrote:
 Thanks for the answer. I guess the correct technique would be to
 define an "equality" function with a tolerance within 1e-08. I guess I
 should head over to the TDLP errata section and point out that the
 example code needs to be fixed to allow for this possibility.

Also, you may want to peruse the function approxEqual in std.math. Andrei
May 12 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei:

 Also, you may want to peruse the function approxEqual in std.math.

I suggest feqrel: http://www.digitalmars.com/d/2.0/phobos/std_math.html#feqrel Bye, bearophile
May 12 2011
parent Abid H. Mujtaba <abid.naqvi83 gmail.com> writes:
The website defines the signature for feqrel to be:

int feqrel(X)(X x, X y);

It requires x and y to be the same type. But the variables we are
working with are NOT the same type. This is what started the whole
debate in the first place. I tested approxEqual and it works. Just
have to be careful with the precision one uses.
May 12 2011