diff options
Diffstat (limited to 'gcc/ada/s-imgrea.adb')
-rw-r--r-- | gcc/ada/s-imgrea.adb | 699 |
1 files changed, 0 insertions, 699 deletions
diff --git a/gcc/ada/s-imgrea.adb b/gcc/ada/s-imgrea.adb deleted file mode 100644 index 62ec93a..0000000 --- a/gcc/ada/s-imgrea.adb +++ /dev/null @@ -1,699 +0,0 @@ ------------------------------------------------------------------------------- --- -- --- GNAT RUN-TIME COMPONENTS -- --- -- --- S Y S T E M . I M G _ R E A L -- --- -- --- B o d y -- --- -- --- Copyright (C) 1992-2016, Free Software Foundation, Inc. -- --- -- --- GNAT is free software; you can redistribute it and/or modify it under -- --- terms of the GNU General Public License as published by the Free Soft- -- --- ware Foundation; either version 3, or (at your option) any later ver- -- --- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- --- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- --- or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- <http://www.gnu.org/licenses/>. -- --- -- --- GNAT was originally developed by the GNAT team at New York University. -- --- Extensive contributions were provided by Ada Core Technologies Inc. -- --- -- ------------------------------------------------------------------------------- - -with System.Img_LLU; use System.Img_LLU; -with System.Img_Uns; use System.Img_Uns; -with System.Powten_Table; use System.Powten_Table; -with System.Unsigned_Types; use System.Unsigned_Types; -with System.Float_Control; - -package body System.Img_Real is - - -- The following defines the maximum number of digits that we can convert - -- accurately. This is limited by the precision of Long_Long_Float, and - -- also by the number of digits we can hold in Long_Long_Unsigned, which - -- is the integer type we use as an intermediate for the result. - - -- We assume that in practice, the limitation will come from the digits - -- value, rather than the integer value. This is true for typical IEEE - -- implementations, and at worst, the only loss is for some precision - -- in very high precision floating-point output. - - -- Note that in the following, the "-2" accounts for the sign and one - -- extra digits, since we need the maximum number of 9's that can be - -- supported, e.g. for the normal 64 bit case, Long_Long_Integer'Width - -- is 21, since the maximum value (approx 1.6 * 10**19) has 20 digits, - -- but the maximum number of 9's that can be supported is 19. - - Maxdigs : constant := - Natural'Min - (Long_Long_Unsigned'Width - 2, Long_Long_Float'Digits); - - Unsdigs : constant := Unsigned'Width - 2; - -- Number of digits that can be converted using type Unsigned - -- See above for the explanation of the -2. - - Maxscaling : constant := 5000; - -- Max decimal scaling required during conversion of floating-point - -- numbers to decimal. This is used to defend against infinite - -- looping in the conversion, as can be caused by erroneous executions. - -- The largest exponent used on any current system is 2**16383, which - -- is approximately 10**4932, and the highest number of decimal digits - -- is about 35 for 128-bit floating-point formats, so 5000 leaves - -- enough room for scaling such values - - function Is_Negative (V : Long_Long_Float) return Boolean; - pragma Import (Intrinsic, Is_Negative); - - -------------------------- - -- Image_Floating_Point -- - -------------------------- - - procedure Image_Floating_Point - (V : Long_Long_Float; - S : in out String; - P : out Natural; - Digs : Natural) - is - pragma Assert (S'First = 1); - - begin - -- Decide whether a blank should be prepended before the call to - -- Set_Image_Real. We generate a blank for positive values, and - -- also for positive zeroes. For negative zeroes, we generate a - -- space only if Signed_Zeroes is True (the RM only permits the - -- output of -0.0 on targets where this is the case). We can of - -- course still see a -0.0 on a target where Signed_Zeroes is - -- False (since this attribute refers to the proper handling of - -- negative zeroes, not to their existence). We do not generate - -- a blank for positive infinity, since we output an explicit +. - - if (not Is_Negative (V) and then V <= Long_Long_Float'Last) - or else (not Long_Long_Float'Signed_Zeros and then V = -0.0) - then - S (1) := ' '; - P := 1; - else - P := 0; - end if; - - Set_Image_Real (V, S, P, 1, Digs - 1, 3); - end Image_Floating_Point; - - -------------------------------- - -- Image_Ordinary_Fixed_Point -- - -------------------------------- - - procedure Image_Ordinary_Fixed_Point - (V : Long_Long_Float; - S : in out String; - P : out Natural; - Aft : Natural) - is - pragma Assert (S'First = 1); - - begin - -- Output space at start if non-negative - - if V >= 0.0 then - S (1) := ' '; - P := 1; - else - P := 0; - end if; - - Set_Image_Real (V, S, P, 1, Aft, 0); - end Image_Ordinary_Fixed_Point; - - -------------------- - -- Set_Image_Real -- - -------------------- - - procedure Set_Image_Real - (V : Long_Long_Float; - S : out String; - P : in out Natural; - Fore : Natural; - Aft : Natural; - Exp : Natural) - is - NFrac : constant Natural := Natural'Max (Aft, 1); - Sign : Character; - X : Long_Long_Float; - Scale : Integer; - Expon : Integer; - - Field_Max : constant := 255; - -- This should be the same value as Ada.[Wide_]Text_IO.Field'Last. - -- It is not worth dragging in Ada.Text_IO to pick up this value, - -- since it really should never be necessary to change it. - - Digs : String (1 .. 2 * Field_Max + 16); - -- Array used to hold digits of converted integer value. This is a - -- large enough buffer to accommodate ludicrous values of Fore and Aft. - - Ndigs : Natural; - -- Number of digits stored in Digs (and also subscript of last digit) - - procedure Adjust_Scale (S : Natural); - -- Adjusts the value in X by multiplying or dividing by a power of - -- ten so that it is in the range 10**(S-1) <= X < 10**S. Includes - -- adding 0.5 to round the result, readjusting if the rounding causes - -- the result to wander out of the range. Scale is adjusted to reflect - -- the power of ten used to divide the result (i.e. one is added to - -- the scale value for each division by 10.0, or one is subtracted - -- for each multiplication by 10.0). - - procedure Convert_Integer; - -- Takes the value in X, outputs integer digits into Digs. On return, - -- Ndigs is set to the number of digits stored. The digits are stored - -- in Digs (1 .. Ndigs), - - procedure Set (C : Character); - -- Sets character C in output buffer - - procedure Set_Blanks_And_Sign (N : Integer); - -- Sets leading blanks and minus sign if needed. N is the number of - -- positions to be filled (a minus sign is output even if N is zero - -- or negative, but for a positive value, if N is non-positive, then - -- the call has no effect). - - procedure Set_Digs (S, E : Natural); - -- Set digits S through E from Digs buffer. No effect if S > E - - procedure Set_Special_Fill (N : Natural); - -- After outputting +Inf, -Inf or NaN, this routine fills out the - -- rest of the field with * characters. The argument is the number - -- of characters output so far (either 3 or 4) - - procedure Set_Zeros (N : Integer); - -- Set N zeros, no effect if N is negative - - pragma Inline (Set); - pragma Inline (Set_Digs); - pragma Inline (Set_Zeros); - - ------------------ - -- Adjust_Scale -- - ------------------ - - procedure Adjust_Scale (S : Natural) is - Lo : Natural; - Hi : Natural; - Mid : Natural; - XP : Long_Long_Float; - - begin - -- Cases where scaling up is required - - if X < Powten (S - 1) then - - -- What we are looking for is a power of ten to multiply X by - -- so that the result lies within the required range. - - loop - XP := X * Powten (Maxpow); - exit when XP >= Powten (S - 1) or else Scale < -Maxscaling; - X := XP; - Scale := Scale - Maxpow; - end loop; - - -- The following exception is only raised in case of erroneous - -- execution, where a number was considered valid but still - -- fails to scale up. One situation where this can happen is - -- when a system which is supposed to be IEEE-compliant, but - -- has been reconfigured to flush denormals to zero. - - if Scale < -Maxscaling then - raise Constraint_Error; - end if; - - -- Here we know that we must multiply by at least 10**1 and that - -- 10**Maxpow takes us too far: binary search to find right one. - - -- Because of roundoff errors, it is possible for the value - -- of XP to be just outside of the interval when Lo >= Hi. In - -- that case we adjust explicitly by a factor of 10. This - -- can only happen with a value that is very close to an - -- exact power of 10. - - Lo := 1; - Hi := Maxpow; - - loop - Mid := (Lo + Hi) / 2; - XP := X * Powten (Mid); - - if XP < Powten (S - 1) then - - if Lo >= Hi then - Mid := Mid + 1; - XP := XP * 10.0; - exit; - - else - Lo := Mid + 1; - end if; - - elsif XP >= Powten (S) then - - if Lo >= Hi then - Mid := Mid - 1; - XP := XP / 10.0; - exit; - - else - Hi := Mid - 1; - end if; - - else - exit; - end if; - end loop; - - X := XP; - Scale := Scale - Mid; - - -- Cases where scaling down is required - - elsif X >= Powten (S) then - - -- What we are looking for is a power of ten to divide X by - -- so that the result lies within the required range. - - loop - XP := X / Powten (Maxpow); - exit when XP < Powten (S) or else Scale > Maxscaling; - X := XP; - Scale := Scale + Maxpow; - end loop; - - -- The following exception is only raised in case of erroneous - -- execution, where a number was considered valid but still - -- fails to scale up. One situation where this can happen is - -- when a system which is supposed to be IEEE-compliant, but - -- has been reconfigured to flush denormals to zero. - - if Scale > Maxscaling then - raise Constraint_Error; - end if; - - -- Here we know that we must divide by at least 10**1 and that - -- 10**Maxpow takes us too far, binary search to find right one. - - Lo := 1; - Hi := Maxpow; - - loop - Mid := (Lo + Hi) / 2; - XP := X / Powten (Mid); - - if XP < Powten (S - 1) then - - if Lo >= Hi then - XP := XP * 10.0; - Mid := Mid - 1; - exit; - - else - Hi := Mid - 1; - end if; - - elsif XP >= Powten (S) then - - if Lo >= Hi then - XP := XP / 10.0; - Mid := Mid + 1; - exit; - - else - Lo := Mid + 1; - end if; - - else - exit; - end if; - end loop; - - X := XP; - Scale := Scale + Mid; - - -- Here we are already scaled right - - else - null; - end if; - - -- Round, readjusting scale if needed. Note that if a readjustment - -- occurs, then it is never necessary to round again, because there - -- is no possibility of such a second rounding causing a change. - - X := X + 0.5; - - if X >= Powten (S) then - X := X / 10.0; - Scale := Scale + 1; - end if; - - end Adjust_Scale; - - --------------------- - -- Convert_Integer -- - --------------------- - - procedure Convert_Integer is - begin - -- Use Unsigned routine if possible, since on many machines it will - -- be significantly more efficient than the Long_Long_Unsigned one. - - if X < Powten (Unsdigs) then - Ndigs := 0; - Set_Image_Unsigned - (Unsigned (Long_Long_Float'Truncation (X)), - Digs, Ndigs); - - -- But if we want more digits than fit in Unsigned, we have to use - -- the Long_Long_Unsigned routine after all. - - else - Ndigs := 0; - Set_Image_Long_Long_Unsigned - (Long_Long_Unsigned (Long_Long_Float'Truncation (X)), - Digs, Ndigs); - end if; - end Convert_Integer; - - --------- - -- Set -- - --------- - - procedure Set (C : Character) is - begin - P := P + 1; - S (P) := C; - end Set; - - ------------------------- - -- Set_Blanks_And_Sign -- - ------------------------- - - procedure Set_Blanks_And_Sign (N : Integer) is - begin - if Sign = '-' then - for J in 1 .. N - 1 loop - Set (' '); - end loop; - - Set ('-'); - - else - for J in 1 .. N loop - Set (' '); - end loop; - end if; - end Set_Blanks_And_Sign; - - -------------- - -- Set_Digs -- - -------------- - - procedure Set_Digs (S, E : Natural) is - begin - for J in S .. E loop - Set (Digs (J)); - end loop; - end Set_Digs; - - ---------------------- - -- Set_Special_Fill -- - ---------------------- - - procedure Set_Special_Fill (N : Natural) is - F : Natural; - - begin - F := Fore + 1 + Aft - N; - - if Exp /= 0 then - F := F + Exp + 1; - end if; - - for J in 1 .. F loop - Set ('*'); - end loop; - end Set_Special_Fill; - - --------------- - -- Set_Zeros -- - --------------- - - procedure Set_Zeros (N : Integer) is - begin - for J in 1 .. N loop - Set ('0'); - end loop; - end Set_Zeros; - - -- Start of processing for Set_Image_Real - - begin - -- We call the floating-point processor reset routine so that we can - -- be sure the floating-point processor is properly set for conversion - -- calls. This is notably need on Windows, where calls to the operating - -- system randomly reset the processor into 64-bit mode. - - System.Float_Control.Reset; - - Scale := 0; - - -- Deal with invalid values first, - - if not V'Valid then - - -- Note that we're taking our chances here, as V might be - -- an invalid bit pattern resulting from erroneous execution - -- (caused by using uninitialized variables for example). - - -- No matter what, we'll at least get reasonable behavior, - -- converting to infinity or some other value, or causing an - -- exception to be raised is fine. - - -- If the following test succeeds, then we definitely have - -- an infinite value, so we print Inf. - - if V > Long_Long_Float'Last then - Set ('+'); - Set ('I'); - Set ('n'); - Set ('f'); - Set_Special_Fill (4); - - -- In all other cases we print NaN - - elsif V < Long_Long_Float'First then - Set ('-'); - Set ('I'); - Set ('n'); - Set ('f'); - Set_Special_Fill (4); - - else - Set ('N'); - Set ('a'); - Set ('N'); - Set_Special_Fill (3); - end if; - - return; - end if; - - -- Positive values - - if V > 0.0 then - X := V; - Sign := '+'; - - -- Negative values - - elsif V < 0.0 then - X := -V; - Sign := '-'; - - -- Zero values - - elsif V = 0.0 then - if Long_Long_Float'Signed_Zeros and then Is_Negative (V) then - Sign := '-'; - else - Sign := '+'; - end if; - - Set_Blanks_And_Sign (Fore - 1); - Set ('0'); - Set ('.'); - Set_Zeros (NFrac); - - if Exp /= 0 then - Set ('E'); - Set ('+'); - Set_Zeros (Natural'Max (1, Exp - 1)); - end if; - - return; - - else - -- It should not be possible for a NaN to end up here. - -- Either the 'Valid test has failed, or we have some form - -- of erroneous execution. Raise Constraint_Error instead of - -- attempting to go ahead printing the value. - - raise Constraint_Error; - end if; - - -- X and Sign are set here, and X is known to be a valid, - -- non-zero floating-point number. - - -- Case of non-zero value with Exp = 0 - - if Exp = 0 then - - -- First step is to multiply by 10 ** Nfrac to get an integer - -- value to be output, an then add 0.5 to round the result. - - declare - NF : Natural := NFrac; - - begin - loop - -- If we are larger than Powten (Maxdigs) now, then - -- we have too many significant digits, and we have - -- not even finished multiplying by NFrac (NF shows - -- the number of unaccounted-for digits). - - if X >= Powten (Maxdigs) then - - -- In this situation, we only to generate a reasonable - -- number of significant digits, and then zeroes after. - -- So first we rescale to get: - - -- 10 ** (Maxdigs - 1) <= X < 10 ** Maxdigs - - -- and then convert the resulting integer - - Adjust_Scale (Maxdigs); - Convert_Integer; - - -- If that caused rescaling, then add zeros to the end - -- of the number to account for this scaling. Also add - -- zeroes to account for the undone multiplications - - for J in 1 .. Scale + NF loop - Ndigs := Ndigs + 1; - Digs (Ndigs) := '0'; - end loop; - - exit; - - -- If multiplication is complete, then convert the resulting - -- integer after rounding (note that X is non-negative) - - elsif NF = 0 then - X := X + 0.5; - Convert_Integer; - exit; - - -- Otherwise we can go ahead with the multiplication. If it - -- can be done in one step, then do it in one step. - - elsif NF < Maxpow then - X := X * Powten (NF); - NF := 0; - - -- If it cannot be done in one step, then do partial scaling - - else - X := X * Powten (Maxpow); - NF := NF - Maxpow; - end if; - end loop; - end; - - -- If number of available digits is less or equal to NFrac, - -- then we need an extra zero before the decimal point. - - if Ndigs <= NFrac then - Set_Blanks_And_Sign (Fore - 1); - Set ('0'); - Set ('.'); - Set_Zeros (NFrac - Ndigs); - Set_Digs (1, Ndigs); - - -- Normal case with some digits before the decimal point - - else - Set_Blanks_And_Sign (Fore - (Ndigs - NFrac)); - Set_Digs (1, Ndigs - NFrac); - Set ('.'); - Set_Digs (Ndigs - NFrac + 1, Ndigs); - end if; - - -- Case of non-zero value with non-zero Exp value - - else - -- If NFrac is less than Maxdigs, then all the fraction digits are - -- significant, so we can scale the resulting integer accordingly. - - if NFrac < Maxdigs then - Adjust_Scale (NFrac + 1); - Convert_Integer; - - -- Otherwise, we get the maximum number of digits available - - else - Adjust_Scale (Maxdigs); - Convert_Integer; - - for J in 1 .. NFrac - Maxdigs + 1 loop - Ndigs := Ndigs + 1; - Digs (Ndigs) := '0'; - Scale := Scale - 1; - end loop; - end if; - - Set_Blanks_And_Sign (Fore - 1); - Set (Digs (1)); - Set ('.'); - Set_Digs (2, Ndigs); - - -- The exponent is the scaling factor adjusted for the digits - -- that we output after the decimal point, since these were - -- included in the scaled digits that we output. - - Expon := Scale + NFrac; - - Set ('E'); - Ndigs := 0; - - if Expon >= 0 then - Set ('+'); - Set_Image_Unsigned (Unsigned (Expon), Digs, Ndigs); - else - Set ('-'); - Set_Image_Unsigned (Unsigned (-Expon), Digs, Ndigs); - end if; - - Set_Zeros (Exp - Ndigs - 1); - Set_Digs (1, Ndigs); - end if; - - end Set_Image_Real; - -end System.Img_Real; |