comp.lang.ada
 help / color / mirror / Atom feed
From: "Markus Schöpflin" <no.spam@spam.spam>
Subject: Ada.Numerics, Accuracy of trigonometric functions
Date: Fri, 7 Oct 2016 12:13:48 +0200
Date: 2016-10-07T12:13:48+02:00	[thread overview]
Message-ID: <nt7sgs$1a06$1@gioia.aioe.org> (raw)

The following tests have been performed using GNAT 7.4 on a 64bit Linux system.

I'm puzzled by the seemingly bad accuracy of calling COS on a large value of 
type Short_Float.

Given the following procedure which calculates y1 = cos(2**32) and y2 = 
cos(2**32 mod 2*PI):

---%<---
with ADA.NUMERICS.GENERIC_ELEMENTARY_FUNCTIONS;

with ADA.TEXT_IO; use ADA.TEXT_IO;
with ADA.SHORT_FLOAT_TEXT_IO; use ADA.SHORT_FLOAT_TEXT_IO;

procedure TEST_TRIG is

    MRE_COS : constant := 2.0 * SHORT_FLOAT'MODEL_EPSILON;
    THRESHOLD : constant := SHORT_FLOAT'MACHINE_MANTISSA / 2;

    package EF is new ADA.NUMERICS.GENERIC_ELEMENTARY_FUNCTIONS (SHORT_FLOAT);

    X : constant SHORT_FLOAT := 2.0**32;
    Y : constant SHORT_FLOAT := EF.COS (X);

begin

    PUT_LINE ("Size of SHORT_FLOAT = " & POSITIVE'IMAGE (SHORT_FLOAT'SIZE));
    PUT_LINE ("Maximum relative error of COS = " & SHORT_FLOAT'IMAGE (MRE_COS));
    PUT_LINE ("Angle threshold = " & POSITIVE'IMAGE (THRESHOLD));

    PUT ("X = ");        PUT (X, EXP => 0);
    PUT ("; COS(X) = "); PUT (Y, EXP => 0);
    NEW_LINE;

end TEST_TRIG;
--->%---

The (for me surprising result is):

---%<---
Size of SHORT_FLOAT =  32
Maximum relative error of COS =  2.38419E-07
Angle threshold =  12
X = 4294967296.00000; COS(X) =  1.00000      <-- WHAT?
--->%---

The corresponding C program:

---%<---
#include <math.h>
#include <stdio.h>

int main() {

   float x = exp2f(32.0);

   printf("sizeof(float) = %lu\n", sizeof(float));
   printf("x = %f; cos(x) = %f\n", x, cosf(x));

   return 0;
}
--->%---

gives:

---%<---
sizeof(float) = 4
x = 4294967296.000000; cos(x) = -0.886887    <--- OK
--->%---

Now, why is the error on cos(2**32) so large in this case? I am aware that I'm 
way beyond the required angle threshold mentioned in G.2.4(12), so it's up to 
the compiler to decide on the accuracy.

Looking at the implementation defined characteristics for GNAT, I find that 
strict mode is on by default, so G.2.4 should apply. For G.2.4(10) the 
documentation states (for the value of the angle threshold and the accuracy 
beyond the threshold): "Information on this subject is not yet available.".

So in principle the compiler is free to give me any answer once I'm beyond the 
minimum required angle threshold, which is about 12 for short float.

But if I understand G.2.4(10) correctly, cos(x1, cycle=>2*PI) should give me 
an answer within the maximum relative error, but this is not the case either, 
as EF.COS (X, CYCLE => TWO_PI) gives 0.33575.

Now for the questions: Is my reasoning above correct? Why does using the cycle 
parameter not help? Do other Ada compilers give the same bad result in this 
case? Should I report this as an error to AdaCore?

TIA,
Markus

             reply	other threads:[~2016-10-07 10:13 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-07 10:13 Markus Schöpflin [this message]
2016-10-07 10:23 ` Ada.Numerics, Accuracy of trigonometric functions Markus Schöpflin
2016-10-07 10:23 ` Brian Drummond
2016-10-07 10:40   ` Markus Schöpflin
2016-10-07 14:52 ` Dennis Lee Bieber
2016-10-07 15:19   ` Markus Schöpflin
2016-10-07 22:15     ` Dennis Lee Bieber
2016-10-07 16:38 ` Jeffrey R. Carter
2016-10-10  7:44   ` Markus Schöpflin
2016-10-22 22:38 ` Robert Eachus
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox