Jump to page: 1 2
Thread overview
[Issue 8476] New: float comparison operand not truncated from real
Jul 30, 2012
Ellery Newcomer
Jul 30, 2012
Walter Bright
Jul 30, 2012
Ellery Newcomer
Jul 31, 2012
Walter Bright
Jul 31, 2012
Walter Bright
Oct 16, 2012
Ellery Newcomer
Oct 16, 2012
Maxim Fomin
Oct 16, 2012
Maxim Fomin
May 28, 2013
Vladimir Panteleev
July 30, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8476

           Summary: float comparison operand not truncated from real
           Product: D
           Version: D2
          Platform: x86
        OS/Version: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: ellery-newcomer@utulsa.edu


--- Comment #0 from Ellery Newcomer <ellery-newcomer@utulsa.edu> 2012-07-30 14:28:26 PDT ---
The following code produces different results on a comparison.
The problem is in fitnessCompare; it looks like one of the two operands has
float precision, while the other has real precision.

assembly dump:

08065710
<_D19travelling_salesman4mainFZv14fitnessCompareMFS19travelling_salesman10chromosomeS19travelling_salesman10chromosomeZb>:
 8065710:       55                      push   ebp
 8065711:       8b ec                   mov    ebp,esp
 8065713:       83 ec 10                sub    esp,0x10
 8065716:       ff 75 14                push   DWORD PTR [ebp+0x14]
 8065719:       ff 75 10                push   DWORD PTR [ebp+0x10]
 806571c:       e8 27 00 00 00          call   8065748
<_D19travelling_salesman7fitnessFNaxS19travelling_salesman10chromosomeZf>
 8065721:       ff 75 0c                push   DWORD PTR [ebp+0xc]
 8065724:       ff 75 08                push   DWORD PTR [ebp+0x8]
 8065727:       d9 5d f0                fstp   DWORD PTR [ebp-0x10]
 806572a:       e8 19 00 00 00          call   8065748
<_D19travelling_salesman7fitnessFNaxS19travelling_salesman10chromosomeZf>
 806572f:       d9 45 f0                fld    DWORD PTR [ebp-0x10]
 8065732:       d9 c9                   fxch   st(1)
 8065734:       de d9                   fcompp
 8065736:       df e0                   fnstsw ax
 8065738:       9e                      sahf
 8065739:       b8 01 00 00 00          mov    eax,0x1
 806573e:       7a 02                   jp     8065742
<_D19travelling_salesman4mainFZv14fitnessCompareMFS19travelling_salesman10chromosomeS19travelling_salesman10chromosomeZb+0x32>
 8065740:       72 02                   jb     8065744
<_D19travelling_salesman4mainFZv14fitnessCompareMFS19travelling_salesman10chromosomeS19travelling_salesman10chromosomeZb+0x34>
 8065742:       31 c0                   xor    eax,eax
 8065744:       c9                      leave
 8065745:       c2 10 00                ret    0x10



actual code:



import std.stdio;
import std.random;
import std.array;
import std.math;

struct city{
    int x;
    int y;
}

struct chromosome{
    city[] dna;
}

void main(){
    bool fitnessCompare(chromosome first,chromosome second){
        return fitness(first)>fitness(second);
    }
    auto less = &fitnessCompare;
    auto z = chromosome([city(0, 10), city(25, 25), city(10, 65), city(50, 50),
city(75, 30), city(20, 0)]);
    auto f = fitness(z);
    writeln("fitness(z) > fitness(z) ?",f > f);
    writeln("fitness(z) > fitness(z) ?",less(z,z));
}

float fitness(const chromosome victim) pure{
    const city[] cities=city(0,0) ~ victim.dna ~ city(0,0);

    //we need to start from home and return to home

    float travelled=0f;
    for(int x=0;x<cities.length-1;x++)
        travelled+=distance(cities[x],cities[x+1]);
    //writeln(100/travelled);
    return 100/travelled;
}

