Hi Roland,

sorry that I answer you that late.  I had vacations and was recently
sick ... anyway to your tests:

First, please don't compare MS-printf output and linux-printf.
Algorithm and rounding are different and therefore values are pretty
different.  So only interesting values in your test are the
hexadecimals.
You could also use '-D__USE_MINGW_ANSI_STDIO=1' on command-line on
mingw-w64, so you get a more linux compatible display (plus you can
display long doubles by it too).

I changed local implementation of powi to use long double instead, and
for me just one value has a different value by one ulp (which is in
general ok). It was 'pow(eps,          2147483647.0)=3ff00000800001fe'
your linux has here 3ff00000800001ff as result.  Which brings me to
the next point.  You are comparing here happily 32-bit (FPU)
calculations with x64 values.  To expect here equal values is an
illegal assumption.  x64 calculates in SSE-registers and therefore is
reduced to actual precision of used types.  32-bit uses her
387-registers which are always 80-bits wide, and therefore have
different precision in rounding.

So if you want to use slow calculation, it is up to you.  Nevertheless
I will commit a change that changes internal use within powi to use
80-bit precision, which seems to me like an improvement in terms of
precision (it a is really small one).

Regards,
Kai

2014-03-28 15:58 GMT+01:00 Roland Schwingel <rol...@onevision.com>:
> Hi...
>
> Whenever possible I investigated pow() more the last days. I calculated
> billions of pow() values on windows/linux/mac and compared them.
>
> First one my main test code. I did let it run in variety of numeric ranges.
>
> // powtest2.c
> // gcc -O3 -fno-builtin powtest2.c -o powtest (-lm)
> #include <stdio.h>
> #include <math.h>
>
> static printhexDouble(double val)
> {
>         unsigned char *pointer = (char *)&val;
>         int i;
>         for (i = sizeof(double) - 1;i >= 0;i--)
>                 printf("%02x",pointer[i]);
> }
>
> int main(int argc,const char **argv)
> {
>         double startPoint = 0.0;
>         double endPoint = 3.0;
>         int numPows = 100000000;
>
>         int i = -numPows/2;
>         int count = 0;
>
>         double result,eps = 1.0;
>         while (1.0 + eps > 1)
>                 eps = eps/2;
>         eps = 1 + eps*2;
>
>         double delta = (endPoint - eps) / (double)numPows;
>
>         startPoint = eps;
>         while (startPoint < endPoint)
>         {
>                 // printhexDouble(startPoint);
>                 // printf(" %d ",i);
>                 result = pow(startPoint,i++);
>                 // printhexDouble(result);
>                 // printf("\n");
>                 startPoint += delta;
>                 count++;
>         }
>
>         return 0;
> }
>
> Here are my results - both in regard of speed and accuraccy.
>
> When doing speed tests I used it in this way (with commented prints).
> When I did accurray test I had the prints enabled and redirected
> the output.
>
> With the given range for X^Y in this example:
>
>    epsilon <= X < 3.0
> -50000000 <= Y < 50000000
>
> the code calculates 100 million pow()s. As Y always is non float powi()
> is used internally on windows when using mingw-w64 trunk code. For
> windows I did a test with this stock implementation and a patched
> version not using powi() at all.
>
> Hardware:
> Linux/Windows both are 100% identical machines running Core i7-3770.
> Mac: XServe3,1 with Xeon E5462
>
> Accurraccy:
> ===========
> All implementations (mingw-w64/linux/mac) had differences in their
> results. For linux/mac the are neglectable. For mingw-w64 using powi()
> they are more severe. When using always pow() for mingw-w64 the
> differences also become neglectable.
>
> Number of different results:
> linux pow()     <-> mac pow()       : 92   Diffs only at the last digit
> mingw-w64 pow() <-> mingw-w64 powi(): 2752 Diff 8th-12th digit after dot
> mingw-w64 pow() <-> mac pow()       : 83   Diffs only at the last digit
> mingw-w64 pow() <-> linux pow()     : 127  Diffs only at the last digit
>
> The problem with powi() on mingw is that it is starting to produce
> non accurate results in a much higher number and already starting from
> the 8th digit after the dot this can severly impact calculation results
> if you use these results as component of subsequent other calculations
> (eg. image processing). We got different images on windows as on
> linux/mac. When avoiding powi() on windows our pictures became binary
> identical(!) on all 3 platforms.
>
> I was able to improve powi() a little bit by using long double
> calculations instead of double calculations. This improved accuraccy
> by ~2 digits. For very small X it did even solve the inaccuraccy
> at all - BUT was IMHO not changing the overall picture.
>
> Speed:
> ======
> On Linux and Windows I am fortunate to have the exact same compiler
> version and the exact same hardware. It did execute the test code 10
> times for each version and took the average.
>
> Execution time for 100 million different pow() calls:
> mingw-w64-crt-trunk (using powi()):  7.748s (+/- 16ms)
> mingw-w64-crt-trunk (no powi())   : 10.941s (+/- 15ms)
> linux                             :  5.783s (+/- 8ms)
>
> As one can see:
> Linux is superior in perfomance. 2nd best (in regard of speed) is
> the inaccurate powi() implementation.
>
> (Due to the different CPU type I did not conduct a speed test for mac
> as I could not compare it to a similar machine running linux/windows.
> I executed the test noncompetitive. On my machine it was around 21s.)
>
> MY conclusion:
> ==============
> For many people the accuraccy of powi() of mingw-w64 might be
> good enough, but when it comes to quality this is no longer true.
> I have changed pow() in our self build toolchain to no longer use
> powi(). QUALITY FIRST!
>
> Maybe it is better for mingw-w64 crt to also switch to plain pow() as
> default and to clearly state that powi() is possibly inaccurate!
>
> Have a nice weekend,
>
> Roland
>
>
> ------------------------------------------------------------------------------
> _______________________________________________
> Mingw-w64-public mailing list
> Mingw-w64-public@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and their
applications. Written by three acclaimed leaders in the field,
this first edition is now available. Download your free book today!
http://p.sf.net/sfu/NeoTech
_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to