File : eval_fat.adb


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                         GNAT COMPILER COMPONENTS                         --
   4 --                                                                          --
   5 --                             E V A L _ F A T                              --
   6 --                                                                          --
   7 --                                 B o d y                                  --
   8 --                                                                          --
   9 --          Copyright (C) 1992-2016, 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.  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 COPYING3.  If not, go to --
  19 -- http://www.gnu.org/licenses for a complete copy of the license.          --
  20 --                                                                          --
  21 -- GNAT was originally developed  by the GNAT team at  New York University. --
  22 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
  23 --                                                                          --
  24 ------------------------------------------------------------------------------
  25 
  26 with Einfo;    use Einfo;
  27 with Errout;   use Errout;
  28 with Sem_Util; use Sem_Util;
  29 
  30 package body Eval_Fat is
  31 
  32    Radix : constant Int := 2;
  33    --  This code is currently only correct for the radix 2 case. We use the
  34    --  symbolic value Radix where possible to help in the unlikely case of
  35    --  anyone ever having to adjust this code for another value, and for
  36    --  documentation purposes.
  37 
  38    --  Another assumption is that the range of the floating-point type is
  39    --  symmetric around zero.
  40 
  41    type Radix_Power_Table is array (Int range 1 .. 4) of Int;
  42 
  43    Radix_Powers : constant Radix_Power_Table :=
  44      (Radix ** 1, Radix ** 2, Radix ** 3, Radix ** 4);
  45 
  46    -----------------------
  47    -- Local Subprograms --
  48    -----------------------
  49 
  50    procedure Decompose
  51      (RT       : R;
  52       X        : T;
  53       Fraction : out T;
  54       Exponent : out UI;
  55       Mode     : Rounding_Mode := Round);
  56    --  Decomposes a non-zero floating-point number into fraction and exponent
  57    --  parts. The fraction is in the interval 1.0 / Radix .. T'Pred (1.0) and
  58    --  uses Rbase = Radix. The result is rounded to a nearest machine number.
  59 
  60    --------------
  61    -- Adjacent --
  62    --------------
  63 
  64    function Adjacent (RT : R; X, Towards : T) return T is
  65    begin
  66       if Towards = X then
  67          return X;
  68       elsif Towards > X then
  69          return Succ (RT, X);
  70       else
  71          return Pred (RT, X);
  72       end if;
  73    end Adjacent;
  74 
  75    -------------
  76    -- Ceiling --
  77    -------------
  78 
  79    function Ceiling (RT : R; X : T) return T is
  80       XT : constant T := Truncation (RT, X);
  81    begin
  82       if UR_Is_Negative (X) then
  83          return XT;
  84       elsif X = XT then
  85          return X;
  86       else
  87          return XT + Ureal_1;
  88       end if;
  89    end Ceiling;
  90 
  91    -------------
  92    -- Compose --
  93    -------------
  94 
  95    function Compose (RT : R; Fraction : T; Exponent : UI) return T is
  96       Arg_Frac : T;
  97       Arg_Exp  : UI;
  98       pragma Warnings (Off, Arg_Exp);
  99    begin
 100       Decompose (RT, Fraction, Arg_Frac, Arg_Exp);
 101       return Scaling (RT, Arg_Frac, Exponent);
 102    end Compose;
 103 
 104    ---------------
 105    -- Copy_Sign --
 106    ---------------
 107 
 108    function Copy_Sign (RT : R; Value, Sign : T) return T is
 109       pragma Warnings (Off, RT);
 110       Result : T;
 111 
 112    begin
 113       Result := abs Value;
 114 
 115       if UR_Is_Negative (Sign) then
 116          return -Result;
 117       else
 118          return Result;
 119       end if;
 120    end Copy_Sign;
 121 
 122    ---------------
 123    -- Decompose --
 124    ---------------
 125 
 126    procedure Decompose
 127      (RT       : R;
 128       X        : T;
 129       Fraction : out T;
 130       Exponent : out UI;
 131       Mode     : Rounding_Mode := Round)
 132    is
 133       Int_F : UI;
 134 
 135    begin
 136       Decompose_Int (RT, abs X, Int_F, Exponent, Mode);
 137 
 138       Fraction := UR_From_Components
 139        (Num      => Int_F,
 140         Den      => Machine_Mantissa_Value (RT),
 141         Rbase    => Radix,
 142         Negative => False);
 143 
 144       if UR_Is_Negative (X) then
 145          Fraction := -Fraction;
 146       end if;
 147 
 148       return;
 149    end Decompose;
 150 
 151    -------------------
 152    -- Decompose_Int --
 153    -------------------
 154 
 155    --  This procedure should be modified with care, as there are many non-
 156    --  obvious details that may cause problems that are hard to detect. For
 157    --  zero arguments, Fraction and Exponent are set to zero. Note that sign
 158    --  of zero cannot be preserved.
 159 
 160    procedure Decompose_Int
 161      (RT       : R;
 162       X        : T;
 163       Fraction : out UI;
 164       Exponent : out UI;
 165       Mode     : Rounding_Mode)
 166    is
 167       Base : Int := Rbase (X);
 168       N    : UI  := abs Numerator (X);
 169       D    : UI  := Denominator (X);
 170 
 171       N_Times_Radix : UI;
 172 
 173       Even : Boolean;
 174       --  True iff Fraction is even
 175 
 176       Most_Significant_Digit : constant UI :=
 177         Radix ** (Machine_Mantissa_Value (RT) - 1);
 178 
 179       Uintp_Mark : Uintp.Save_Mark;
 180       --  The code is divided into blocks that systematically release
 181       --  intermediate values (this routine generates lots of junk).
 182 
 183    begin
 184       if N = Uint_0 then
 185          Fraction := Uint_0;
 186          Exponent := Uint_0;
 187          return;
 188       end if;
 189 
 190       Calculate_D_And_Exponent_1 : begin
 191          Uintp_Mark := Mark;
 192          Exponent := Uint_0;
 193 
 194          --  In cases where Base > 1, the actual denominator is Base**D. For
 195          --  cases where Base is a power of Radix, use the value 1 for the
 196          --  Denominator and adjust the exponent.
 197 
 198          --  Note: Exponent has different sign from D, because D is a divisor
 199 
 200          for Power in 1 .. Radix_Powers'Last loop
 201             if Base = Radix_Powers (Power) then
 202                Exponent := -D * Power;
 203                Base := 0;
 204                D := Uint_1;
 205                exit;
 206             end if;
 207          end loop;
 208 
 209          Release_And_Save (Uintp_Mark, D, Exponent);
 210       end Calculate_D_And_Exponent_1;
 211 
 212       if Base > 0 then
 213          Calculate_Exponent : begin
 214             Uintp_Mark := Mark;
 215 
 216             --  For bases that are a multiple of the Radix, divide the base by
 217             --  Radix and adjust the Exponent. This will help because D will be
 218             --  much smaller and faster to process.
 219 
 220             --  This occurs for decimal bases on machines with binary floating-
 221             --  point for example. When calculating 1E40, with Radix = 2, N
 222             --  will be 93 bits instead of 133.
 223 
 224             --        N            E
 225             --      ------  * Radix
 226             --           D
 227             --       Base
 228 
 229             --                  N                        E
 230             --    =  --------------------------  *  Radix
 231             --                     D        D
 232             --         (Base/Radix)  * Radix
 233 
 234             --             N                  E-D
 235             --    =  ---------------  *  Radix
 236             --                    D
 237             --        (Base/Radix)
 238 
 239             --  This code is commented out, because it causes numerous
 240             --  failures in the regression suite. To be studied ???
 241 
 242             while False and then Base > 0 and then Base mod Radix = 0 loop
 243                Base := Base / Radix;
 244                Exponent := Exponent + D;
 245             end loop;
 246 
 247             Release_And_Save (Uintp_Mark, Exponent);
 248          end Calculate_Exponent;
 249 
 250          --  For remaining bases we must actually compute the exponentiation
 251 
 252          --  Because the exponentiation can be negative, and D must be integer,
 253          --  the numerator is corrected instead.
 254 
 255          Calculate_N_And_D : begin
 256             Uintp_Mark := Mark;
 257 
 258             if D < 0 then
 259                N := N * Base ** (-D);
 260                D := Uint_1;
 261             else
 262                D := Base ** D;
 263             end if;
 264 
 265             Release_And_Save (Uintp_Mark, N, D);
 266          end Calculate_N_And_D;
 267 
 268          Base := 0;
 269       end if;
 270 
 271       --  Now scale N and D so that N / D is a value in the interval [1.0 /
 272       --  Radix, 1.0) and adjust Exponent accordingly, so the value N / D *
 273       --  Radix ** Exponent remains unchanged.
 274 
 275       --  Step 1 - Adjust N so N / D >= 1 / Radix, or N = 0
 276 
 277       --  N and D are positive, so N / D >= 1 / Radix implies N * Radix >= D.
 278       --  As this scaling is not possible for N is Uint_0, zero is handled
 279       --  explicitly at the start of this subprogram.
 280 
 281       Calculate_N_And_Exponent : begin
 282          Uintp_Mark := Mark;
 283 
 284          N_Times_Radix := N * Radix;
 285          while not (N_Times_Radix >= D) loop
 286             N := N_Times_Radix;
 287             Exponent := Exponent - 1;
 288             N_Times_Radix := N * Radix;
 289          end loop;
 290 
 291          Release_And_Save (Uintp_Mark, N, Exponent);
 292       end Calculate_N_And_Exponent;
 293 
 294       --  Step 2 - Adjust D so N / D < 1
 295 
 296       --  Scale up D so N / D < 1, so N < D
 297 
 298       Calculate_D_And_Exponent_2 : begin
 299          Uintp_Mark := Mark;
 300 
 301          while not (N < D) loop
 302 
 303             --  As N / D >= 1, N / (D * Radix) will be at least 1 / Radix, so
 304             --  the result of Step 1 stays valid
 305 
 306             D := D * Radix;
 307             Exponent := Exponent + 1;
 308          end loop;
 309 
 310          Release_And_Save (Uintp_Mark, D, Exponent);
 311       end Calculate_D_And_Exponent_2;
 312 
 313       --  Here the value N / D is in the range [1.0 / Radix .. 1.0)
 314 
 315       --  Now find the fraction by doing a very simple-minded division until
 316       --  enough digits have been computed.
 317 
 318       --  This division works for all radices, but is only efficient for a
 319       --  binary radix. It is just like a manual division algorithm, but
 320       --  instead of moving the denominator one digit right, we move the
 321       --  numerator one digit left so the numerator and denominator remain
 322       --  integral.
 323 
 324       Fraction := Uint_0;
 325       Even := True;
 326 
 327       Calculate_Fraction_And_N : begin
 328          Uintp_Mark := Mark;
 329 
 330          loop
 331             while N >= D loop
 332                N := N - D;
 333                Fraction := Fraction + 1;
 334                Even := not Even;
 335             end loop;
 336 
 337             --  Stop when the result is in [1.0 / Radix, 1.0)
 338 
 339             exit when Fraction >= Most_Significant_Digit;
 340 
 341             N := N * Radix;
 342             Fraction := Fraction * Radix;
 343             Even := True;
 344          end loop;
 345 
 346          Release_And_Save (Uintp_Mark, Fraction, N);
 347       end Calculate_Fraction_And_N;
 348 
 349       Calculate_Fraction_And_Exponent : begin
 350          Uintp_Mark := Mark;
 351 
 352          --  Determine correct rounding based on the remainder which is in
 353          --  N and the divisor D. The rounding is performed on the absolute
 354          --  value of X, so Ceiling and Floor need to check for the sign of
 355          --  X explicitly.
 356 
 357          case Mode is
 358             when Round_Even =>
 359 
 360                --  This rounding mode corresponds to the unbiased rounding
 361                --  method that is used at run time. When the real value is
 362                --  exactly between two machine numbers, choose the machine
 363                --  number with its least significant bit equal to zero.
 364 
 365                --  The recommendation advice in RM 4.9(38) is that static
 366                --  expressions are rounded to machine numbers in the same
 367                --  way as the target machine does.
 368 
 369                if (Even and then N * 2 > D)
 370                      or else
 371                   (not Even and then N * 2 >= D)
 372                then
 373                   Fraction := Fraction + 1;
 374                end if;
 375 
 376             when Round   =>
 377 
 378                --  Do not round to even as is done with IEEE arithmetic, but
 379                --  instead round away from zero when the result is exactly
 380                --  between two machine numbers. This biased rounding method
 381                --  should not be used to convert static expressions to
 382                --  machine numbers, see AI95-268.
 383 
 384                if N * 2 >= D then
 385                   Fraction := Fraction + 1;
 386                end if;
 387 
 388             when Ceiling =>
 389                if N > Uint_0 and then not UR_Is_Negative (X) then
 390                   Fraction := Fraction + 1;
 391                end if;
 392 
 393             when Floor   =>
 394                if N > Uint_0 and then UR_Is_Negative (X) then
 395                   Fraction := Fraction + 1;
 396                end if;
 397          end case;
 398 
 399          --  The result must be normalized to [1.0/Radix, 1.0), so adjust if
 400          --  the result is 1.0 because of rounding.
 401 
 402          if Fraction = Most_Significant_Digit * Radix then
 403             Fraction := Most_Significant_Digit;
 404             Exponent := Exponent + 1;
 405          end if;
 406 
 407          --  Put back sign after applying the rounding
 408 
 409          if UR_Is_Negative (X) then
 410             Fraction := -Fraction;
 411          end if;
 412 
 413          Release_And_Save (Uintp_Mark, Fraction, Exponent);
 414       end Calculate_Fraction_And_Exponent;
 415    end Decompose_Int;
 416 
 417    --------------
 418    -- Exponent --
 419    --------------
 420 
 421    function Exponent (RT : R; X : T) return UI is
 422       X_Frac : UI;
 423       X_Exp  : UI;
 424       pragma Warnings (Off, X_Frac);
 425    begin
 426       Decompose_Int (RT, X, X_Frac, X_Exp, Round_Even);
 427       return X_Exp;
 428    end Exponent;
 429 
 430    -----------
 431    -- Floor --
 432    -----------
 433 
 434    function Floor (RT : R; X : T) return T is
 435       XT : constant T := Truncation (RT, X);
 436 
 437    begin
 438       if UR_Is_Positive (X) then
 439          return XT;
 440 
 441       elsif XT = X then
 442          return X;
 443 
 444       else
 445          return XT - Ureal_1;
 446       end if;
 447    end Floor;
 448 
 449    --------------
 450    -- Fraction --
 451    --------------
 452 
 453    function Fraction (RT : R; X : T) return T is
 454       X_Frac : T;
 455       X_Exp  : UI;
 456       pragma Warnings (Off, X_Exp);
 457    begin
 458       Decompose (RT, X, X_Frac, X_Exp);
 459       return X_Frac;
 460    end Fraction;
 461 
 462    ------------------
 463    -- Leading_Part --
 464    ------------------
 465 
 466    function Leading_Part (RT : R; X : T; Radix_Digits : UI) return T is
 467       RD : constant UI := UI_Min (Radix_Digits, Machine_Mantissa_Value (RT));
 468       L  : UI;
 469       Y  : T;
 470    begin
 471       L := Exponent (RT, X) - RD;
 472       Y := UR_From_Uint (UR_Trunc (Scaling (RT, X, -L)));
 473       return Scaling (RT, Y, L);
 474    end Leading_Part;
 475 
 476    -------------
 477    -- Machine --
 478    -------------
 479 
 480    function Machine
 481      (RT    : R;
 482       X     : T;
 483       Mode  : Rounding_Mode;
 484       Enode : Node_Id) return T
 485    is
 486       X_Frac : T;
 487       X_Exp  : UI;
 488       Emin   : constant UI := Machine_Emin_Value (RT);
 489 
 490    begin
 491       Decompose (RT, X, X_Frac, X_Exp, Mode);
 492 
 493       --  Case of denormalized number or (gradual) underflow
 494 
 495       --  A denormalized number is one with the minimum exponent Emin, but that
 496       --  breaks the assumption that the first digit of the mantissa is a one.
 497       --  This allows the first non-zero digit to be in any of the remaining
 498       --  Mant - 1 spots. The gap between subsequent denormalized numbers is
 499       --  the same as for the smallest normalized numbers. However, the number
 500       --  of significant digits left decreases as a result of the mantissa now
 501       --  having leading seros.
 502 
 503       if X_Exp < Emin then
 504          declare
 505             Emin_Den : constant UI := Machine_Emin_Value (RT)
 506                                         - Machine_Mantissa_Value (RT) + Uint_1;
 507          begin
 508             if X_Exp < Emin_Den or not Has_Denormals (RT) then
 509                if Has_Signed_Zeros (RT) and then UR_Is_Negative (X) then
 510                   Error_Msg_N
 511                     ("floating-point value underflows to -0.0??", Enode);
 512                   return Ureal_M_0;
 513 
 514                else
 515                   Error_Msg_N
 516                     ("floating-point value underflows to 0.0??", Enode);
 517                   return Ureal_0;
 518                end if;
 519 
 520             elsif Has_Denormals (RT) then
 521 
 522                --  Emin - Mant <= X_Exp < Emin, so result is denormal. Handle
 523                --  gradual underflow by first computing the number of
 524                --  significant bits still available for the mantissa and
 525                --  then truncating the fraction to this number of bits.
 526 
 527                --  If this value is different from the original fraction,
 528                --  precision is lost due to gradual underflow.
 529 
 530                --  We probably should round here and prevent double rounding as
 531                --  a result of first rounding to a model number and then to a
 532                --  machine number. However, this is an extremely rare case that
 533                --  is not worth the extra complexity. In any case, a warning is
 534                --  issued in cases where gradual underflow occurs.
 535 
 536                declare
 537                   Denorm_Sig_Bits : constant UI := X_Exp - Emin_Den + 1;
 538 
 539                   X_Frac_Denorm   : constant T := UR_From_Components
 540                     (UR_Trunc (Scaling (RT, abs X_Frac, Denorm_Sig_Bits)),
 541                      Denorm_Sig_Bits,
 542                      Radix,
 543                      UR_Is_Negative (X));
 544 
 545                begin
 546                   if X_Frac_Denorm /= X_Frac then
 547                      Error_Msg_N
 548                        ("gradual underflow causes loss of precision??",
 549                         Enode);
 550                      X_Frac := X_Frac_Denorm;
 551                   end if;
 552                end;
 553             end if;
 554          end;
 555       end if;
 556 
 557       return Scaling (RT, X_Frac, X_Exp);
 558    end Machine;
 559 
 560    -----------
 561    -- Model --
 562    -----------
 563 
 564    function Model (RT : R; X : T) return T is
 565       X_Frac : T;
 566       X_Exp  : UI;
 567    begin
 568       Decompose (RT, X, X_Frac, X_Exp);
 569       return Compose (RT, X_Frac, X_Exp);
 570    end Model;
 571 
 572    ----------
 573    -- Pred --
 574    ----------
 575 
 576    function Pred (RT : R; X : T) return T is
 577    begin
 578       return -Succ (RT, -X);
 579    end Pred;
 580 
 581    ---------------
 582    -- Remainder --
 583    ---------------
 584 
 585    function Remainder (RT : R; X, Y : T) return T is
 586       A        : T;
 587       B        : T;
 588       Arg      : T;
 589       P        : T;
 590       Arg_Frac : T;
 591       P_Frac   : T;
 592       Sign_X   : T;
 593       IEEE_Rem : T;
 594       Arg_Exp  : UI;
 595       P_Exp    : UI;
 596       K        : UI;
 597       P_Even   : Boolean;
 598 
 599       pragma Warnings (Off, Arg_Frac);
 600 
 601    begin
 602       if UR_Is_Positive (X) then
 603          Sign_X :=  Ureal_1;
 604       else
 605          Sign_X := -Ureal_1;
 606       end if;
 607 
 608       Arg := abs X;
 609       P   := abs Y;
 610 
 611       if Arg < P then
 612          P_Even := True;
 613          IEEE_Rem := Arg;
 614          P_Exp := Exponent (RT, P);
 615 
 616       else
 617          --  ??? what about zero cases?
 618          Decompose (RT, Arg, Arg_Frac, Arg_Exp);
 619          Decompose (RT, P,   P_Frac,   P_Exp);
 620 
 621          P := Compose (RT, P_Frac, Arg_Exp);
 622          K := Arg_Exp - P_Exp;
 623          P_Even := True;
 624          IEEE_Rem := Arg;
 625 
 626          for Cnt in reverse 0 .. UI_To_Int (K) loop
 627             if IEEE_Rem >= P then
 628                P_Even := False;
 629                IEEE_Rem := IEEE_Rem - P;
 630             else
 631                P_Even := True;
 632             end if;
 633 
 634             P := P * Ureal_Half;
 635          end loop;
 636       end if;
 637 
 638       --  That completes the calculation of modulus remainder. The final step
 639       --  is get the IEEE remainder. Here we compare Rem with (abs Y) / 2.
 640 
 641       if P_Exp >= 0 then
 642          A := IEEE_Rem;
 643          B := abs Y * Ureal_Half;
 644 
 645       else
 646          A := IEEE_Rem * Ureal_2;
 647          B := abs Y;
 648       end if;
 649 
 650       if A > B or else (A = B and then not P_Even) then
 651          IEEE_Rem := IEEE_Rem - abs Y;
 652       end if;
 653 
 654       return Sign_X * IEEE_Rem;
 655    end Remainder;
 656 
 657    --------------
 658    -- Rounding --
 659    --------------
 660 
 661    function Rounding (RT : R; X : T) return T is
 662       Result : T;
 663       Tail   : T;
 664 
 665    begin
 666       Result := Truncation (RT, abs X);
 667       Tail   := abs X - Result;
 668 
 669       if Tail >= Ureal_Half then
 670          Result := Result + Ureal_1;
 671       end if;
 672 
 673       if UR_Is_Negative (X) then
 674          return -Result;
 675       else
 676          return Result;
 677       end if;
 678    end Rounding;
 679 
 680    -------------
 681    -- Scaling --
 682    -------------
 683 
 684    function Scaling (RT : R; X : T; Adjustment : UI) return T is
 685       pragma Warnings (Off, RT);
 686 
 687    begin
 688       if Rbase (X) = Radix then
 689          return UR_From_Components
 690            (Num      => Numerator (X),
 691             Den      => Denominator (X) - Adjustment,
 692             Rbase    => Radix,
 693             Negative => UR_Is_Negative (X));
 694 
 695       elsif Adjustment >= 0 then
 696          return X * Radix ** Adjustment;
 697       else
 698          return X / Radix ** (-Adjustment);
 699       end if;
 700    end Scaling;
 701 
 702    ----------
 703    -- Succ --
 704    ----------
 705 
 706    function Succ (RT : R; X : T) return T is
 707       Emin     : constant UI := Machine_Emin_Value (RT);
 708       Mantissa : constant UI := Machine_Mantissa_Value (RT);
 709       Exp      : UI := UI_Max (Emin, Exponent (RT, X));
 710       Frac     : T;
 711       New_Frac : T;
 712 
 713    begin
 714       if UR_Is_Zero (X) then
 715          Exp := Emin;
 716       end if;
 717 
 718       --  Set exponent such that the radix point will be directly following the
 719       --  mantissa after scaling.
 720 
 721       if Has_Denormals (RT) or Exp /= Emin then
 722          Exp := Exp - Mantissa;
 723       else
 724          Exp := Exp - 1;
 725       end if;
 726 
 727       Frac := Scaling (RT, X, -Exp);
 728       New_Frac := Ceiling (RT, Frac);
 729 
 730       if New_Frac = Frac then
 731          if New_Frac = Scaling (RT, -Ureal_1, Mantissa - 1) then
 732             New_Frac := New_Frac + Scaling (RT, Ureal_1, Uint_Minus_1);
 733          else
 734             New_Frac := New_Frac + Ureal_1;
 735          end if;
 736       end if;
 737 
 738       return Scaling (RT, New_Frac, Exp);
 739    end Succ;
 740 
 741    ----------------
 742    -- Truncation --
 743    ----------------
 744 
 745    function Truncation (RT : R; X : T) return T is
 746       pragma Warnings (Off, RT);
 747    begin
 748       return UR_From_Uint (UR_Trunc (X));
 749    end Truncation;
 750 
 751    -----------------------
 752    -- Unbiased_Rounding --
 753    -----------------------
 754 
 755    function Unbiased_Rounding (RT : R; X : T) return T is
 756       Abs_X  : constant T := abs X;
 757       Result : T;
 758       Tail   : T;
 759 
 760    begin
 761       Result := Truncation (RT, Abs_X);
 762       Tail   := Abs_X - Result;
 763 
 764       if Tail > Ureal_Half then
 765          Result := Result + Ureal_1;
 766 
 767       elsif Tail = Ureal_Half then
 768          Result := Ureal_2 *
 769                      Truncation (RT, (Result / Ureal_2) + Ureal_Half);
 770       end if;
 771 
 772       if UR_Is_Negative (X) then
 773          return -Result;
 774       elsif UR_Is_Positive (X) then
 775          return Result;
 776 
 777       --  For zero case, make sure sign of zero is preserved
 778 
 779       else
 780          return X;
 781       end if;
 782    end Unbiased_Rounding;
 783 
 784 end Eval_Fat;