float distance(city from,city to) pure{
    return sqrt(cast(float)(pow(to.x-from.x,2) + pow(to.y-from.y,2)));
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 30, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8476


Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bugzilla@digitalmars.com


--- Comment #1 from Walter Bright <bugzilla@digitalmars.com> 2012-07-30 14:44:36 PDT ---
I'm not sure what the issue is here. Can you point to what you think it should be doing?

Also, the compiler is allowed to not truncate reals to floats when doing comparisons, even if it is typed as a float. This is a feature, not a bug. The compiler is always allowed to use a higher precision for intermediate calculations than the source is typed.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 30, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8476


bearophile_hugs@eml.cc changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bearophile_hugs@eml.cc


--- Comment #2 from bearophile_hugs@eml.cc 2012-07-30 15:09:48 PDT ---
(In reply to comment #1)

> The compiler is always allowed to use a higher precision for intermediate calculations than the source is typed.

A disadvantage of this is loss of floating point reproducibility across compilers, maybe similar to using the "-ffast-math" of GCC.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 30, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8476



--- Comment #3 from Ellery Newcomer <ellery-newcomer@utulsa.edu> 2012-07-30 16:09:48 PDT ---
(In reply to comment #1)
> I'm not sure what the issue is here. Can you point to what you think it should be doing?
> 
> Also, the compiler is allowed to not truncate reals to floats when doing comparisons, even if it is typed as a float. This is a feature, not a bug. The compiler is always allowed to use a higher precision for intermediate calculations than the source is typed.

my diagnosis is probably wrong, but

    writeln("fitness(z) > fitness(z) ?",f > f);
    writeln("fitness(z) > fitness(z) ?",less(z,z));

are printing out different results when they should be printing the same thing.

dmd 2.059, 32 bit only.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 31, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8476



--- Comment #4 from Walter Bright <bugzilla@digitalmars.com> 2012-07-30 20:58:21 PDT ---
f is of type float.

z is of type chromosome.

Where are they the same types?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 31, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8476



--- Comment #5 from Walter Bright <bugzilla@digitalmars.com> 2012-07-30 21:00:54 PDT ---
(In reply to comment #2)
> (In reply to comment #1)
> 
> > The compiler is always allowed to use a higher precision for intermediate calculations than the source is typed.
> 
> A disadvantage of this is loss of floating point reproducibility across compilers, maybe similar to using the "-ffast-math" of GCC.

D made the decision early on that:

    more precision == better

and that any program that relied on results being less accurate was a faulty program. Use of float should be for:

1. speed
2. less memory consumption

and *never* for reduced precision. float guarantees a *minimum* precision, not a maximum.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 31, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8476



--- Comment #6 from bearophile_hugs@eml.cc 2012-07-31 02:12:51 PDT ---
(In reply to comment #5)

> D made the decision early on that:
> 
>     more precision == better
> 
> and that any program that relied on results being less accurate was a faulty program.

You are right, of course, and such problems are common: http://www.parashift.com/c++-faq-lite/floating-point-arith2.html

On the other hand I remember one of my D programs not being as efficient as a very similar C++ program just because the C++ code used float-based operations instead of double-based ones, despite me typing float every FP variable and tagging with "f" every floating point literal. In some cases std.math return a double even if all it's required is a float, and the useless computation of the extra precision slows down the code compared to the C++ code that uses functions that return only a float precision. I presume the float versions of some functions perform less iterations to compute the smaller number of precision digits, and this makes them faster. And in some way std.math was unable to let me use the faster float version.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 16, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8476



--- Comment #7 from Ellery Newcomer <ellery-newcomer@utulsa.edu> 2012-10-15 17:16:10 PDT ---
Alright, let's try this again, except with me being comprehensible this time.

There is one thing happening here, and that is

float f;
...
bool result = f < f;

It is happening in two places: main, and main.fitnessCompare. In both places, f has the same value (4.2 or something). In both places, f is the result of the pure function fitness.

result should always be false for a non-{nan, inf, other floating point screwball}

In main.fitnessCompare, result is true. This is wrong.

Running the debugger, it appeared to me that one of the two operands to the floating point compare in main.fitnessCompare had 80 bits of precision, while the other only had 64 (or maybe 64 and 32, I don't remember).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 16, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8476


Maxim Fomin <maxim@maxim-fomin.ru> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |monarchdodra@gmail.com


--- Comment #8 from Maxim Fomin <maxim@maxim-fomin.ru> 2012-10-16 09:04:45 PDT ---
*** Issue 8745 has been marked as a duplicate of this issue. ***

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 16, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8476


Maxim Fomin <maxim@maxim-fomin.ru> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |maxim@maxim-fomin.ru


--- Comment #9 from Maxim Fomin <maxim@maxim-fomin.ru> 2012-10-16 09:18:02 PDT ---
Regardless of whether (when comparing floats with reals) compiler should compare with full or truncated to smaller type precision, current behavior seems to be inconsistent with spec. According to the spec in section "Equality Expressions" floating point types are compared bitwise. This means that if two floats are compared, compiler need not care about extra precision but currently it compares 32 bit with 80 bit (issue is better revealed in 8745).

But if this is feature and not a bug, spec should be changed and better explain the issue.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
« First   ‹ Prev
1 2