
Boost : 
From: Greg Chicares (chicares_at_[hidden])
Date: 20010830 17:42:09
"George A. Heintzelman" wrote:
>
> I would like to enable y = x with y in centimeters and x in inches,
> however. If it is not going to be regularly optimized down to a single
> multiplication, though, these kinds of conversions get stickier,
> especially with higherdimensionality (= more multiplications) units
> involved.
Agreed: mixing centimeters and inches shouldn't be forbidden, at least
not if it can be efficient. We shouldn't impose that decision on users.
> So, I tested this code (which would look very similar to what a
> compiler would need to do for an implicit conversion between inches and
> centimeters) with the two compilers readily available to me: g++2.95
> and Sun CC 6u1, both on a Solaris 2.8 machine:
[snip code, and most of the analysis except this:]
> When the parentheses around (x/y) were removed, g++ did *not* optimize
> out the multiplication  correctly, I believe, as IEEE
> multiplication/division are not associative, unlike the pure
> mathematical form. So we would have to take care that all floating
> point arithmetic with constants was carried out before applying it to
> the user's variable, if at all possible, to enable this optimization.
> That is probably also necessary to avoid unnecessary overflows, anyway.
>
> In sum, g++ gets full marks and Sun CC fails the test. I would be
> interested in knowing how well other compilers manage with this little
> test, but the fact that g++ successfully optimized it is encouraging;
> it certainly isn't beyond expecting compilers to do.
I tried this on windows with with gcc2.95.21 and borland C++ 5.5.1 .
Here is my analysis, code, and disassembly.
Analysis:
gcc borland
#mul #div #mul #div
inches * ( x / y ); 1 0 1 1
inches * x / y ; 1 1 1 1
inches * (fx() / fy()); 1 0 1 0
inches * fx() / fy() ; 1 1 2 0
As you noted, putting x and y inside parentheses helps.
The borland compiler actually does better optimization for an inline
function than for a const double.
In the last case, the borland compiler saves the reciprocal of fy()
so that it can multiply instead of divide (faster on intel). I don't
think IEC 60559 allows that: cf. C99 standard [F.8.2].
Code:
#include <iostream>
inline double fx() {return 0.0254;}
inline double fy() {return 0.01 ;}
int main() {
const double x = 0.0254;
const double y = 0.01;
volatile double inches = 2.718281828459045;
double r0 = inches * ( x / y );
double r1 = inches * x / y ;
double r2 = inches * (fx() / fy());
double r3 = inches * fx() / fy() ;
std::cout << r0 << " " << r1 << " " << r2 << " " << r3 << "\n";
}
Disassembly:
g++ O3 ggdb heintzelman.cpp
14 double r0 = inches * ( x / y );
0x40124c <main+20>: fld QWORD PTR [%ebp8]
0x401262 <main+42>: fld %ds:0x401230
0x401268 <main+48>: fmul %st(4),%st
15 double r1 = inches * x / y ;
0x40124f <main+23>: fld QWORD PTR [%ebp8]
0x401252 <main+26>: fld %ds:0x401218
0x401258 <main+32>: fmul %st(1),%st
0x40125a <main+34>: fld %ds:0x401220
0x401260 <main+40>: fdivr %st(2),%st
16
17 double r2 = inches * (fx() / fy());
0x40126a <main+50>: fld QWORD PTR [%ebp8]
0x40126d <main+53>: fmulp %st(1),%st
18 double r3 = inches * fx() / fy() ;
0x40126f <main+55>: fld QWORD PTR [%ebp8]
0x401272 <main+58>: fmulp %st(3),%st
0x401274 <main+60>: fxch %st(2)
0x401276 <main+62>: fdivp %st(1),%st
borland C++ 5.5.1
bcc32 O2 6 v vi ff heintzelman.cpp
O2 optimize for speed
6 pentium pro
v debug info
vi inline functions
ff standardcompliant floatingpoint math
#heintzelman#14: double r0 = inches * ( x / y );
:00401182 DD0424 fld qword ptr[esp]
:00401185 DC742408 fdiv qword ptr[esp+08]
:00401189 DC4C2410 fmul qword ptr[esp+10]
:0040118D DD5C2418 fstp qword ptr[esp+18]
:00401191 9B wait
#heintzelman#15: double r1 = inches * x / y ;
:00401192 DD442410 fld qword ptr[esp+10]
:00401196 DC0C24 fmul qword ptr[esp]
:00401199 DC742408 fdiv qword ptr[esp+08]
:0040119D DD5C2420 fstp qword ptr[esp+20]
:004011A1 9B wait
#heintzelman#17: double r2 = inches * (fx() / fy());
:004011A2 DD442410 fld qword ptr[esp+10]
:004011A6 DC0D50124000 fmul qword ptr[HEINTZELMAN.00401
:004011AC DD5C2428 fstp qword ptr[esp+28]
:004011B0 9B wait
#heintzelman#18: double r3 = inches * fx() / fy() ;
:004011B1 DD442410 fld qword ptr[esp+10]
:004011B5 DC0D58124000 fmul qword ptr[HEINTZELMAN.00401
:004011BB DB2D60124000 fld tbyte ptr[HEINTZELMAN.00401
:004011C1 DEC9 fmulp st(1),st
:004011C3 DD5C2430 fstp qword ptr[esp+30]
:004011C7 9B wait
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk