lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] MinGW-w64 anomaly?


From: Vadim Zeitlin
Subject: Re: [lmi] MinGW-w64 anomaly?
Date: Tue, 20 Dec 2016 17:24:56 +0100

On Tue, 20 Dec 2016 02:41:20 +0000 Greg Chicares <address@hidden> wrote:

GC> On 2016-12-19 00:38, Vadim Zeitlin wrote:
GC> > On Sun, 18 Dec 2016 22:18:07 +0000 Greg Chicares <address@hidden> wrote:
GC> [...]
GC> > GC> Yet I really do want long doubles.
GC> > 
GC> >  This is the part which worries me because it means that either lmi will
GC> > need to continue to use x87 forever or will need to using something
GC> > non-standard like __float128. Shouldn't 52 bits of precision be enough 
for,
GC> > well, basically anything?
GC> 
GC> Extended precision does have its advantages, of course, and the x87
GC> stuff is still in hardware, so why not use it where appropriate?

 They may well be both in the hardware, but from what I understand SSE is
much faster for typical code. And, AFAIK, you only get (potentially huge,
like orders of magnitude) gains from auto-vectorization when using SSE.

GC> Committed ae22927..83d8eb3 . Please let me know if you find any
GC> contemporary compiler that doesn't pass the round_to unit test.

 Unfortunately it does seem to have broken things. First of all,
round_test.cpp doesn't compile any longer because it uses
detail::perform_fabs() expunged in 46d02c56f8d0bb5483c771a36b936d495cf8a898
The following trivial change is needed to fix it:
---------------------------------- >8 --------------------------------------
diff --git a/round_test.cpp b/round_test.cpp
index aeb8165..5f86240 100644
--- a/round_test.cpp
+++ b/round_test.cpp
@@ -215,7 +215,7 @@ void print_hex_val(T t, char const* name)
 {
     RealType observed = roundFDL(unrounded);

-    max_prec_real abs_error = detail::perform_fabs(observed - expected);
+    max_prec_real abs_error = std::abs(observed - expected);
     // Nonstandardly define relative error in terms of
     // o(bserved) and e(xpected) as
     //   |(o-e)/e| if e nonzero, else
@@ -225,7 +225,7 @@ void print_hex_val(T t, char const* name)
     max_prec_real rel_error(0.0);
     if(max_prec_real(0.0) != expected)
         {
-        rel_error = detail::perform_fabs
+        rel_error = std::abs
             (
               (observed - max_prec_real(expected))
             / expected
@@ -233,7 +233,7 @@ void print_hex_val(T t, char const* name)
         }
     else if(max_prec_real(0.0) != observed)
         {
-        rel_error = detail::perform_fabs
+        rel_error = std::abs
             (
               (observed - max_prec_real(expected))
             / observed
---------------------------------- >8 --------------------------------------
Should I commit and push it?

 But after fixing its compilation, this test does pass, while
round_to_test.cpp compiles just fine, but fails with 126 errors under 64
bit Linux, which were not present before. It's not the latest commit that
broke it, however, rather it was 54d2503 ("Presume std::rint() is available
[424]"). It looks like the problem is that the rounding mode is (still) set
using x87-specific instructions, but std::rint() uses SSE in 64 bits and so
is not affected by it. I tried to build lmi with LMI_IEC_559 to see if it
would fix the problem, but currently turning it on results in many
compilation errors. I've "fixed" them by ripping out all x87-specific code
and just using fesetround() instead and now the test indeed passes again.

 So I think the logical next step is to use fesetround() instead of
manipulating x87 control word directly in fenv_rounding(), notwithstanding
the comment in the beginning of fenv_lmi.cpp claiming that we shouldn't do
this for consistency. Of course, nowadays we should use C++11 <cfenv>
instead of C99 <fenv.h>, but this is a minor detail.

 Otherwise you'd either need to revert the std::rint() change or we'll have
to live with completely broken 64 bit (and MSVC, which also uses SSE)
versions which is IMHO not ideal.


GC> Having committed this, I'm not sure it's really preferable to
GC> the code between #if 0 ... #endif, especially if the newer code
GC> works with fewer compilers.

 I think it's preferable if only because we've seen that the compiler will
unroll the loop inside std::pow() efficiently while it's unlikely to do it
for the loop in the old perform_pow().

GC> > GC> It's probably time to reveal my motivation, which is to modernize and
GC> > GC> simplify 'round_to.hpp'. I didn't want to state that earlier because
GC> > GC> that file will soon become smaller and much clearer.
GC> > 
GC> >  I'm definitely looking forward to it, this is not a part of lmi I really
GC> > like delving into right now.
GC> 
GC> After this:
GC>  round_to.hpp      | 331 
+++++++++++++++---------------------------------------
GC>  round_to_test.cpp |   6 +-
GC>  2 files changed, 92 insertions(+), 245 deletions(-)
GC> I'd say it's rather less rusty.

 Excellent, thanks a lot. If now we could do the same thing with
fenv_lmi.*, it would be great!
VZ


reply via email to

[Prev in Thread] Current Thread [Next in Thread]