1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- S Y S T E M . V A L U E _ D --
9 -- Copyright (C) 2020-2024, 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 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. --
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. --
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/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 with System
.Unsigned_Types
; use System
.Unsigned_Types
;
33 with System
.Val_Util
; use System
.Val_Util
;
36 package body System
.Value_D
is
38 pragma Assert
(Int
'Size <= Uns
'Size);
39 -- We need an unsigned type large enough to represent the mantissa
41 package Impl
is new Value_R
(Uns
, 1, 2**(Int
'Size - 1), Round
=> False);
42 -- We do not use the Extra digit for decimal fixed-point types
44 function Integer_to_Decimal
50 Scale
: Integer) return Int
;
51 -- Convert the real value from integer to decimal representation
53 ------------------------
54 -- Integer_to_Decimal --
55 ------------------------
57 function Integer_to_Decimal
63 Scale
: Integer) return Int
68 Factor
: Int
) return Int
;
69 -- Return (Base ** Exp) * Factor if the computation does not overflow,
70 -- or else the number of the form (Base ** K) * Factor with the largest
71 -- magnitude if the former computation overflows. In both cases, Exp is
72 -- updated to contain the remaining power in the computation. Note that
73 -- Factor is expected to be positive in this context.
75 function Unsigned_To_Signed
(Val
: Uns
) return Int
;
76 -- Convert an integer value from unsigned to signed representation
85 Factor
: Int
) return Int
87 pragma Assert
(Base
/= 0 and then Factor
> 0);
89 Max
: constant Int
:= Int
'Last / Base
;
91 Result
: Int
:= Factor
;
94 while Exp
> 0 and then Result
<= Max
loop
95 Result
:= Result
* Base
;
102 ------------------------
103 -- Unsigned_To_Signed --
104 ------------------------
106 function Unsigned_To_Signed
(Val
: Uns
) return Int
is
108 -- Deal with overflow cases, and also with largest negative number
110 if Val
> Uns
(Int
'Last) then
111 if Minus
and then Val
= Uns
(-(Int
'First)) then
127 end Unsigned_To_Signed
;
130 -- If the base of the value is 10 or its scaling factor is zero, then
131 -- add the scales (they are defined in the opposite sense) and apply
132 -- the result to the value, checking for overflow in the process.
134 if Base
= 10 or else ScaleB
= 0 then
136 S
: Integer := ScaleB
+ Scale
;
146 if V
<= Uns
'Last / 10 then
154 return Unsigned_To_Signed
(V
);
157 -- If the base of the value is not 10, use a scaled divide operation
158 -- to compute Val * (Base ** ScaleB) * (10 ** Scale).
162 B
: constant Int
:= Int
(Base
);
163 S
: constant Integer := ScaleB
;
170 -- If S is too negative, then drop trailing digits
177 Y
:= 10 ** Integer'Max (0, Scale
);
178 Z
:= Safe_Expont
(B
, LS
, 10 ** Integer'Max (0, -Scale
));
180 for J
in 1 .. LS
loop
185 -- If S is too positive, then scale V up, which may then overflow
192 Y
:= Safe_Expont
(B
, LS
, 10 ** Integer'Max (0, Scale
));
193 Z
:= 10 ** Integer'Max (0, -Scale
);
195 for J
in 1 .. LS
loop
196 if V
<= Uns
'Last / Uns
(B
) then
204 -- The case S equal to zero should have been handled earlier
210 -- Perform a scale divide operation with rounding to match 'Image
212 Scaled_Divide
(Unsigned_To_Signed
(V
), Y
, Z
, Q
, R
, Round
=> True);
219 when Constraint_Error
=> Bad_Value
(Str
);
220 end Integer_to_Decimal
;
226 function Scan_Decimal
228 Ptr
: not null access Integer;
230 Scale
: Integer) return Int
233 Scl
: Impl
.Scale_Array
;
236 Val
: Impl
.Value_Array
;
239 Val
:= Impl
.Scan_Raw_Real
(Str
, Ptr
, Max
, Base
, Scl
, Extra
, Minus
);
241 return Integer_to_Decimal
(Str
, Val
(1), Base
, Scl
(1), Minus
, Scale
);
248 function Value_Decimal
(Str
: String; Scale
: Integer) return Int
is
250 Scl
: Impl
.Scale_Array
;
253 Val
: Impl
.Value_Array
;
256 Val
:= Impl
.Value_Raw_Real
(Str
, Base
, Scl
, Extra
, Minus
);
258 return Integer_to_Decimal
(Str
, Val
(1), Base
, Scl
(1), Minus
, Scale
);