OSDN Git Service

2010-10-08 Robert Dewar <dewar@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / a-ngcoty.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT RUN-TIME COMPONENTS                         --
4 --                                                                          --
5 --   A D A . N U M E R I C S . G E N E R I C _ C O M P L E X _ T Y P E S    --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 1992-2010, 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 ------------------------------------------------------------------------------
31
32 with Ada.Numerics.Aux; use Ada.Numerics.Aux;
33
34 package body Ada.Numerics.Generic_Complex_Types is
35
36    subtype R is Real'Base;
37
38    Two_Pi  : constant R := R (2.0) * Pi;
39    Half_Pi : constant R := Pi / R (2.0);
40
41    ---------
42    -- "*" --
43    ---------
44
45    function "*" (Left, Right : Complex) return Complex is
46
47       Scale : constant R := R (R'Machine_Radix) ** ((R'Machine_Emax - 1) / 2);
48       --  In case of overflow, scale the operands by the largest power of the
49       --  radix (to avoid rounding error), so that the square of the scale does
50       --  not overflow itself.
51
52       X : R;
53       Y : R;
54
55    begin
56       X := Left.Re * Right.Re - Left.Im * Right.Im;
57       Y := Left.Re * Right.Im + Left.Im * Right.Re;
58
59       --  If either component overflows, try to scale (skip in fast math mode)
60
61       if not Standard'Fast_Math then
62
63          --  Note that the test below is written as a negation. This is to
64          --  account for the fact that X and Y may be NaNs, because both of
65          --  their operands could overflow. Given that all operations on NaNs
66          --  return false, the test can only be written thus.
67
68          if not (abs (X) <= R'Last) then
69             X := Scale**2 * ((Left.Re / Scale) * (Right.Re / Scale) -
70                              (Left.Im / Scale) * (Right.Im / Scale));
71          end if;
72
73          if not (abs (Y) <= R'Last) then
74             Y := Scale**2 * ((Left.Re / Scale) * (Right.Im / Scale)
75                            + (Left.Im / Scale) * (Right.Re / Scale));
76          end if;
77       end if;
78
79       return (X, Y);
80    end "*";
81
82    function "*" (Left, Right : Imaginary) return Real'Base is
83    begin
84       return -(R (Left) * R (Right));
85    end "*";
86
87    function "*" (Left : Complex; Right : Real'Base) return Complex is
88    begin
89       return Complex'(Left.Re * Right, Left.Im * Right);
90    end "*";
91
92    function "*" (Left : Real'Base; Right : Complex) return Complex is
93    begin
94       return (Left * Right.Re, Left * Right.Im);
95    end "*";
96
97    function "*" (Left : Complex; Right : Imaginary) return Complex is
98    begin
99       return Complex'(-(Left.Im * R (Right)), Left.Re * R (Right));
100    end "*";
101
102    function "*" (Left : Imaginary; Right : Complex) return Complex is
103    begin
104       return Complex'(-(R (Left) * Right.Im), R (Left) * Right.Re);
105    end "*";
106
107    function "*" (Left : Imaginary; Right : Real'Base) return Imaginary is
108    begin
109       return Left * Imaginary (Right);
110    end "*";
111
112    function "*" (Left : Real'Base; Right : Imaginary) return Imaginary is
113    begin
114       return Imaginary (Left * R (Right));
115    end "*";
116
117    ----------
118    -- "**" --
119    ----------
120
121    function "**" (Left : Complex; Right : Integer) return Complex is
122       Result : Complex := (1.0, 0.0);
123       Factor : Complex := Left;
124       Exp    : Integer := Right;
125
126    begin
127       --  We use the standard logarithmic approach, Exp gets shifted right
128       --  testing successive low order bits and Factor is the value of the
129       --  base raised to the next power of 2. For positive exponents we
130       --  multiply the result by this factor, for negative exponents, we
131       --  divide by this factor.
132
133       if Exp >= 0 then
134
135          --  For a positive exponent, if we get a constraint error during
136          --  this loop, it is an overflow, and the constraint error will
137          --  simply be passed on to the caller.
138
139          while Exp /= 0 loop
140             if Exp rem 2 /= 0 then
141                Result := Result * Factor;
142             end if;
143
144             Factor := Factor * Factor;
145             Exp := Exp / 2;
146          end loop;
147
148          return Result;
149
150       else -- Exp < 0 then
151
152          --  For the negative exponent case, a constraint error during this
153          --  calculation happens if Factor gets too large, and the proper
154          --  response is to return 0.0, since what we essentially have is
155          --  1.0 / infinity, and the closest model number will be zero.
156
157          begin
158             while Exp /= 0 loop
159                if Exp rem 2 /= 0 then
160                   Result := Result * Factor;
161                end if;
162
163                Factor := Factor * Factor;
164                Exp := Exp / 2;
165             end loop;
166
167             return R'(1.0) / Result;
168
169          exception
170             when Constraint_Error =>
171                return (0.0, 0.0);
172          end;
173       end if;
174    end "**";
175
176    function "**" (Left : Imaginary; Right : Integer) return Complex is
177       M : constant R := R (Left) ** Right;
178    begin
179       case Right mod 4 is
180          when 0 => return (M,   0.0);
181          when 1 => return (0.0, M);
182          when 2 => return (-M,  0.0);
183          when 3 => return (0.0, -M);
184          when others => raise Program_Error;
185       end case;
186    end "**";
187
188    ---------
189    -- "+" --
190    ---------
191
192    function "+" (Right : Complex) return Complex is
193    begin
194       return Right;
195    end "+";
196
197    function "+" (Left, Right : Complex) return Complex is
198    begin
199       return Complex'(Left.Re + Right.Re, Left.Im + Right.Im);
200    end "+";
201
202    function "+" (Right : Imaginary) return Imaginary is
203    begin
204       return Right;
205    end "+";
206
207    function "+" (Left, Right : Imaginary) return Imaginary is
208    begin
209       return Imaginary (R (Left) + R (Right));
210    end "+";
211
212    function "+" (Left : Complex; Right : Real'Base) return Complex is
213    begin
214       return Complex'(Left.Re + Right, Left.Im);
215    end "+";
216
217    function "+" (Left : Real'Base; Right : Complex) return Complex is
218    begin
219       return Complex'(Left + Right.Re, Right.Im);
220    end "+";
221
222    function "+" (Left : Complex; Right : Imaginary) return Complex is
223    begin
224       return Complex'(Left.Re, Left.Im + R (Right));
225    end "+";
226
227    function "+" (Left : Imaginary; Right : Complex) return Complex is
228    begin
229       return Complex'(Right.Re, R (Left) + Right.Im);
230    end "+";
231
232    function "+" (Left : Imaginary; Right : Real'Base) return Complex is
233    begin
234       return Complex'(Right, R (Left));
235    end "+";
236
237    function "+" (Left : Real'Base; Right : Imaginary) return Complex is
238    begin
239       return Complex'(Left, R (Right));
240    end "+";
241
242    ---------
243    -- "-" --
244    ---------
245
246    function "-" (Right : Complex) return Complex is
247    begin
248       return (-Right.Re, -Right.Im);
249    end "-";
250
251    function "-" (Left, Right : Complex) return Complex is
252    begin
253       return (Left.Re - Right.Re, Left.Im - Right.Im);
254    end "-";
255
256    function "-" (Right : Imaginary) return Imaginary is
257    begin
258       return Imaginary (-R (Right));
259    end "-";
260
261    function "-" (Left, Right : Imaginary) return Imaginary is
262    begin
263       return Imaginary (R (Left) - R (Right));
264    end "-";
265
266    function "-" (Left : Complex; Right : Real'Base) return Complex is
267    begin
268       return Complex'(Left.Re - Right, Left.Im);
269    end "-";
270
271    function "-" (Left : Real'Base; Right : Complex) return Complex is
272    begin
273       return Complex'(Left - Right.Re, -Right.Im);
274    end "-";
275
276    function "-" (Left : Complex; Right : Imaginary) return Complex is
277    begin
278       return Complex'(Left.Re, Left.Im - R (Right));
279    end "-";
280
281    function "-" (Left : Imaginary; Right : Complex) return Complex is
282    begin
283       return Complex'(-Right.Re, R (Left) - Right.Im);
284    end "-";
285
286    function "-" (Left : Imaginary; Right : Real'Base) return Complex is
287    begin
288       return Complex'(-Right, R (Left));
289    end "-";
290
291    function "-" (Left : Real'Base; Right : Imaginary) return Complex is
292    begin
293       return Complex'(Left, -R (Right));
294    end "-";
295
296    ---------
297    -- "/" --
298    ---------
299
300    function "/" (Left, Right : Complex) return Complex is
301       a : constant R := Left.Re;
302       b : constant R := Left.Im;
303       c : constant R := Right.Re;
304       d : constant R := Right.Im;
305
306    begin
307       if c = 0.0 and then d = 0.0 then
308          raise Constraint_Error;
309       else
310          return Complex'(Re => ((a * c) + (b * d)) / (c ** 2 + d ** 2),
311                          Im => ((b * c) - (a * d)) / (c ** 2 + d ** 2));
312       end if;
313    end "/";
314
315    function "/" (Left, Right : Imaginary) return Real'Base is
316    begin
317       return R (Left) / R (Right);
318    end "/";
319
320    function "/" (Left : Complex; Right : Real'Base) return Complex is
321    begin
322       return Complex'(Left.Re / Right, Left.Im / Right);
323    end "/";
324
325    function "/" (Left : Real'Base; Right : Complex) return Complex is
326       a : constant R := Left;
327       c : constant R := Right.Re;
328       d : constant R := Right.Im;
329    begin
330       return Complex'(Re =>   (a * c) / (c ** 2 + d ** 2),
331                       Im => -((a * d) / (c ** 2 + d ** 2)));
332    end "/";
333
334    function "/" (Left : Complex; Right : Imaginary) return Complex is
335       a : constant R := Left.Re;
336       b : constant R := Left.Im;
337       d : constant R := R (Right);
338
339    begin
340       return (b / d,  -(a / d));
341    end "/";
342
343    function "/" (Left : Imaginary; Right : Complex) return Complex is
344       b : constant R := R (Left);
345       c : constant R := Right.Re;
346       d : constant R := Right.Im;
347
348    begin
349       return (Re => b * d / (c ** 2 + d ** 2),
350               Im => b * c / (c ** 2 + d ** 2));
351    end "/";
352
353    function "/" (Left : Imaginary; Right : Real'Base) return Imaginary is
354    begin
355       return Imaginary (R (Left) / Right);
356    end "/";
357
358    function "/" (Left : Real'Base; Right : Imaginary) return Imaginary is
359    begin
360       return Imaginary (-(Left / R (Right)));
361    end "/";
362
363    ---------
364    -- "<" --
365    ---------
366
367    function "<" (Left, Right : Imaginary) return Boolean is
368    begin
369       return R (Left) < R (Right);
370    end "<";
371
372    ----------
373    -- "<=" --
374    ----------
375
376    function "<=" (Left, Right : Imaginary) return Boolean is
377    begin
378       return R (Left) <= R (Right);
379    end "<=";
380
381    ---------
382    -- ">" --
383    ---------
384
385    function ">" (Left, Right : Imaginary) return Boolean is
386    begin
387       return R (Left) > R (Right);
388    end ">";
389
390    ----------
391    -- ">=" --
392    ----------
393
394    function ">=" (Left, Right : Imaginary) return Boolean is
395    begin
396       return R (Left) >= R (Right);
397    end ">=";
398
399    -----------
400    -- "abs" --
401    -----------
402
403    function "abs" (Right : Imaginary) return Real'Base is
404    begin
405       return abs R (Right);
406    end "abs";
407
408    --------------
409    -- Argument --
410    --------------
411
412    function Argument (X : Complex) return Real'Base is
413       a   : constant R := X.Re;
414       b   : constant R := X.Im;
415       arg : R;
416
417    begin
418       if b = 0.0 then
419
420          if a >= 0.0 then
421             return 0.0;
422          else
423             return R'Copy_Sign (Pi, b);
424          end if;
425
426       elsif a = 0.0 then
427
428          if b >= 0.0 then
429             return Half_Pi;
430          else
431             return -Half_Pi;
432          end if;
433
434       else
435          arg := R (Atan (Double (abs (b / a))));
436
437          if a > 0.0 then
438             if b > 0.0 then
439                return arg;
440             else                  --  b < 0.0
441                return -arg;
442             end if;
443
444          else                     --  a < 0.0
445             if b >= 0.0 then
446                return Pi - arg;
447             else                  --  b < 0.0
448                return -(Pi - arg);
449             end if;
450          end if;
451       end if;
452
453    exception
454       when Constraint_Error =>
455          if b > 0.0 then
456             return Half_Pi;
457          else
458             return -Half_Pi;
459          end if;
460    end Argument;
461
462    function Argument (X : Complex; Cycle : Real'Base) return Real'Base is
463    begin
464       if Cycle > 0.0 then
465          return Argument (X) * Cycle / Two_Pi;
466       else
467          raise Argument_Error;
468       end if;
469    end Argument;
470
471    ----------------------------
472    -- Compose_From_Cartesian --
473    ----------------------------
474
475    function Compose_From_Cartesian (Re, Im : Real'Base) return Complex is
476    begin
477       return (Re, Im);
478    end Compose_From_Cartesian;
479
480    function Compose_From_Cartesian (Re : Real'Base) return Complex is
481    begin
482       return (Re, 0.0);
483    end Compose_From_Cartesian;
484
485    function Compose_From_Cartesian (Im : Imaginary) return Complex is
486    begin
487       return (0.0, R (Im));
488    end Compose_From_Cartesian;
489
490    ------------------------
491    -- Compose_From_Polar --
492    ------------------------
493
494    function Compose_From_Polar (
495      Modulus, Argument : Real'Base)
496      return Complex
497    is
498    begin
499       if Modulus = 0.0 then
500          return (0.0, 0.0);
501       else
502          return (Modulus * R (Cos (Double (Argument))),
503                  Modulus * R (Sin (Double (Argument))));
504       end if;
505    end Compose_From_Polar;
506
507    function Compose_From_Polar (
508      Modulus, Argument, Cycle : Real'Base)
509      return Complex
510    is
511       Arg : Real'Base;
512
513    begin
514       if Modulus = 0.0 then
515          return (0.0, 0.0);
516
517       elsif Cycle > 0.0 then
518          if Argument = 0.0 then
519             return (Modulus, 0.0);
520
521          elsif Argument = Cycle / 4.0 then
522             return (0.0, Modulus);
523
524          elsif Argument = Cycle / 2.0 then
525             return (-Modulus, 0.0);
526
527          elsif Argument = 3.0 * Cycle / R (4.0) then
528             return (0.0, -Modulus);
529          else
530             Arg := Two_Pi * Argument / Cycle;
531             return (Modulus * R (Cos (Double (Arg))),
532                     Modulus * R (Sin (Double (Arg))));
533          end if;
534       else
535          raise Argument_Error;
536       end if;
537    end Compose_From_Polar;
538
539    ---------------
540    -- Conjugate --
541    ---------------
542
543    function Conjugate (X : Complex) return Complex is
544    begin
545       return Complex'(X.Re, -X.Im);
546    end Conjugate;
547
548    --------
549    -- Im --
550    --------
551
552    function Im (X : Complex) return Real'Base is
553    begin
554       return X.Im;
555    end Im;
556
557    function Im (X : Imaginary) return Real'Base is
558    begin
559       return R (X);
560    end Im;
561
562    -------------
563    -- Modulus --
564    -------------
565
566    function Modulus (X : Complex) return Real'Base is
567       Re2, Im2 : R;
568
569    begin
570
571       begin
572          Re2 := X.Re ** 2;
573
574          --  To compute (a**2 + b**2) ** (0.5) when a**2 may be out of bounds,
575          --  compute a * (1 + (b/a) **2) ** (0.5). On a machine where the
576          --  squaring does not raise constraint_error but generates infinity,
577          --  we can use an explicit comparison to determine whether to use
578          --  the scaling expression.
579
580          --  The scaling expression is computed in double format throughout
581          --  in order to prevent inaccuracies on machines where not all
582          --  immediate expressions are rounded, such as PowerPC.
583
584          --  ??? same weird test, why not Re2 > R'Last ???
585          if not (Re2 <= R'Last) then
586             raise Constraint_Error;
587          end if;
588
589       exception
590          when Constraint_Error =>
591             return R (Double (abs (X.Re))
592               * Sqrt (1.0 + (Double (X.Im) / Double (X.Re)) ** 2));
593       end;
594
595       begin
596          Im2 := X.Im ** 2;
597
598          --  ??? same weird test
599          if not (Im2 <= R'Last) then
600             raise Constraint_Error;
601          end if;
602
603       exception
604          when Constraint_Error =>
605             return R (Double (abs (X.Im))
606               * Sqrt (1.0 + (Double (X.Re) / Double (X.Im)) ** 2));
607       end;
608
609       --  Now deal with cases of underflow. If only one of the squares
610       --  underflows, return the modulus of the other component. If both
611       --  squares underflow, use scaling as above.
612
613       if Re2 = 0.0 then
614
615          if X.Re = 0.0 then
616             return abs (X.Im);
617
618          elsif Im2 = 0.0 then
619
620             if X.Im = 0.0 then
621                return abs (X.Re);
622
623             else
624                if abs (X.Re) > abs (X.Im) then
625                   return
626                     R (Double (abs (X.Re))
627                       * Sqrt (1.0 + (Double (X.Im) / Double (X.Re)) ** 2));
628                else
629                   return
630                     R (Double (abs (X.Im))
631                       * Sqrt (1.0 + (Double (X.Re) / Double (X.Im)) ** 2));
632                end if;
633             end if;
634
635          else
636             return abs (X.Im);
637          end if;
638
639       elsif Im2 = 0.0 then
640          return abs (X.Re);
641
642       --  In all other cases, the naive computation will do
643
644       else
645          return R (Sqrt (Double (Re2 + Im2)));
646       end if;
647    end Modulus;
648
649    --------
650    -- Re --
651    --------
652
653    function Re (X : Complex) return Real'Base is
654    begin
655       return X.Re;
656    end Re;
657
658    ------------
659    -- Set_Im --
660    ------------
661
662    procedure Set_Im (X : in out Complex; Im : Real'Base) is
663    begin
664       X.Im := Im;
665    end Set_Im;
666
667    procedure Set_Im (X : out Imaginary; Im : Real'Base) is
668    begin
669       X := Imaginary (Im);
670    end Set_Im;
671
672    ------------
673    -- Set_Re --
674    ------------
675
676    procedure Set_Re (X : in out Complex; Re : Real'Base) is
677    begin
678       X.Re := Re;
679    end Set_Re;
680
681 end Ada.Numerics.Generic_Complex_Types;