2016-10-26 François Dumont <fdumont@gcc.gnu.org>
[official-gcc.git] / gcc / ada / math_lib.adb
blobe539f477beef080a0523bf36f801d38d7a98261d
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME COMPONENTS --
4 -- --
5 -- M A T H _ L I B --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2009, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
29 -- --
30 ------------------------------------------------------------------------------
32 -- This body is specifically for using an Ada interface to C math.h to get
33 -- the computation engine. Many special cases are handled locally to avoid
34 -- unnecessary calls. This is not a "strict" implementation, but takes full
35 -- advantage of the C functions, e.g. in providing interface to hardware
36 -- provided versions of the elementary functions.
38 -- A known weakness is that on the x86, all computation is done in Double,
39 -- which means that a lot of accuracy is lost for the Long_Long_Float case.
41 -- Uses functions sqrt, exp, log, pow, sin, asin, cos, acos, tan, atan,
42 -- sinh, cosh, tanh from C library via math.h
44 -- This is an adaptation of Ada.Numerics.Generic_Elementary_Functions that
45 -- provides a compatible body for the DEC Math_Lib package.
47 with Ada.Numerics.Aux;
48 use type Ada.Numerics.Aux.Double;
49 with Ada.Numerics; use Ada.Numerics;
51 package body Math_Lib is
53 Log_Two : constant := 0.69314_71805_59945_30941_72321_21458_17656_80755;
55 Two_Pi : constant Real'Base := 2.0 * Pi;
56 Half_Pi : constant Real'Base := Pi / 2.0;
57 Fourth_Pi : constant Real'Base := Pi / 4.0;
58 Epsilon : constant Real'Base := Real'Base'Epsilon;
59 IEpsilon : constant Real'Base := 1.0 / Epsilon;
61 subtype Double is Aux.Double;
63 DEpsilon : constant Double := Double (Epsilon);
64 DIEpsilon : constant Double := Double (IEpsilon);
66 -----------------------
67 -- Local Subprograms --
68 -----------------------
70 function Arctan
71 (Y : Real;
72 A : Real := 1.0)
73 return Real;
75 function Arctan
76 (Y : Real;
77 A : Real := 1.0;
78 Cycle : Real)
79 return Real;
81 function Exact_Remainder
82 (A : Real;
83 Y : Real)
84 return Real;
85 -- Computes exact remainder of A divided by Y
87 function Half_Log_Epsilon return Real;
88 -- Function to provide constant: 0.5 * Log (Epsilon)
90 function Local_Atan
91 (Y : Real;
92 A : Real := 1.0)
93 return Real;
94 -- Common code for arc tangent after cycle reduction
96 function Log_Inverse_Epsilon return Real;
97 -- Function to provide constant: Log (1.0 / Epsilon)
99 function Square_Root_Epsilon return Real;
100 -- Function to provide constant: Sqrt (Epsilon)
102 ----------
103 -- "**" --
104 ----------
106 function "**" (A1, A2 : Real) return Real is
108 begin
109 if A1 = 0.0
110 and then A2 = 0.0
111 then
112 raise Argument_Error;
114 elsif A1 < 0.0 then
115 raise Argument_Error;
117 elsif A2 = 0.0 then
118 return 1.0;
120 elsif A1 = 0.0 then
121 if A2 < 0.0 then
122 raise Constraint_Error;
123 else
124 return 0.0;
125 end if;
127 elsif A1 = 1.0 then
128 return 1.0;
130 elsif A2 = 1.0 then
131 return A1;
133 else
134 begin
135 if A2 = 2.0 then
136 return A1 * A1;
137 else
138 return
139 Real (Aux.pow (Double (A1), Double (A2)));
140 end if;
142 exception
143 when others =>
144 raise Constraint_Error;
145 end;
146 end if;
147 end "**";
149 ------------
150 -- Arccos --
151 ------------
153 -- Natural cycle
155 function Arccos (A : Real) return Real is
156 Temp : Real'Base;
158 begin
159 if abs A > 1.0 then
160 raise Argument_Error;
162 elsif abs A < Square_Root_Epsilon then
163 return Pi / 2.0 - A;
165 elsif A = 1.0 then
166 return 0.0;
168 elsif A = -1.0 then
169 return Pi;
170 end if;
172 Temp := Real (Aux.acos (Double (A)));
174 if Temp < 0.0 then
175 Temp := Pi + Temp;
176 end if;
178 return Temp;
179 end Arccos;
181 -- Arbitrary cycle
183 function Arccos (A, Cycle : Real) return Real is
184 Temp : Real'Base;
186 begin
187 if Cycle <= 0.0 then
188 raise Argument_Error;
190 elsif abs A > 1.0 then
191 raise Argument_Error;
193 elsif abs A < Square_Root_Epsilon then
194 return Cycle / 4.0;
196 elsif A = 1.0 then
197 return 0.0;
199 elsif A = -1.0 then
200 return Cycle / 2.0;
201 end if;
203 Temp := Arctan (Sqrt (1.0 - A * A) / A, 1.0, Cycle);
205 if Temp < 0.0 then
206 Temp := Cycle / 2.0 + Temp;
207 end if;
209 return Temp;
210 end Arccos;
212 -------------
213 -- Arccosh --
214 -------------
216 function Arccosh (A : Real) return Real is
217 begin
218 -- Return Log (A - Sqrt (A * A - 1.0)); double valued,
219 -- only positive value returned
220 -- What is this comment ???
222 if A < 1.0 then
223 raise Argument_Error;
225 elsif A < 1.0 + Square_Root_Epsilon then
226 return A - 1.0;
228 elsif abs A > 1.0 / Square_Root_Epsilon then
229 return Log (A) + Log_Two;
231 else
232 return Log (A + Sqrt (A * A - 1.0));
233 end if;
234 end Arccosh;
236 ------------
237 -- Arccot --
238 ------------
240 -- Natural cycle
242 function Arccot
243 (A : Real;
244 Y : Real := 1.0)
245 return Real
247 begin
248 -- Just reverse arguments
250 return Arctan (Y, A);
251 end Arccot;
253 -- Arbitrary cycle
255 function Arccot
256 (A : Real;
257 Y : Real := 1.0;
258 Cycle : Real)
259 return Real
261 begin
262 -- Just reverse arguments
264 return Arctan (Y, A, Cycle);
265 end Arccot;
267 -------------
268 -- Arccoth --
269 -------------
271 function Arccoth (A : Real) return Real is
272 begin
273 if abs A = 1.0 then
274 raise Constraint_Error;
276 elsif abs A < 1.0 then
277 raise Argument_Error;
279 elsif abs A > 1.0 / Epsilon then
280 return 0.0;
282 else
283 return 0.5 * Log ((1.0 + A) / (A - 1.0));
284 end if;
285 end Arccoth;
287 ------------
288 -- Arcsin --
289 ------------
291 -- Natural cycle
293 function Arcsin (A : Real) return Real is
294 begin
295 if abs A > 1.0 then
296 raise Argument_Error;
298 elsif abs A < Square_Root_Epsilon then
299 return A;
301 elsif A = 1.0 then
302 return Pi / 2.0;
304 elsif A = -1.0 then
305 return -Pi / 2.0;
306 end if;
308 return Real (Aux.asin (Double (A)));
309 end Arcsin;
311 -- Arbitrary cycle
313 function Arcsin (A, Cycle : Real) return Real is
314 begin
315 if Cycle <= 0.0 then
316 raise Argument_Error;
318 elsif abs A > 1.0 then
319 raise Argument_Error;
321 elsif A = 0.0 then
322 return A;
324 elsif A = 1.0 then
325 return Cycle / 4.0;
327 elsif A = -1.0 then
328 return -Cycle / 4.0;
329 end if;
331 return Arctan (A / Sqrt (1.0 - A * A), 1.0, Cycle);
332 end Arcsin;
334 -------------
335 -- Arcsinh --
336 -------------
338 function Arcsinh (A : Real) return Real is
339 begin
340 if abs A < Square_Root_Epsilon then
341 return A;
343 elsif A > 1.0 / Square_Root_Epsilon then
344 return Log (A) + Log_Two;
346 elsif A < -1.0 / Square_Root_Epsilon then
347 return -(Log (-A) + Log_Two);
349 elsif A < 0.0 then
350 return -Log (abs A + Sqrt (A * A + 1.0));
352 else
353 return Log (A + Sqrt (A * A + 1.0));
354 end if;
355 end Arcsinh;
357 ------------
358 -- Arctan --
359 ------------
361 -- Natural cycle
363 function Arctan
364 (Y : Real;
365 A : Real := 1.0)
366 return Real
368 begin
369 if A = 0.0
370 and then Y = 0.0
371 then
372 raise Argument_Error;
374 elsif Y = 0.0 then
375 if A > 0.0 then
376 return 0.0;
377 else -- A < 0.0
378 return Pi;
379 end if;
381 elsif A = 0.0 then
382 if Y > 0.0 then
383 return Half_Pi;
384 else -- Y < 0.0
385 return -Half_Pi;
386 end if;
388 else
389 return Local_Atan (Y, A);
390 end if;
391 end Arctan;
393 -- Arbitrary cycle
395 function Arctan
396 (Y : Real;
397 A : Real := 1.0;
398 Cycle : Real)
399 return Real
401 begin
402 if Cycle <= 0.0 then
403 raise Argument_Error;
405 elsif A = 0.0
406 and then Y = 0.0
407 then
408 raise Argument_Error;
410 elsif Y = 0.0 then
411 if A > 0.0 then
412 return 0.0;
413 else -- A < 0.0
414 return Cycle / 2.0;
415 end if;
417 elsif A = 0.0 then
418 if Y > 0.0 then
419 return Cycle / 4.0;
420 else -- Y < 0.0
421 return -Cycle / 4.0;
422 end if;
424 else
425 return Local_Atan (Y, A) * Cycle / Two_Pi;
426 end if;
427 end Arctan;
429 -------------
430 -- Arctanh --
431 -------------
433 function Arctanh (A : Real) return Real is
434 begin
435 if abs A = 1.0 then
436 raise Constraint_Error;
438 elsif abs A > 1.0 then
439 raise Argument_Error;
441 elsif abs A < Square_Root_Epsilon then
442 return A;
444 else
445 return 0.5 * Log ((1.0 + A) / (1.0 - A));
446 end if;
447 end Arctanh;
449 ---------
450 -- Cos --
451 ---------
453 -- Natural cycle
455 function Cos (A : Real) return Real is
456 begin
457 if A = 0.0 then
458 return 1.0;
460 elsif abs A < Square_Root_Epsilon then
461 return 1.0;
463 end if;
465 return Real (Aux.Cos (Double (A)));
466 end Cos;
468 -- Arbitrary cycle
470 function Cos (A, Cycle : Real) return Real is
471 T : Real'Base;
473 begin
474 if Cycle <= 0.0 then
475 raise Argument_Error;
477 elsif A = 0.0 then
478 return 1.0;
479 end if;
481 T := Exact_Remainder (abs (A), Cycle) / Cycle;
483 if T = 0.25
484 or else T = 0.75
485 or else T = -0.25
486 or else T = -0.75
487 then
488 return 0.0;
490 elsif T = 0.5 or T = -0.5 then
491 return -1.0;
492 end if;
494 return Real (Aux.Cos (Double (T * Two_Pi)));
495 end Cos;
497 ----------
498 -- Cosh --
499 ----------
501 function Cosh (A : Real) return Real is
502 begin
503 if abs A < Square_Root_Epsilon then
504 return 1.0;
506 elsif abs A > Log_Inverse_Epsilon then
507 return Exp ((abs A) - Log_Two);
508 end if;
510 return Real (Aux.cosh (Double (A)));
512 exception
513 when others =>
514 raise Constraint_Error;
515 end Cosh;
517 ---------
518 -- Cot --
519 ---------
521 -- Natural cycle
523 function Cot (A : Real) return Real is
524 begin
525 if A = 0.0 then
526 raise Constraint_Error;
528 elsif abs A < Square_Root_Epsilon then
529 return 1.0 / A;
530 end if;
532 return Real (1.0 / Real'Base (Aux.tan (Double (A))));
533 end Cot;
535 -- Arbitrary cycle
537 function Cot (A, Cycle : Real) return Real is
538 T : Real'Base;
540 begin
541 if Cycle <= 0.0 then
542 raise Argument_Error;
544 elsif A = 0.0 then
545 raise Constraint_Error;
547 elsif abs A < Square_Root_Epsilon then
548 return 1.0 / A;
549 end if;
551 T := Exact_Remainder (A, Cycle) / Cycle;
553 if T = 0.0 or T = 0.5 or T = -0.5 then
554 raise Constraint_Error;
555 else
556 return Cos (T * Two_Pi) / Sin (T * Two_Pi);
557 end if;
558 end Cot;
560 ----------
561 -- Coth --
562 ----------
564 function Coth (A : Real) return Real is
565 begin
566 if A = 0.0 then
567 raise Constraint_Error;
569 elsif A < Half_Log_Epsilon then
570 return -1.0;
572 elsif A > -Half_Log_Epsilon then
573 return 1.0;
575 elsif abs A < Square_Root_Epsilon then
576 return 1.0 / A;
577 end if;
579 return Real (1.0 / Real'Base (Aux.tanh (Double (A))));
580 end Coth;
582 ---------------------
583 -- Exact_Remainder --
584 ---------------------
586 function Exact_Remainder
587 (A : Real;
588 Y : Real)
589 return Real
591 Denominator : Real'Base := abs A;
592 Divisor : Real'Base := abs Y;
593 Reducer : Real'Base;
594 Sign : Real'Base := 1.0;
596 begin
597 if Y = 0.0 then
598 raise Constraint_Error;
600 elsif A = 0.0 then
601 return 0.0;
603 elsif A = Y then
604 return 0.0;
606 elsif Denominator < Divisor then
607 return A;
608 end if;
610 while Denominator >= Divisor loop
612 -- Put divisors mantissa with denominators exponent to make reducer
614 Reducer := Divisor;
616 begin
617 while Reducer * 1_048_576.0 < Denominator loop
618 Reducer := Reducer * 1_048_576.0;
619 end loop;
621 exception
622 when others => null;
623 end;
625 begin
626 while Reducer * 1_024.0 < Denominator loop
627 Reducer := Reducer * 1_024.0;
628 end loop;
630 exception
631 when others => null;
632 end;
634 begin
635 while Reducer * 2.0 < Denominator loop
636 Reducer := Reducer * 2.0;
637 end loop;
639 exception
640 when others => null;
641 end;
643 Denominator := Denominator - Reducer;
644 end loop;
646 if A < 0.0 then
647 return -Denominator;
648 else
649 return Denominator;
650 end if;
651 end Exact_Remainder;
653 ---------
654 -- Exp --
655 ---------
657 function Exp (A : Real) return Real is
658 Result : Real'Base;
660 begin
661 if A = 0.0 then
662 return 1.0;
664 else
665 Result := Real (Aux.Exp (Double (A)));
667 -- The check here catches the case of Exp returning IEEE infinity
669 if Result > Real'Last then
670 raise Constraint_Error;
671 else
672 return Result;
673 end if;
674 end if;
675 end Exp;
677 ----------------------
678 -- Half_Log_Epsilon --
679 ----------------------
681 -- Cannot precompute this constant, because this is required to be a
682 -- pure package, which allows no state. A pity, but no way around it!
684 function Half_Log_Epsilon return Real is
685 begin
686 return Real (0.5 * Real'Base (Aux.Log (DEpsilon)));
687 end Half_Log_Epsilon;
689 ----------------
690 -- Local_Atan --
691 ----------------
693 function Local_Atan
694 (Y : Real;
695 A : Real := 1.0)
696 return Real
698 Z : Real'Base;
699 Raw_Atan : Real'Base;
701 begin
702 if abs Y > abs A then
703 Z := abs (A / Y);
704 else
705 Z := abs (Y / A);
706 end if;
708 if Z < Square_Root_Epsilon then
709 Raw_Atan := Z;
711 elsif Z = 1.0 then
712 Raw_Atan := Pi / 4.0;
714 elsif Z < Square_Root_Epsilon then
715 Raw_Atan := Z;
717 else
718 Raw_Atan := Real'Base (Aux.Atan (Double (Z)));
719 end if;
721 if abs Y > abs A then
722 Raw_Atan := Half_Pi - Raw_Atan;
723 end if;
725 if A > 0.0 then
726 if Y > 0.0 then
727 return Raw_Atan;
728 else -- Y < 0.0
729 return -Raw_Atan;
730 end if;
732 else -- A < 0.0
733 if Y > 0.0 then
734 return Pi - Raw_Atan;
735 else -- Y < 0.0
736 return -(Pi - Raw_Atan);
737 end if;
738 end if;
739 end Local_Atan;
741 ---------
742 -- Log --
743 ---------
745 -- Natural base
747 function Log (A : Real) return Real is
748 begin
749 if A < 0.0 then
750 raise Argument_Error;
752 elsif A = 0.0 then
753 raise Constraint_Error;
755 elsif A = 1.0 then
756 return 0.0;
757 end if;
759 return Real (Aux.Log (Double (A)));
760 end Log;
762 -- Arbitrary base
764 function Log (A, Base : Real) return Real is
765 begin
766 if A < 0.0 then
767 raise Argument_Error;
769 elsif Base <= 0.0 or else Base = 1.0 then
770 raise Argument_Error;
772 elsif A = 0.0 then
773 raise Constraint_Error;
775 elsif A = 1.0 then
776 return 0.0;
777 end if;
779 return Real (Aux.Log (Double (A)) / Aux.Log (Double (Base)));
780 end Log;
782 -------------------------
783 -- Log_Inverse_Epsilon --
784 -------------------------
786 -- Cannot precompute this constant, because this is required to be a
787 -- pure package, which allows no state. A pity, but no way around it!
789 function Log_Inverse_Epsilon return Real is
790 begin
791 return Real (Aux.Log (DIEpsilon));
792 end Log_Inverse_Epsilon;
794 ---------
795 -- Sin --
796 ---------
798 -- Natural cycle
800 function Sin (A : Real) return Real is
801 begin
802 if abs A < Square_Root_Epsilon then
803 return A;
804 end if;
806 return Real (Aux.Sin (Double (A)));
807 end Sin;
809 -- Arbitrary cycle
811 function Sin (A, Cycle : Real) return Real is
812 T : Real'Base;
814 begin
815 if Cycle <= 0.0 then
816 raise Argument_Error;
818 elsif A = 0.0 then
819 return A;
820 end if;
822 T := Exact_Remainder (A, Cycle) / Cycle;
824 if T = 0.0 or T = 0.5 or T = -0.5 then
825 return 0.0;
827 elsif T = 0.25 or T = -0.75 then
828 return 1.0;
830 elsif T = -0.25 or T = 0.75 then
831 return -1.0;
833 end if;
835 return Real (Aux.Sin (Double (T * Two_Pi)));
836 end Sin;
838 ----------
839 -- Sinh --
840 ----------
842 function Sinh (A : Real) return Real is
843 begin
844 if abs A < Square_Root_Epsilon then
845 return A;
847 elsif A > Log_Inverse_Epsilon then
848 return Exp (A - Log_Two);
850 elsif A < -Log_Inverse_Epsilon then
851 return -Exp ((-A) - Log_Two);
852 end if;
854 return Real (Aux.Sinh (Double (A)));
856 exception
857 when others =>
858 raise Constraint_Error;
859 end Sinh;
861 -------------------------
862 -- Square_Root_Epsilon --
863 -------------------------
865 -- Cannot precompute this constant, because this is required to be a
866 -- pure package, which allows no state. A pity, but no way around it!
868 function Square_Root_Epsilon return Real is
869 begin
870 return Real (Aux.Sqrt (DEpsilon));
871 end Square_Root_Epsilon;
873 ----------
874 -- Sqrt --
875 ----------
877 function Sqrt (A : Real) return Real is
878 begin
879 if A < 0.0 then
880 raise Argument_Error;
882 -- Special case Sqrt (0.0) to preserve possible minus sign per IEEE
884 elsif A = 0.0 then
885 return A;
887 -- Sqrt (1.0) must be exact for good complex accuracy
889 elsif A = 1.0 then
890 return 1.0;
892 end if;
894 return Real (Aux.Sqrt (Double (A)));
895 end Sqrt;
897 ---------
898 -- Tan --
899 ---------
901 -- Natural cycle
903 function Tan (A : Real) return Real is
904 begin
905 if abs A < Square_Root_Epsilon then
906 return A;
908 elsif abs A = Pi / 2.0 then
909 raise Constraint_Error;
910 end if;
912 return Real (Aux.tan (Double (A)));
913 end Tan;
915 -- Arbitrary cycle
917 function Tan (A, Cycle : Real) return Real is
918 T : Real'Base;
920 begin
921 if Cycle <= 0.0 then
922 raise Argument_Error;
924 elsif A = 0.0 then
925 return A;
926 end if;
928 T := Exact_Remainder (A, Cycle) / Cycle;
930 if T = 0.25
931 or else T = 0.75
932 or else T = -0.25
933 or else T = -0.75
934 then
935 raise Constraint_Error;
937 else
938 return Sin (T * Two_Pi) / Cos (T * Two_Pi);
939 end if;
940 end Tan;
942 ----------
943 -- Tanh --
944 ----------
946 function Tanh (A : Real) return Real is
947 begin
948 if A < Half_Log_Epsilon then
949 return -1.0;
951 elsif A > -Half_Log_Epsilon then
952 return 1.0;
954 elsif abs A < Square_Root_Epsilon then
955 return A;
956 end if;
958 return Real (Aux.tanh (Double (A)));
959 end Tanh;
961 ----------------------------
962 -- DEC-Specific functions --
963 ----------------------------
965 function LOG10 (A : REAL) return REAL is
966 begin
967 return Log (A, 10.0);
968 end LOG10;
970 function LOG2 (A : REAL) return REAL is
971 begin
972 return Log (A, 2.0);
973 end LOG2;
975 function ASIN (A : REAL) return REAL renames Arcsin;
976 function ACOS (A : REAL) return REAL renames Arccos;
978 function ATAN (A : REAL) return REAL is
979 begin
980 return Arctan (A, 1.0);
981 end ATAN;
983 function ATAN2 (A1, A2 : REAL) return REAL renames Arctan;
985 function SIND (A : REAL) return REAL is
986 begin
987 return Sin (A, 360.0);
988 end SIND;
990 function COSD (A : REAL) return REAL is
991 begin
992 return Cos (A, 360.0);
993 end COSD;
995 function TAND (A : REAL) return REAL is
996 begin
997 return Tan (A, 360.0);
998 end TAND;
1000 function ASIND (A : REAL) return REAL is
1001 begin
1002 return Arcsin (A, 360.0);
1003 end ASIND;
1005 function ACOSD (A : REAL) return REAL is
1006 begin
1007 return Arccos (A, 360.0);
1008 end ACOSD;
1010 function Arctan (A : REAL) return REAL is
1011 begin
1012 return Arctan (A, 1.0, 360.0);
1013 end Arctan;
1015 function ATAND (A : REAL) return REAL is
1016 begin
1017 return Arctan (A, 1.0, 360.0);
1018 end ATAND;
1020 function ATAN2D (A1, A2 : REAL) return REAL is
1021 begin
1022 return Arctan (A1, A2, 360.0);
1023 end ATAN2D;
1025 end Math_Lib;