1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1992-2006, Free Software Foundation, Inc. --
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 2, 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. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
25 ------------------------------------------------------------------------------
27 with Einfo
; use Einfo
;
28 with Errout
; use Errout
;
29 with Sem_Util
; use Sem_Util
;
30 with Ttypef
; use Ttypef
;
31 with Targparm
; use Targparm
;
33 package body Eval_Fat
is
35 Radix
: constant Int
:= 2;
36 -- This code is currently only correct for the radix 2 case. We use
37 -- the symbolic value Radix where possible to help in the unlikely
38 -- case of anyone ever having to adjust this code for another value,
39 -- and for documentation purposes.
41 -- Another assumption is that the range of the floating-point type
42 -- is symmetric around zero.
44 type Radix_Power_Table
is array (Int
range 1 .. 4) of Int
;
46 Radix_Powers
: constant Radix_Power_Table
:=
47 (Radix
** 1, Radix
** 2, Radix
** 3, Radix
** 4);
49 -----------------------
50 -- Local Subprograms --
51 -----------------------
58 Mode
: Rounding_Mode
:= Round
);
59 -- Decomposes a non-zero floating-point number into fraction and
60 -- exponent parts. The fraction is in the interval 1.0 / Radix ..
61 -- T'Pred (1.0) and uses Rbase = Radix.
62 -- The result is rounded to a nearest machine number.
64 procedure Decompose_Int
69 Mode
: Rounding_Mode
);
70 -- This is similar to Decompose, except that the Fraction value returned
71 -- is an integer representing the value Fraction * Scale, where Scale is
72 -- the value (Radix ** Machine_Mantissa (RT)). The value is obtained by
73 -- using biased rounding (halfway cases round away from zero), round to
74 -- even, a floor operation or a ceiling operation depending on the setting
75 -- of Mode (see corresponding descriptions in Urealp).
77 function Machine_Emin
(RT
: R
) return Int
;
78 -- Return value of the Machine_Emin attribute
84 function Adjacent
(RT
: R
; X
, Towards
: T
) return T
is
88 elsif Towards
> X
then
99 function Ceiling
(RT
: R
; X
: T
) return T
is
100 XT
: constant T
:= Truncation
(RT
, X
);
102 if UR_Is_Negative
(X
) then
115 function Compose
(RT
: R
; Fraction
: T
; Exponent
: UI
) return T
is
119 if UR_Is_Zero
(Fraction
) then
122 Decompose
(RT
, Fraction
, Arg_Frac
, Arg_Exp
);
123 return Scaling
(RT
, Arg_Frac
, Exponent
);
131 function Copy_Sign
(RT
: R
; Value
, Sign
: T
) return T
is
132 pragma Warnings
(Off
, RT
);
138 if UR_Is_Negative
(Sign
) then
154 Mode
: Rounding_Mode
:= Round
)
159 Decompose_Int
(RT
, abs X
, Int_F
, Exponent
, Mode
);
161 Fraction
:= UR_From_Components
163 Den
=> UI_From_Int
(Machine_Mantissa
(RT
)),
167 if UR_Is_Negative
(X
) then
168 Fraction
:= -Fraction
;
178 -- This procedure should be modified with care, as there are many
179 -- non-obvious details that may cause problems that are hard to
180 -- detect. The cases of positive and negative zeroes are also
181 -- special and should be verified separately.
183 procedure Decompose_Int
188 Mode
: Rounding_Mode
)
190 Base
: Int
:= Rbase
(X
);
191 N
: UI
:= abs Numerator
(X
);
192 D
: UI
:= Denominator
(X
);
197 -- True iff Fraction is even
199 Most_Significant_Digit
: constant UI
:=
200 Radix
** (Machine_Mantissa
(RT
) - 1);
202 Uintp_Mark
: Uintp
.Save_Mark
;
203 -- The code is divided into blocks that systematically release
204 -- intermediate values (this routine generates lots of junk!)
207 Calculate_D_And_Exponent_1
: begin
211 -- In cases where Base > 1, the actual denominator is
212 -- Base**D. For cases where Base is a power of Radix, use
213 -- the value 1 for the Denominator and adjust the exponent.
215 -- Note: Exponent has different sign from D, because D is a divisor
217 for Power
in 1 .. Radix_Powers
'Last loop
218 if Base
= Radix_Powers
(Power
) then
219 Exponent
:= -D
* Power
;
226 Release_And_Save
(Uintp_Mark
, D
, Exponent
);
227 end Calculate_D_And_Exponent_1
;
230 Calculate_Exponent
: begin
233 -- For bases that are a multiple of the Radix, divide
234 -- the base by Radix and adjust the Exponent. This will
235 -- help because D will be much smaller and faster to process.
237 -- This occurs for decimal bases on a machine with binary
238 -- floating-point for example. When calculating 1E40,
239 -- with Radix = 2, N will be 93 bits instead of 133.
247 -- = -------------------------- * Radix
249 -- (Base/Radix) * Radix
252 -- = --------------- * Radix
256 -- This code is commented out, because it causes numerous
257 -- failures in the regression suite. To be studied ???
259 while False and then Base
> 0 and then Base
mod Radix
= 0 loop
260 Base
:= Base
/ Radix
;
261 Exponent
:= Exponent
+ D
;
264 Release_And_Save
(Uintp_Mark
, Exponent
);
265 end Calculate_Exponent
;
267 -- For remaining bases we must actually compute
268 -- the exponentiation.
270 -- Because the exponentiation can be negative, and D must
271 -- be integer, the numerator is corrected instead.
273 Calculate_N_And_D
: begin
277 N
:= N
* Base
** (-D
);
283 Release_And_Save
(Uintp_Mark
, N
, D
);
284 end Calculate_N_And_D
;
289 -- Now scale N and D so that N / D is a value in the
290 -- interval [1.0 / Radix, 1.0) and adjust Exponent accordingly,
291 -- so the value N / D * Radix ** Exponent remains unchanged.
293 -- Step 1 - Adjust N so N / D >= 1 / Radix, or N = 0
295 -- N and D are positive, so N / D >= 1 / Radix implies N * Radix >= D.
296 -- This scaling is not possible for N is Uint_0 as there
297 -- is no way to scale Uint_0 so the first digit is non-zero.
299 Calculate_N_And_Exponent
: begin
302 N_Times_Radix
:= N
* Radix
;
305 while not (N_Times_Radix
>= D
) loop
307 Exponent
:= Exponent
- 1;
309 N_Times_Radix
:= N
* Radix
;
313 Release_And_Save
(Uintp_Mark
, N
, Exponent
);
314 end Calculate_N_And_Exponent
;
316 -- Step 2 - Adjust D so N / D < 1
318 -- Scale up D so N / D < 1, so N < D
320 Calculate_D_And_Exponent_2
: begin
323 while not (N
< D
) loop
325 -- As N / D >= 1, N / (D * Radix) will be at least 1 / Radix,
326 -- so the result of Step 1 stays valid
329 Exponent
:= Exponent
+ 1;
332 Release_And_Save
(Uintp_Mark
, D
, Exponent
);
333 end Calculate_D_And_Exponent_2
;
335 -- Here the value N / D is in the range [1.0 / Radix .. 1.0)
337 -- Now find the fraction by doing a very simple-minded
338 -- division until enough digits have been computed.
340 -- This division works for all radices, but is only efficient for
341 -- a binary radix. It is just like a manual division algorithm,
342 -- but instead of moving the denominator one digit right, we move
343 -- the numerator one digit left so the numerator and denominator
349 Calculate_Fraction_And_N
: begin
355 Fraction
:= Fraction
+ 1;
359 -- Stop when the result is in [1.0 / Radix, 1.0)
361 exit when Fraction
>= Most_Significant_Digit
;
364 Fraction
:= Fraction
* Radix
;
368 Release_And_Save
(Uintp_Mark
, Fraction
, N
);
369 end Calculate_Fraction_And_N
;
371 Calculate_Fraction_And_Exponent
: begin
374 -- Determine correct rounding based on the remainder which is in
375 -- N and the divisor D. The rounding is performed on the absolute
376 -- value of X, so Ceiling and Floor need to check for the sign of
382 -- This rounding mode should not be used for static
383 -- expressions, but only for compile-time evaluation
384 -- of non-static expressions.
386 if (Even
and then N
* 2 > D
)
388 (not Even
and then N
* 2 >= D
)
390 Fraction
:= Fraction
+ 1;
395 -- Do not round to even as is done with IEEE arithmetic,
396 -- but instead round away from zero when the result is
397 -- exactly between two machine numbers. See RM 4.9(38).
400 Fraction
:= Fraction
+ 1;
404 if N
> Uint_0
and then not UR_Is_Negative
(X
) then
405 Fraction
:= Fraction
+ 1;
409 if N
> Uint_0
and then UR_Is_Negative
(X
) then
410 Fraction
:= Fraction
+ 1;
414 -- The result must be normalized to [1.0/Radix, 1.0),
415 -- so adjust if the result is 1.0 because of rounding.
417 if Fraction
= Most_Significant_Digit
* Radix
then
418 Fraction
:= Most_Significant_Digit
;
419 Exponent
:= Exponent
+ 1;
422 -- Put back sign after applying the rounding
424 if UR_Is_Negative
(X
) then
425 Fraction
:= -Fraction
;
428 Release_And_Save
(Uintp_Mark
, Fraction
, Exponent
);
429 end Calculate_Fraction_And_Exponent
;
436 function Exponent
(RT
: R
; X
: T
) return UI
is
440 if UR_Is_Zero
(X
) then
443 Decompose_Int
(RT
, X
, X_Frac
, X_Exp
, Round_Even
);
452 function Floor
(RT
: R
; X
: T
) return T
is
453 XT
: constant T
:= Truncation
(RT
, X
);
456 if UR_Is_Positive
(X
) then
471 function Fraction
(RT
: R
; X
: T
) return T
is
475 if UR_Is_Zero
(X
) then
478 Decompose
(RT
, X
, X_Frac
, X_Exp
);
487 function Leading_Part
(RT
: R
; X
: T
; Radix_Digits
: UI
) return T
is
488 RD
: constant UI
:= UI_Min
(Radix_Digits
, Machine_Mantissa
(RT
));
492 L
:= Exponent
(RT
, X
) - RD
;
493 Y
:= UR_From_Uint
(UR_Trunc
(Scaling
(RT
, X
, -L
)));
494 return Scaling
(RT
, Y
, L
);
504 Mode
: Rounding_Mode
;
505 Enode
: Node_Id
) return T
509 Emin
: constant UI
:= UI_From_Int
(Machine_Emin
(RT
));
512 if UR_Is_Zero
(X
) then
516 Decompose
(RT
, X
, X_Frac
, X_Exp
, Mode
);
518 -- Case of denormalized number or (gradual) underflow
520 -- A denormalized number is one with the minimum exponent Emin, but
521 -- that breaks the assumption that the first digit of the mantissa
522 -- is a one. This allows the first non-zero digit to be in any
523 -- of the remaining Mant - 1 spots. The gap between subsequent
524 -- denormalized numbers is the same as for the smallest normalized
525 -- numbers. However, the number of significant digits left decreases
526 -- as a result of the mantissa now having leading seros.
530 Emin_Den
: constant UI
:=
532 (Machine_Emin
(RT
) - Machine_Mantissa
(RT
) + 1);
534 if X_Exp
< Emin_Den
or not Denorm_On_Target
then
535 if UR_Is_Negative
(X
) then
537 ("floating-point value underflows to -0.0?", Enode
);
542 ("floating-point value underflows to 0.0?", Enode
);
546 elsif Denorm_On_Target
then
548 -- Emin - Mant <= X_Exp < Emin, so result is denormal.
549 -- Handle gradual underflow by first computing the
550 -- number of significant bits still available for the
551 -- mantissa and then truncating the fraction to this
554 -- If this value is different from the original
555 -- fraction, precision is lost due to gradual underflow.
557 -- We probably should round here and prevent double
558 -- rounding as a result of first rounding to a model
559 -- number and then to a machine number. However, this
560 -- is an extremely rare case that is not worth the extra
561 -- complexity. In any case, a warning is issued in cases
562 -- where gradual underflow occurs.
565 Denorm_Sig_Bits
: constant UI
:= X_Exp
- Emin_Den
+ 1;
567 X_Frac_Denorm
: constant T
:= UR_From_Components
568 (UR_Trunc
(Scaling
(RT
, abs X_Frac
, Denorm_Sig_Bits
)),
574 if X_Frac_Denorm
/= X_Frac
then
576 ("gradual underflow causes loss of precision?",
578 X_Frac
:= X_Frac_Denorm
;
585 return Scaling
(RT
, X_Frac
, X_Exp
);
593 function Machine_Emin
(RT
: R
) return Int
is
594 Digs
: constant UI
:= Digits_Value
(RT
);
598 if Vax_Float
(RT
) then
599 if Digs
= VAXFF_Digits
then
600 Emin
:= VAXFF_Machine_Emin
;
602 elsif Digs
= VAXDF_Digits
then
603 Emin
:= VAXDF_Machine_Emin
;
606 pragma Assert
(Digs
= VAXGF_Digits
);
607 Emin
:= VAXGF_Machine_Emin
;
610 elsif Is_AAMP_Float
(RT
) then
611 if Digs
= AAMPS_Digits
then
612 Emin
:= AAMPS_Machine_Emin
;
615 pragma Assert
(Digs
= AAMPL_Digits
);
616 Emin
:= AAMPL_Machine_Emin
;
620 if Digs
= IEEES_Digits
then
621 Emin
:= IEEES_Machine_Emin
;
623 elsif Digs
= IEEEL_Digits
then
624 Emin
:= IEEEL_Machine_Emin
;
627 pragma Assert
(Digs
= IEEEX_Digits
);
628 Emin
:= IEEEX_Machine_Emin
;
635 ----------------------
636 -- Machine_Mantissa --
637 ----------------------
639 function Machine_Mantissa
(RT
: R
) return Nat
is
640 Digs
: constant UI
:= Digits_Value
(RT
);
644 if Vax_Float
(RT
) then
645 if Digs
= VAXFF_Digits
then
646 Mant
:= VAXFF_Machine_Mantissa
;
648 elsif Digs
= VAXDF_Digits
then
649 Mant
:= VAXDF_Machine_Mantissa
;
652 pragma Assert
(Digs
= VAXGF_Digits
);
653 Mant
:= VAXGF_Machine_Mantissa
;
656 elsif Is_AAMP_Float
(RT
) then
657 if Digs
= AAMPS_Digits
then
658 Mant
:= AAMPS_Machine_Mantissa
;
661 pragma Assert
(Digs
= AAMPL_Digits
);
662 Mant
:= AAMPL_Machine_Mantissa
;
666 if Digs
= IEEES_Digits
then
667 Mant
:= IEEES_Machine_Mantissa
;
669 elsif Digs
= IEEEL_Digits
then
670 Mant
:= IEEEL_Machine_Mantissa
;
673 pragma Assert
(Digs
= IEEEX_Digits
);
674 Mant
:= IEEEX_Machine_Mantissa
;
679 end Machine_Mantissa
;
685 function Machine_Radix
(RT
: R
) return Nat
is
686 pragma Warnings
(Off
, RT
);
695 function Model
(RT
: R
; X
: T
) return T
is
699 Decompose
(RT
, X
, X_Frac
, X_Exp
);
700 return Compose
(RT
, X_Frac
, X_Exp
);
707 function Pred
(RT
: R
; X
: T
) return T
is
709 return -Succ
(RT
, -X
);
716 function Remainder
(RT
: R
; X
, Y
: T
) return T
is
731 if UR_Is_Positive
(X
) then
743 P_Exp
:= Exponent
(RT
, P
);
746 -- ??? what about zero cases?
747 Decompose
(RT
, Arg
, Arg_Frac
, Arg_Exp
);
748 Decompose
(RT
, P
, P_Frac
, P_Exp
);
750 P
:= Compose
(RT
, P_Frac
, Arg_Exp
);
751 K
:= Arg_Exp
- P_Exp
;
755 for Cnt
in reverse 0 .. UI_To_Int
(K
) loop
756 if IEEE_Rem
>= P
then
758 IEEE_Rem
:= IEEE_Rem
- P
;
767 -- That completes the calculation of modulus remainder. The final step
768 -- is get the IEEE remainder. Here we compare Rem with (abs Y) / 2.
772 B
:= abs Y
* Ureal_Half
;
775 A
:= IEEE_Rem
* Ureal_2
;
779 if A
> B
or else (A
= B
and then not P_Even
) then
780 IEEE_Rem
:= IEEE_Rem
- abs Y
;
783 return Sign_X
* IEEE_Rem
;
790 function Rounding
(RT
: R
; X
: T
) return T
is
795 Result
:= Truncation
(RT
, abs X
);
796 Tail
:= abs X
- Result
;
798 if Tail
>= Ureal_Half
then
799 Result
:= Result
+ Ureal_1
;
802 if UR_Is_Negative
(X
) then
813 function Scaling
(RT
: R
; X
: T
; Adjustment
: UI
) return T
is
814 pragma Warnings
(Off
, RT
);
817 if Rbase
(X
) = Radix
then
818 return UR_From_Components
819 (Num
=> Numerator
(X
),
820 Den
=> Denominator
(X
) - Adjustment
,
822 Negative
=> UR_Is_Negative
(X
));
824 elsif Adjustment
>= 0 then
825 return X
* Radix
** Adjustment
;
827 return X
/ Radix
** (-Adjustment
);
835 function Succ
(RT
: R
; X
: T
) return T
is
836 Emin
: constant UI
:= UI_From_Int
(Machine_Emin
(RT
));
837 Mantissa
: constant UI
:= UI_From_Int
(Machine_Mantissa
(RT
));
838 Exp
: UI
:= UI_Max
(Emin
, Exponent
(RT
, X
));
843 if UR_Is_Zero
(X
) then
847 -- Set exponent such that the radix point will be directly
848 -- following the mantissa after scaling
850 if Denorm_On_Target
or Exp
/= Emin
then
851 Exp
:= Exp
- Mantissa
;
856 Frac
:= Scaling
(RT
, X
, -Exp
);
857 New_Frac
:= Ceiling
(RT
, Frac
);
859 if New_Frac
= Frac
then
860 if New_Frac
= Scaling
(RT
, -Ureal_1
, Mantissa
- 1) then
861 New_Frac
:= New_Frac
+ Scaling
(RT
, Ureal_1
, Uint_Minus_1
);
863 New_Frac
:= New_Frac
+ Ureal_1
;
867 return Scaling
(RT
, New_Frac
, Exp
);
874 function Truncation
(RT
: R
; X
: T
) return T
is
875 pragma Warnings
(Off
, RT
);
877 return UR_From_Uint
(UR_Trunc
(X
));
880 -----------------------
881 -- Unbiased_Rounding --
882 -----------------------
884 function Unbiased_Rounding
(RT
: R
; X
: T
) return T
is
885 Abs_X
: constant T
:= abs X
;
890 Result
:= Truncation
(RT
, Abs_X
);
891 Tail
:= Abs_X
- Result
;
893 if Tail
> Ureal_Half
then
894 Result
:= Result
+ Ureal_1
;
896 elsif Tail
= Ureal_Half
then
898 Truncation
(RT
, (Result
/ Ureal_2
) + Ureal_Half
);
901 if UR_Is_Negative
(X
) then
903 elsif UR_Is_Positive
(X
) then
906 -- For zero case, make sure sign of zero is preserved
911 end Unbiased_Rounding
;