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

Reply via email to