Let's consider the accuracy of sice and cosine. I've run tests as
follows, using a program provided at the end of this message.

On the Opteron, using GCC 4.0.0 release, the command lines produce these
outputs:

-lm -O3 -march=k8 -funsafe-math-optimizations -mfpmath=387

  generates:
      fsincos

  cumulative accuracy:   60.830074998557684 (binary)
                         18.311677213055471 (decimal)

-lm -O3 -march=k8 -mfpmath=387

  generates:
      call sin
      call cos

  cumulative accuracy:   49.415037499278846 (binary)
                         14.875408524143376 (decimal)

-lm -O3 -march=k8 -funsafe-math-optimizations

  generates:
      call sin
      call cos

  cumulative accuracy:   47.476438043942984 (binary)
                         14.291831938509427 (decimal)

-lm -O3 -march=k8

  generates:
      call sin
      call cos

  cumulative accuracy:   47.476438043942984 (binary)
                         14.291831938509427 (decimal)

The default for Opteron is -mfpmath=sse; as has been discussed in other
threads, this may not be a good choice. I also note that using
-funsafe-math-optimizations (and thus the combined fsincos instruction)
*increases* accuracy.

On the Pentium4, using the same version of GCC, I get:

-lm -O3 -march=pentium4 -funsafe-math-optimizations

  cumulative accuracy:   63.000000000000000 (binary)
                         18.964889726830815 (decimal)

-lm -O3 -march=pentium4

  cumulative accuracy:   49.299560281858909 (binary)
                         14.840646417884166 (decimal)

-lm -O3 -march=pentium4 -funsafe-math-optimizations -mfpmath=sse

  cumulative accuracy:   47.476438043942984 (binary)
                         14.291831938509427 (decimal)

The program used is below. I'm very open to suggestions about this
program, which is a subset of a larger accuracy benchmark I'm writing
(Subtilis).

#include <fenv.h>
#pragma STDC FENV_ACCESS ON
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

static bool verbose = false;
#define PI 3.14159265358979323846

// Test floating point accuracy
inline double binary_accuracy(double x)
{
    return -(log(fabs(x)) / log(2.0));
}

inline double decimal_accuracy(double x)
{
    return -(log(fabs(x)) / log(10.0));
}

// accuracy of trigonometric functions
void trigtest()
{
    static const double range = PI; // * 2.0;
    static const double incr  = PI / 100.0;

    if (verbose)
       printf("          x                diff             accuracy\n");

    double final = 1.0;
    double x;

    for (x = -range; x <= range; x += incr)
    {
        double s1  = sin(x);
        double c1  = cos(x);
        double one = s1 * s1 + c1 * c1;
        double diff = one - 1.0;
        final *= one;

        double accuracy1 = binary_accuracy(diff);

        if (verbose)
            printf("%20.15f %14g %20.15f\n",x,diff,accuracy1);
    }

    final -= 1.0;

    printf("\ncumulative accuracy: %20.15f (binary)\n",
           binary_accuracy(final));

    printf("                     %20.15f (decimal)\n",
           decimal_accuracy(final));
}

// Entry point
int main(int argc, char ** argv)
{
    int i;

    // do we have verbose output?
    if (argc > 1)
    {
        for (i = 1; i < argc; ++i)
        {
            if (!strcmp(argv[i],"-v"))
            {
                verbose = true;
                break;
            }
        }
    }


    // run tests
    trigtest();

    // done
    return 0;
}

..Scott

Reply via email to