From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=unavailable autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!news.eternal-september.org!news.eternal-september.org!feeder.eternal-september.org!aioe.org!.POSTED!not-for-mail From: =?UTF-8?Q?Markus_Sch=c3=b6pflin?= Newsgroups: comp.lang.ada Subject: Ada.Numerics, Accuracy of trigonometric functions Date: Fri, 7 Oct 2016 12:13:48 +0200 Organization: Aioe.org NNTP Server Message-ID: NNTP-Posting-Host: MdpKeRr+sx3LK7JQiK5aNw.user.gioia.aioe.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit X-Complaints-To: abuse@aioe.org User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.3.0 X-Mozilla-News-Host: news://nntp.aioe.org:119 X-Notice: Filtered by postfilter v. 0.8.2 Xref: news.eternal-september.org comp.lang.ada:32030 Date: 2016-10-07T12:13:48+02:00 List-Id: 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 #include 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