1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- ADA.NUMERICS.BIG_NUMBERS.BIG_REALS --
9 -- Copyright (C) 2019-2023, 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
;
34 package body Ada
.Numerics
.Big_Numbers
.Big_Reals
is
38 procedure Normalize
(Arg
: in out Big_Real
);
39 -- Normalize Arg by ensuring that Arg.Den is always positive and that
40 -- Arg.Num and Arg.Den always have a GCD of 1.
46 function Is_Valid
(Arg
: Big_Real
) return Boolean is
47 (Is_Valid
(Arg
.Num
) and Is_Valid
(Arg
.Den
));
53 function "/" (Num
, Den
: Valid_Big_Integer
) return Valid_Big_Real
is
56 if Den
= To_Big_Integer
(0) then
57 raise Constraint_Error
with "divide by zero";
70 function Numerator
(Arg
: Valid_Big_Real
) return Valid_Big_Integer
is
77 function Denominator
(Arg
: Valid_Big_Real
) return Big_Positive
is
84 function "=" (L
, R
: Valid_Big_Real
) return Boolean is
85 (L
.Num
= R
.Num
and then L
.Den
= R
.Den
);
91 function "<" (L
, R
: Valid_Big_Real
) return Boolean is
92 (L
.Num
* R
.Den
< R
.Num
* L
.Den
);
93 -- The denominator is guaranteed to be positive since Normalized is
94 -- always called when constructing a Valid_Big_Real
100 function "<=" (L
, R
: Valid_Big_Real
) return Boolean is (not (R
< L
));
106 function ">" (L
, R
: Valid_Big_Real
) return Boolean is (R
< L
);
112 function ">=" (L
, R
: Valid_Big_Real
) return Boolean is (not (L
< R
));
114 -----------------------
115 -- Float_Conversions --
116 -----------------------
118 package body Float_Conversions
is
121 Big_Integers
.Unsigned_Conversions
(Long_Long_Unsigned
);
127 -- We get the fractional representation of the floating-point number by
128 -- multiplying Num'Fraction by 2.0**M, with M the size of the mantissa,
129 -- which gives zero or a number in the range [2.0**(M-1)..2.0**M), which
130 -- means that it is an integer N of M bits. The floating-point number is
131 -- thus equal to N / 2**(M-E) where E is its Num'Exponent.
133 function To_Big_Real
(Arg
: Num
) return Valid_Big_Real
is
135 A
: constant Num
'Base := abs (Arg
);
136 E
: constant Integer := Num
'Exponent (A
);
137 F
: constant Num
'Base := Num
'Fraction (A
);
138 M
: constant Natural := Num
'Machine_Mantissa;
143 pragma Assert
(Num
'Machine_Radix = 2);
144 -- This implementation does not handle radix 16
146 pragma Assert
(M
<= 64);
147 -- This implementation handles only 80-bit IEEE Extended or smaller
149 N
:= Conv
.To_Big_Integer
(Long_Long_Unsigned
(F
* 2.0**M
));
151 -- If E is smaller than M, the denominator is 2**(M-E)
154 D
:= To_Big_Integer
(2) ** (M
- E
);
156 -- Or else, if E is larger than M, multiply the numerator by 2**(E-M)
159 N
:= N
* To_Big_Integer
(2) ** (E
- M
);
160 D
:= To_Big_Integer
(1);
162 -- Otherwise E is equal to M and the result is just N
165 D
:= To_Big_Integer
(1);
168 return (if Arg
>= 0.0 then N
/ D
else -N
/ D
);
175 -- We get the (Frac, Exp) representation of the real number by finding
176 -- the exponent E such that it lies in the range [2.0**(E-1)..2.0**E),
177 -- multiplying the number by 2.0**(M-E) with M the size of the mantissa,
178 -- and converting the result to integer N in the range [2**(M-1)..2**M)
179 -- with rounding to nearest, ties to even, and finally call Num'Compose.
180 -- This does not apply to the zero, for which we return 0.0 early.
182 function From_Big_Real
(Arg
: Big_Real
) return Num
is
184 M
: constant Natural := Num
'Machine_Mantissa;
185 One
: constant Big_Real
:= To_Real
(1);
186 Two
: constant Big_Real
:= To_Real
(2);
187 Half
: constant Big_Real
:= One
/ Two
;
188 TwoI
: constant Big_Integer
:= To_Big_Integer
(2);
190 function Log2_Estimate
(V
: Big_Real
) return Natural;
191 -- Return an integer not larger than Log2 (V) for V >= 1.0
193 function Minus_Log2_Estimate
(V
: Big_Real
) return Natural;
194 -- Return an integer not larger than -Log2 (V) for V < 1.0
200 function Log2_Estimate
(V
: Big_Real
) return Natural is
202 Pow
: Big_Real
:= Two
;
213 -------------------------
214 -- Minus_Log2_Estimate --
215 -------------------------
217 function Minus_Log2_Estimate
(V
: Big_Real
) return Natural is
219 Pow
: Big_Real
:= Half
;
228 end Minus_Log2_Estimate
;
232 V
: Big_Real
:= abs (Arg
);
236 A
, B
, Q
, X
: Big_Integer
;
237 N
: Long_Long_Unsigned
;
241 pragma Assert
(Num
'Machine_Radix = 2);
242 -- This implementation does not handle radix 16
244 pragma Assert
(M
<= 64);
245 -- This implementation handles only 80-bit IEEE Extended or smaller
247 -- Protect from degenerate case
249 if Numerator
(V
) = To_Big_Integer
(0) then
253 -- Use a binary search to compute exponent E
256 L
:= Minus_Log2_Estimate
(V
);
261 -- The dissymetry with above is expected since we go below 2
264 L
:= Log2_Estimate
(V
) + 1;
269 -- The multiplication by 2.0**(-E) has already been done in the loops
271 V
:= V
* To_Big_Real
(TwoI
** M
);
273 -- Now go into the integer domain and divide
276 B
:= Denominator
(V
);
279 N
:= Conv
.From_Big_Integer
(Q
);
281 -- Round to nearest, ties to even, by comparing twice the remainder
283 X
:= (A
- Q
* B
) * TwoI
;
285 if X
> B
or else (X
= B
and then (N
mod 2) = 1) then
288 -- If the adjusted quotient overflows the mantissa, scale up
296 R
:= Num
'Compose (Num
'Base (N
), E
);
298 return (if Numerator
(Arg
) >= To_Big_Integer
(0) then R
else -R
);
301 end Float_Conversions
;
303 -----------------------
304 -- Fixed_Conversions --
305 -----------------------
307 package body Fixed_Conversions
is
309 package Float_Aux
is new Float_Conversions
(Long_Float);
311 subtype LLLI
is Long_Long_Long_Integer
;
312 subtype LLLU
is Long_Long_Long_Unsigned
;
314 Too_Large
: constant Boolean :=
315 Num
'Small_Numerator > LLLU
'Last
316 or else Num
'Small_Denominator > LLLU
'Last;
317 -- True if the Small is too large for Long_Long_Long_Unsigned, in which
318 -- case we convert to/from Long_Float as an intermediate step.
320 package Conv_I
is new Big_Integers
.Signed_Conversions
(LLLI
);
321 package Conv_U
is new Big_Integers
.Unsigned_Conversions
(LLLU
);
327 -- We just compute V * N / D where V is the mantissa value of the fixed
328 -- point number, and N resp. D is the numerator resp. the denominator of
329 -- the Small of the fixed-point type.
331 function To_Big_Real
(Arg
: Num
) return Valid_Big_Real
is
332 N
, D
, V
: Big_Integer
;
336 return Float_Aux
.To_Big_Real
(Long_Float (Arg
));
339 N
:= Conv_U
.To_Big_Integer
(Num
'Small_Numerator);
340 D
:= Conv_U
.To_Big_Integer
(Num
'Small_Denominator);
341 V
:= Conv_I
.To_Big_Integer
(LLLI
'Integer_Value (Arg
));
350 -- We first compute A / B = Arg * D / N where N resp. D is the numerator
351 -- resp. the denominator of the Small of the fixed-point type. Then we
352 -- divide A by B and convert the result to the mantissa value.
354 function From_Big_Real
(Arg
: Big_Real
) return Num
is
355 N
, D
, A
, B
, Q
, X
: Big_Integer
;
359 return Num
(Float_Aux
.From_Big_Real
(Arg
));
362 N
:= Conv_U
.To_Big_Integer
(Num
'Small_Numerator);
363 D
:= Conv_U
.To_Big_Integer
(Num
'Small_Denominator);
364 A
:= Numerator
(Arg
) * D
;
365 B
:= Denominator
(Arg
) * N
;
369 -- Round to nearest, ties to away, by comparing twice the remainder
371 X
:= (A
- Q
* B
) * To_Big_Integer
(2);
374 Q
:= Q
+ To_Big_Integer
(1);
377 Q
:= Q
- To_Big_Integer
(1);
380 return Num
'Fixed_Value (Conv_I
.From_Big_Integer
(Q
));
383 end Fixed_Conversions
;
390 (Arg
: Valid_Big_Real
;
393 Exp
: Field
:= 0) return String
395 Zero
: constant Big_Integer
:= To_Big_Integer
(0);
396 Ten
: constant Big_Integer
:= To_Big_Integer
(10);
398 function Leading_Padding
401 Char
: Character := ' ') return String;
402 -- Return padding of Char concatenated with Str so that the resulting
403 -- string is at least Min_Length long.
405 function Trailing_Padding
408 Char
: Character := '0') return String;
409 -- Return Str with trailing Char removed, and if needed either
410 -- truncated or concatenated with padding of Char so that the resulting
411 -- string is Length long.
413 function Image
(N
: Natural) return String;
414 -- Return image of N, with no leading space.
416 function Numerator_Image
418 After
: Natural) return String;
419 -- Return image of Num as a float value with After digits after the "."
420 -- and taking Fore, Aft, Exp into account.
426 function Image
(N
: Natural) return String is
427 S
: constant String := Natural'Image (N
);
429 return S
(2 .. S
'Last);
432 ---------------------
433 -- Leading_Padding --
434 ---------------------
436 function Leading_Padding
439 Char
: Character := ' ') return String is
442 return Leading_Padding
("0", Min_Length
, Char
);
444 return [1 .. Integer'Max (Integer (Min_Length
) - Str
'Length, 0)
449 ----------------------
450 -- Trailing_Padding --
451 ----------------------
453 function Trailing_Padding
456 Char
: Character := '0') return String is
458 if Str
'Length > 0 and then Str
(Str
'Last) = Char
then
459 for J
in reverse Str
'Range loop
460 if Str
(J
) /= '0' then
461 return Trailing_Padding
462 (Str
(Str
'First .. J
), Length
, Char
);
467 if Str
'Length >= Length
then
468 return Str
(Str
'First .. Str
'First + Length
- 1);
471 [1 .. Integer'Max (Integer (Length
) - Str
'Length, 0)
474 end Trailing_Padding
;
476 ---------------------
477 -- Numerator_Image --
478 ---------------------
480 function Numerator_Image
482 After
: Natural) return String
484 Tmp
: constant String := To_String
(Num
);
485 Str
: constant String (1 .. Tmp
'Last - 1) := Tmp
(2 .. Tmp
'Last);
490 return Leading_Padding
(Str
, Fore
) & "."
491 & Trailing_Padding
("0", Aft
);
493 Index
:= Str
'Last - After
;
496 return Leading_Padding
("0", Fore
)
498 & Trailing_Padding
([1 .. -Index
=> '0'] & Str
, Aft
)
499 & (if Exp
= 0 then "" else "E+" & Image
(Natural (Exp
)));
501 return Leading_Padding
(Str
(Str
'First .. Index
), Fore
)
503 & Trailing_Padding
(Str
(Index
+ 1 .. Str
'Last), Aft
)
504 & (if Exp
= 0 then "" else "E+" & Image
(Natural (Exp
)));
510 if Arg
.Num
< Zero
then
512 Str
: String := To_String
(-Arg
, Fore
, Aft
, Exp
);
514 if Str
(1) = ' ' then
515 for J
in 1 .. Str
'Last - 1 loop
516 if Str
(J
+ 1) /= ' ' then
528 -- Compute Num * 10^Aft so that we get Aft significant digits
529 -- in the integer part (rounded) to display.
531 return Numerator_Image
532 ((Arg
.Num
* Ten
** Aft
) / Arg
.Den
, After
=> Exp
+ Aft
);
540 function From_String
(Arg
: String) return Valid_Big_Real
is
541 Ten
: constant Big_Integer
:= To_Big_Integer
(10);
545 Index
: Natural := 0;
546 Last
: Natural := Arg
'Last;
549 for J
in reverse Arg
'Range loop
550 if Arg
(J
) in 'e' |
'E' then
551 if Last
/= Arg
'Last then
552 raise Constraint_Error
with "multiple exponents specified";
556 Exp
:= Integer'Value (Arg
(J
+ 1 .. Arg
'Last));
559 elsif Arg
(J
) = '.' then
562 elsif Arg
(J
) /= '_' then
568 raise Constraint_Error
with "invalid real value";
574 Result
.Den
:= Ten
** Pow
;
575 Result
.Num
:= From_String
(Arg
(Arg
'First .. Index
)) * Result
.Den
;
576 Frac
:= From_String
(Arg
(Index
+ 2 .. Last
));
578 if Result
.Num
< To_Big_Integer
(0) then
579 Result
.Num
:= Result
.Num
- Frac
;
581 Result
.Num
:= Result
.Num
+ Frac
;
585 Result
.Num
:= Result
.Num
* Ten
** Exp
;
587 Result
.Den
:= Result
.Den
* Ten
** (-Exp
);
595 --------------------------
596 -- From_Quotient_String --
597 --------------------------
599 function From_Quotient_String
(Arg
: String) return Valid_Big_Real
is
600 Index
: Natural := 0;
602 for J
in Arg
'First + 1 .. Arg
'Last - 1 loop
603 if Arg
(J
) = '/' then
610 raise Constraint_Error
with "no quotient found";
613 return Big_Integers
.From_String
(Arg
(Arg
'First .. Index
- 1)) /
614 Big_Integers
.From_String
(Arg
(Index
+ 1 .. Arg
'Last));
615 end From_Quotient_String
;
621 procedure Put_Image
(S
: in out Root_Buffer_Type
'Class; V
: Big_Real
) is
622 -- This is implemented in terms of To_String. It might be more elegant
623 -- and more efficient to do it the other way around, but this is the
624 -- most expedient implementation for now.
626 Strings
.Text_Buffers
.Put_UTF_8
(S
, To_String
(V
));
633 function "+" (L
: Valid_Big_Real
) return Valid_Big_Real
is
645 function "-" (L
: Valid_Big_Real
) return Valid_Big_Real
is
646 (Num
=> -L
.Num
, Den
=> L
.Den
);
652 function "abs" (L
: Valid_Big_Real
) return Valid_Big_Real
is
653 (Num
=> abs L
.Num
, Den
=> L
.Den
);
659 function "+" (L
, R
: Valid_Big_Real
) return Valid_Big_Real
is
662 Result
.Num
:= L
.Num
* R
.Den
+ R
.Num
* L
.Den
;
663 Result
.Den
:= L
.Den
* R
.Den
;
672 function "-" (L
, R
: Valid_Big_Real
) return Valid_Big_Real
is
675 Result
.Num
:= L
.Num
* R
.Den
- R
.Num
* L
.Den
;
676 Result
.Den
:= L
.Den
* R
.Den
;
685 function "*" (L
, R
: Valid_Big_Real
) return Valid_Big_Real
is
688 Result
.Num
:= L
.Num
* R
.Num
;
689 Result
.Den
:= L
.Den
* R
.Den
;
698 function "/" (L
, R
: Valid_Big_Real
) return Valid_Big_Real
is
701 Result
.Num
:= L
.Num
* R
.Den
;
702 Result
.Den
:= L
.Den
* R
.Num
;
711 function "**" (L
: Valid_Big_Real
; R
: Integer) return Valid_Big_Real
is
715 Result
.Num
:= To_Big_Integer
(1);
716 Result
.Den
:= To_Big_Integer
(1);
719 Result
.Num
:= L
.Den
** (-R
);
720 Result
.Den
:= L
.Num
** (-R
);
722 Result
.Num
:= L
.Num
** R
;
723 Result
.Den
:= L
.Den
** R
;
736 function Min
(L
, R
: Valid_Big_Real
) return Valid_Big_Real
is
737 (if L
< R
then L
else R
);
743 function Max
(L
, R
: Valid_Big_Real
) return Valid_Big_Real
is
744 (if L
> R
then L
else R
);
750 procedure Normalize
(Arg
: in out Big_Real
) is
751 Zero
: constant Big_Integer
:= To_Big_Integer
(0);
753 if Arg
.Den
< Zero
then
758 if Arg
.Num
= Zero
then
759 Arg
.Den
:= To_Big_Integer
(1);
762 GCD
: constant Big_Integer
:=
763 Greatest_Common_Divisor
(Arg
.Num
, Arg
.Den
);
765 Arg
.Num
:= Arg
.Num
/ GCD
;
766 Arg
.Den
:= Arg
.Den
/ GCD
;
771 end Ada
.Numerics
.Big_Numbers
.Big_Reals
;