home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / urealp.adb < prev    next >
Text File  |  1996-09-28  |  39KB  |  1,333 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT COMPILER COMPONENTS                         --
  4. --                                                                          --
  5. --                               U R E A L P                                --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                             $Revision: 1.30 $                            --
  10. --                                                                          --
  11. --        Copyright (c) 1992,1993,1994,1995 NYU, All Rights Reserved        --
  12. --                                                                          --
  13. -- The GNAT library is free software; you can redistribute it and/or modify --
  14. -- it under terms of the GNU Library General Public License as published by --
  15. -- the Free Software  Foundation; either version 2, or (at your option) any --
  16. -- later version.  The GNAT library is distributed in the hope that it will --
  17. -- be useful, but WITHOUT ANY WARRANTY;  without even  the implied warranty --
  18. -- of MERCHANTABILITY  or  FITNESS FOR  A PARTICULAR PURPOSE.  See the  GNU --
  19. -- Library  General  Public  License for  more  details.  You  should  have --
  20. -- received  a copy of the GNU  Library  General Public License  along with --
  21. -- the GNAT library;  see the file  COPYING.LIB.  If not, write to the Free --
  22. -- Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.        --
  23. --                                                                          --
  24. ------------------------------------------------------------------------------
  25.  
  26. with Alloc;   use Alloc;
  27. with Output;  use Output;
  28. with Table;
  29. with Tree_IO; use Tree_IO;
  30.  
  31. package body Urealp is
  32.  
  33.    Ureal_First_Entry : constant Ureal := Ureal'Succ (No_Ureal);
  34.    --  First subscript allocated in Ureal table (note that we can't just
  35.    --  add 1 to No_Ureal, since "+" means something different for Ureals!
  36.  
  37.    type Ureal_Entry is record
  38.       Num  : Uint;
  39.       --  Numerator (always non-negative)
  40.  
  41.       Den  : Uint;
  42.       --  Denominator (always non-zero, always positive if base is zero)
  43.  
  44.       Rbase : Nat;
  45.       --  Base value. If Rbase is zero, then the value is simply Num / Den.
  46.       --  If Rbase is non-zero, then the value is Num / (Rbase ** Den)
  47.  
  48.       Negative : Boolean;
  49.       --  Flag set if value is negative
  50.  
  51.    end record;
  52.  
  53.    package Ureals is new Table (
  54.      Table_Component_Type => Ureal_Entry,
  55.      Table_Index_Type     => Ureal,
  56.      Table_Low_Bound      => Ureal_First_Entry,
  57.      Table_Initial        => Alloc_Ureals_Initial,
  58.      Table_Increment      => Alloc_Ureals_Increment,
  59.      Table_Name           => "Ureals");
  60.  
  61.    --  The following universal reals are the values returned by the constant
  62.    --  functions. They are initialized by the initialization procedure.
  63.  
  64.    UR_0          : Ureal;
  65.    UR_Tenth      : Ureal;
  66.    UR_Half       : Ureal;
  67.    UR_1          : Ureal;
  68.    UR_2          : Ureal;
  69.    UR_10         : Ureal;
  70.    UR_Fine_Delta : Ureal;
  71.  
  72.    Normalized_Real : Ureal := No_Ureal;
  73.    --  Used to memoize Norm_Num and Norm_Den, if either of these functions
  74.    --  is called, this value is set and Normalized_Entry contains the result
  75.    --  of the normalization. On subsequent calls, this is used to avoid the
  76.    --  call to Normalize if it has already been made.
  77.  
  78.    Normalized_Entry : Ureal_Entry;
  79.    --  Entry built by most recent call to Normalize
  80.  
  81.    -----------------------
  82.    -- Local Subprograms --
  83.    -----------------------
  84.  
  85.    function Decimal_Exponent_Hi (V : Ureal) return Int;
  86.    --  Returns an estimate of the exponent of Val represented as a normalized
  87.    --  decimal number (non-zero digit before decimal point), The estimate is
  88.    --  either correct, or high, but never low. The accuracy of the estimate
  89.    --  affects only the efficiency of the comparison routines.
  90.  
  91.    function Decimal_Exponent_Lo (V : Ureal) return Int;
  92.    --  Returns an estimate of the exponent of Val represented as a normalized
  93.    --  decimal number (non-zero digit before decimal point), The estimate is
  94.    --  either correct, or low, but never high. The accuracy of the estimate
  95.    --  affects only the efficiency of the comparison routines.
  96.  
  97.    function Equivalent_Decimal_Exponent (U : Ureal_Entry) return Int;
  98.    --  U is a Ureal entry for which the base value is non-zero, the value
  99.    --  returned is the equivalent decimal exponent value, i.e. the value of
  100.    --  Den, adjusted as though the base were base 10. The value is rounded
  101.    --  to the nearest integer, and so can be one off.
  102.  
  103.    function Is_Integer (Num, Den : Uint) return boolean;
  104.    --  Return true if the real quotient of Num / Den is an integer value
  105.  
  106.    function Normalize (Val : Ureal_Entry) return Ureal_Entry;
  107.    --  Normalizes the Ureal_Entry by reducing it to lowest terms (with a
  108.    --  base value of 0).
  109.  
  110.    function Same (U1, U2 : Ureal) return Boolean;
  111.    pragma Inline (Same);
  112.    --  Determines if U1 and U2 are the same Ureal. Note that we cannot use
  113.    --  the equals operator for this test, it means something else!
  114.  
  115.    function Store_Ureal (Val : Ureal_Entry) return Ureal;
  116.    --  This store a new entry in the universal reals table and return
  117.    --  its index in the table.
  118.  
  119.    -------------------------
  120.    -- Decimal_Exponent_Hi --
  121.    -------------------------
  122.  
  123.    function Decimal_Exponent_Hi (V : Ureal) return Int is
  124.       Val : constant Ureal_Entry := Ureals.Table (V);
  125.  
  126.    begin
  127.       --  For numbers in rational form, get the maximum number of digits in the
  128.       --  numerator and the minimum number of digits in the denominator, and
  129.       --  subtract. For example:
  130.  
  131.       --     1000 / 99 = 1.010E+1
  132.       --     9999 / 10 = 9.999E+2
  133.  
  134.       --  This estimate may of course be high, but that is acceptable
  135.  
  136.       if Val.Rbase = 0 then
  137.          return UI_Decimal_Digits_Hi (Val.Num) -
  138.                 UI_Decimal_Digits_Lo (Val.Den);
  139.  
  140.       --  For based numbers, just subtract the decimal exponent from the
  141.       --  high estimate of the number of digits in the numerator and add
  142.       --  one to accomodate possible round off errors for non-decimal
  143.       --  bases. For example:
  144.  
  145.       --     1_500_000 / 10**4 = 1.50E-2
  146.  
  147.       else -- Val.Rbase /= 0
  148.          return UI_Decimal_Digits_Hi (Val.Num) -
  149.                 Equivalent_Decimal_Exponent (Val) + 1;
  150.       end if;
  151.  
  152.    end Decimal_Exponent_Hi;
  153.  
  154.    -------------------------
  155.    -- Decimal_Exponent_Lo --
  156.    -------------------------
  157.  
  158.    function Decimal_Exponent_Lo (V : Ureal) return Int is
  159.       Val : constant Ureal_Entry := Ureals.Table (V);
  160.  
  161.    begin
  162.       --  For numbers in rational form, get min digits in numerator, max digits
  163.       --  in denominator, and subtract and subtract one more for possible loss
  164.       --  during the division. For example:
  165.  
  166.       --     1000 / 99 = 1.010E+1
  167.       --     9999 / 10 = 9.999E+2
  168.  
  169.       --  This estimate may of course be low, but that is acceptable
  170.  
  171.       if Val.Rbase = 0 then
  172.          return UI_Decimal_Digits_Lo (Val.Num) -
  173.                 UI_Decimal_Digits_Hi (Val.Den) - 1;
  174.  
  175.       --  For based numbers, just subtract the decimal exponent from the
  176.       --  low estimate of the number of digits in the numerator and subtract
  177.       --  one to accomodate possible round off errors for non-decimal
  178.       --  bases. For example:
  179.  
  180.       --     1_500_000 / 10**4 = 1.50E-2
  181.  
  182.       else -- Val.Rbase /= 0
  183.          return UI_Decimal_Digits_Lo (Val.Num) -
  184.                 Equivalent_Decimal_Exponent (Val) - 1;
  185.       end if;
  186.  
  187.    end Decimal_Exponent_Lo;
  188.  
  189.    -----------------
  190.    -- Denominator --
  191.    -----------------
  192.  
  193.    function Denominator (Real : Ureal) return Uint is
  194.       Val : Ureal_Entry := Ureals.Table (Real);
  195.  
  196.    begin
  197.       return Val.Den;
  198.    end Denominator;
  199.  
  200.    ---------------------------------
  201.    -- Equivalent_Decimal_Exponent --
  202.    ---------------------------------
  203.  
  204.    function Equivalent_Decimal_Exponent (U : Ureal_Entry) return Int is
  205.  
  206.       --  The following table is a table of logs to the base 10
  207.  
  208.       Logs : array (Nat range 2 .. 16) of Long_Float := (
  209.                 2 => 0.301029995663981,
  210.                 3 => 0.477121254719662,
  211.                 4 => 0.602059991327962,
  212.                 5 => 0.698970004336019,
  213.                 6 => 0.778151250383644,
  214.                 7 => 0.845098040014257,
  215.                 8 => 0.903089986991944,
  216.                 9 => 0.954242509439325,
  217.                10 => 1.000000000000000,
  218.                11 => 1.041392685158230,
  219.                12 => 1.079181246047620,
  220.                13 => 1.113943352306840,
  221.                14 => 1.146128035678240,
  222.                15 => 1.176091259055680,
  223.                16 => 1.204119982655920);
  224.  
  225.    begin
  226.       pragma Assert (U.Rbase /= 0);
  227.       return Int (Long_Float (UI_To_Int (U.Den)) * Logs (U.Rbase));
  228.    end Equivalent_Decimal_Exponent;
  229.  
  230.    ----------------
  231.    -- Initialize --
  232.    ----------------
  233.  
  234.    procedure Initialize is
  235.    begin
  236.       Ureals.Init;
  237.       UR_0          := UR_From_Components (Uint_0, Uint_1);
  238.       UR_Half       := UR_From_Components (Uint_1, Uint_1, 2);
  239.       UR_Tenth      := UR_From_Components (Uint_1, Uint_1, 10);
  240.       UR_1          := UR_From_Components (Uint_1, Uint_1);
  241.       UR_2          := UR_From_Components (Uint_1, Uint_Minus_1, 2);
  242.       UR_10         := UR_From_Components (Uint_1, Uint_Minus_1, 10);
  243.       UR_Fine_Delta := UR_From_Components (Uint_1, Uint_63, 2);
  244.    end Initialize;
  245.  
  246.    ----------------
  247.    -- Is_Integer --
  248.    ----------------
  249.  
  250.    function Is_Integer (Num, Den : Uint) return Boolean is
  251.    begin
  252.       return (Num / Den) * Den = Num;
  253.    end Is_Integer;
  254.  
  255.    ----------
  256.    -- Mark --
  257.    ----------
  258.  
  259.    function Mark return Save_Mark is
  260.    begin
  261.       return Save_Mark (Ureals.Last);
  262.    end Mark;
  263.  
  264.    --------------
  265.    -- Norm_Den --
  266.    --------------
  267.  
  268.    function Norm_Den (Real : Ureal) return Uint is
  269.    begin
  270.       if not Same (Real, Normalized_Real) then
  271.          Normalized_Real  := Real;
  272.          Normalized_Entry := Normalize (Ureals.Table (Real));
  273.       end if;
  274.  
  275.       return Normalized_Entry.Den;
  276.    end Norm_Den;
  277.  
  278.    --------------
  279.    -- Norm_Num --
  280.    --------------
  281.  
  282.    function Norm_Num (Real : Ureal) return Uint is
  283.    begin
  284.       if not Same (Real, Normalized_Real) then
  285.          Normalized_Real  := Real;
  286.          Normalized_Entry := Normalize (Ureals.Table (Real));
  287.       end if;
  288.  
  289.       return Normalized_Entry.Num;
  290.    end Norm_Num;
  291.  
  292.    ---------------
  293.    -- Normalize --
  294.    ---------------
  295.  
  296.    function Normalize (Val : Ureal_Entry) return Ureal_Entry is
  297.       J, K, Tmp : Uint;
  298.       Num, Den  : Uint;
  299.  
  300.    begin
  301.       --  Start by setting J to the greatest of the absolute values of the
  302.       --  numerator and the denominator (taking into account the base value),
  303.       --  and K to the lesser of the two absolute values. The gcd of Num and
  304.       --  Den is the gcd of J and K.
  305.  
  306.       if Val.Rbase = 0 then
  307.          J := Val.Num;
  308.          K := Val.Den;
  309.  
  310.       elsif Val.Den < 0 then
  311.          J := Val.Num * Val.Rbase ** (-Val.Den);
  312.          K := Uint_1;
  313.  
  314.       else
  315.          J := Val.Num;
  316.          K := Val.Rbase ** Val.Den;
  317.       end if;
  318.  
  319.       Num := J;
  320.       Den := K;
  321.  
  322.       if K > J then
  323.          Tmp := J;
  324.          J := K;
  325.          K := Tmp;
  326.       end if;
  327.  
  328.       --  Now apply Euclid's algorithm to find the gcd, which is left in J.
  329.  
  330.       while K /= 0 loop
  331.          Tmp := J mod K;
  332.          J := K;
  333.          K := Tmp;
  334.       end loop;
  335.  
  336.       --  Divide numerator and denominator by gcd and return result
  337.  
  338.       return (Num      => Num / J,
  339.               Den      => Den / J,
  340.               Rbase    => 0,
  341.               Negative => Val.Negative);
  342.    end Normalize;
  343.  
  344.    ---------------
  345.    -- Numerator --
  346.    ---------------
  347.  
  348.    function Numerator (Real : Ureal) return Uint is
  349.       Val : Ureal_Entry := Ureals.Table (Real);
  350.  
  351.    begin
  352.       return Val.Num;
  353.    end Numerator;
  354.  
  355.    -----------
  356.    -- Rbase --
  357.    -----------
  358.  
  359.    function Rbase (Real : Ureal) return Nat is
  360.       Val : Ureal_Entry := Ureals.Table (Real);
  361.  
  362.    begin
  363.       return Val.Rbase;
  364.    end Rbase;
  365.  
  366.    -------------
  367.    -- Release --
  368.    -------------
  369.  
  370.    procedure Release (M : Save_Mark) is
  371.    begin
  372.       Ureals.Set_Last (Ureal (M));
  373.    end Release;
  374.  
  375.    ----------
  376.    -- Same --
  377.    ----------
  378.  
  379.    function Same (U1, U2 : Ureal) return Boolean is
  380.    begin
  381.       return Int (U1) = Int (U2);
  382.    end Same;
  383.  
  384.    -----------------
  385.    -- Store_Ureal --
  386.    -----------------
  387.  
  388.    function Store_Ureal (Val : Ureal_Entry) return Ureal is
  389.    begin
  390.       Ureals.Increment_Last;
  391.       Ureals.Table (Ureals.Last) := Val;
  392.  
  393.       --  Normalize representation of signed values
  394.  
  395.       if Val.Num < 0 then
  396.          Ureals.Table (Ureals.Last).Negative := True;
  397.          Ureals.Table (Ureals.Last).Num := -Val.Num;
  398.       end if;
  399.  
  400.       return Ureals.Last;
  401.    end Store_Ureal;
  402.  
  403.    ---------------
  404.    -- Tree_Read --
  405.    ---------------
  406.  
  407.    procedure Tree_Read is
  408.    begin
  409.       Ureals.Tree_Read;
  410.       Tree_Read_Int (Int (UR_0));
  411.       Tree_Read_Int (Int (UR_Tenth));
  412.       Tree_Read_Int (Int (UR_Half));
  413.       Tree_Read_Int (Int (UR_1));
  414.       Tree_Read_Int (Int (UR_2));
  415.       Tree_Read_Int (Int (UR_10));
  416.       Tree_Read_Int (Int (UR_Fine_Delta));
  417.    end Tree_Read;
  418.  
  419.    ----------------
  420.    -- Tree_Write --
  421.    ----------------
  422.  
  423.    procedure Tree_Write is
  424.    begin
  425.       Ureals.Tree_Write;
  426.       Tree_Write_Int (Int (UR_0));
  427.       Tree_Write_Int (Int (UR_Tenth));
  428.       Tree_Write_Int (Int (UR_Half));
  429.       Tree_Write_Int (Int (UR_1));
  430.       Tree_Write_Int (Int (UR_2));
  431.       Tree_Write_Int (Int (UR_10));
  432.       Tree_Write_Int (Int (UR_Fine_Delta));
  433.    end Tree_Write;
  434.  
  435.    ----------------
  436.    -- Ureal_Half --
  437.    ----------------
  438.  
  439.    function Ureal_Half return Ureal is
  440.    begin
  441.       return UR_Half;
  442.    end Ureal_Half;
  443.  
  444.    -----------------
  445.    -- Ureal_Tenth --
  446.    -----------------
  447.  
  448.    function Ureal_Tenth return Ureal is
  449.    begin
  450.       return UR_Tenth;
  451.    end Ureal_Tenth;
  452.  
  453.    -------------
  454.    -- Ureal_0 --
  455.    -------------
  456.  
  457.    function Ureal_0 return Ureal is
  458.    begin
  459.       return UR_0;
  460.    end Ureal_0;
  461.  
  462.    -------------
  463.    -- Ureal_1 --
  464.    -------------
  465.  
  466.    function Ureal_1 return Ureal is
  467.    begin
  468.       return UR_1;
  469.    end Ureal_1;
  470.  
  471.    -------------
  472.    -- Ureal_2 --
  473.    -------------
  474.  
  475.    function Ureal_2 return Ureal is
  476.    begin
  477.       return UR_2;
  478.    end Ureal_2;
  479.  
  480.    --------------
  481.    -- Ureal_10 --
  482.    --------------
  483.  
  484.    function Ureal_10 return Ureal is
  485.    begin
  486.       return UR_10;
  487.    end Ureal_10;
  488.  
  489.    ----------------------
  490.    -- Ureal_Fine_Delta --
  491.    ----------------------
  492.  
  493.    function Ureal_Fine_Delta return Ureal is
  494.    begin
  495.       return UR_Fine_Delta;
  496.    end Ureal_Fine_Delta;
  497.  
  498.    ------------
  499.    -- UR_Abs --
  500.    ------------
  501.  
  502.    function UR_Abs (Real : Ureal) return Ureal is
  503.       Val : constant Ureal_Entry := Ureals.Table (Real);
  504.  
  505.    begin
  506.       return Store_Ureal (
  507.                (Num      => Val.Num,
  508.                 Den      => Val.Den,
  509.                 Rbase    => Val.Rbase,
  510.                 Negative => False));
  511.    end UR_Abs;
  512.  
  513.    ------------
  514.    -- UR_Add --
  515.    ------------
  516.  
  517.    function UR_Add (Left : Uint; Right : Ureal) return Ureal is
  518.    begin
  519.       return UR_From_Uint (Left) + Right;
  520.    end UR_Add;
  521.  
  522.    function UR_Add (Left : Ureal; Right : Uint) return Ureal is
  523.    begin
  524.       return Left + UR_From_Uint (Right);
  525.    end UR_Add;
  526.  
  527.    function UR_Add (Left : Ureal; Right : Ureal) return Ureal is
  528.       Lval : Ureal_Entry := Ureals.Table (Left);
  529.       Rval : Ureal_Entry := Ureals.Table (Right);
  530.  
  531.       Num  : Uint;
  532.  
  533.    begin
  534.       --  Note, in the temporary Ureal_Entry values used in this procedure,
  535.       --  we store the sign as the sign of the numerator (i.e. xxx.Num may
  536.       --  be negative, even though in stored entries this can never be so)
  537.  
  538.       if Lval.Rbase /= 0 and then Lval.Rbase = Rval.Rbase then
  539.  
  540.          declare
  541.             Opd_Min, Opd_Max   : Ureal_Entry;
  542.             Exp_Min, Exp_Max   : Uint;
  543.  
  544.          begin
  545.             if Lval.Negative then
  546.                Lval.Num := (-Lval.Num);
  547.             end if;
  548.  
  549.             if Rval.Negative then
  550.                Rval.Num := (-Rval.Num);
  551.             end if;
  552.  
  553.             if Lval.Den < Rval.Den then
  554.                Exp_Min := Lval.Den;
  555.                Exp_Max := Rval.Den;
  556.                Opd_Min := Lval;
  557.                Opd_Max := Rval;
  558.             else
  559.                Exp_Min := Rval.Den;
  560.                Exp_Max := Lval.Den;
  561.                Opd_Min := Rval;
  562.                Opd_Max := Lval;
  563.             end if;
  564.  
  565.             Num :=
  566.               Opd_Min.Num * Lval.Rbase ** (Exp_Max - Exp_Min) + Opd_Max.Num;
  567.  
  568.             if Num = 0 then
  569.                return Store_Ureal (
  570.                         (Num      => Uint_0,
  571.                          Den      => Uint_1,
  572.                          Rbase    => 0,
  573.                          Negative => Lval.Negative));
  574.  
  575.             else
  576.                return Store_Ureal (
  577.                         (Num      => abs Num,
  578.                          Den      => Exp_Max,
  579.                          Rbase    => Lval.Rbase,
  580.                          Negative => (Num < 0)));
  581.             end if;
  582.          end;
  583.  
  584.       else
  585.          declare
  586.             Ln : Ureal_Entry := Normalize (Lval);
  587.             Rn : Ureal_Entry := Normalize (Rval);
  588.  
  589.          begin
  590.             if Ln.Negative then
  591.                Ln.Num := (-Ln.Num);
  592.             end if;
  593.  
  594.             if Rn.Negative then
  595.                Rn.Num := (-Rn.Num);
  596.             end if;
  597.  
  598.             Num := (Ln.Num * Rn.Den) + (Rn.Num * Ln.Den);
  599.  
  600.             if Num = 0 then
  601.                return Store_Ureal (
  602.                         (Num      => Uint_0,
  603.                          Den      => Uint_1,
  604.                          Rbase    => 0,
  605.                          Negative => Lval.Negative));
  606.  
  607.             else
  608.                return Store_Ureal (
  609.                         Normalize (
  610.                           (Num      => abs Num,
  611.                            Den      => Ln.Den * Rn.Den,
  612.                            Rbase    => 0,
  613.                            Negative => (Num < 0))));
  614.             end if;
  615.          end;
  616.       end if;
  617.    end UR_Add;
  618.  
  619.    ------------
  620.    -- UR_Div --
  621.    ------------
  622.  
  623.    function UR_Div (Left : Uint; Right : Ureal) return Ureal is
  624.    begin
  625.       return UR_From_Uint (Left) / Right;
  626.    end UR_Div;
  627.  
  628.    function UR_Div (Left : Ureal; Right : Uint) return Ureal is
  629.    begin
  630.       return Left / UR_From_Uint (Right);
  631.    end UR_Div;
  632.  
  633.    function UR_Div (Left, Right : Ureal) return Ureal is
  634.       Lval : constant Ureal_Entry := Ureals.Table (Left);
  635.       Rval : constant Ureal_Entry := Ureals.Table (Right);
  636.       Rneg : constant Boolean     := Rval.Negative xor Lval.Negative;
  637.  
  638.    begin
  639.       pragma Assert (Rval.Num /= Uint_0);
  640.  
  641.       if Lval.Rbase = 0 then
  642.  
  643.          if Rval.Rbase = 0 then
  644.             return Store_Ureal (
  645.                      Normalize (
  646.                        (Num      => Lval.Num * Rval.Den,
  647.                         Den      => Lval.Den * Rval.Num,
  648.                         Rbase    => 0,
  649.                         Negative => Rneg)));
  650.  
  651.          elsif Is_Integer (Lval.Num, Rval.Num * Lval.Den) then
  652.             return Store_Ureal (
  653.                      (Num      => Lval.Num / (Rval.Num * Lval.Den),
  654.                       Den      => (-Rval.Den),
  655.                       Rbase    => Rval.Rbase,
  656.                       Negative => Rneg));
  657.  
  658.          elsif Rval.Den < 0 then
  659.             return Store_Ureal (
  660.                      Normalize (
  661.                        (Num      => Lval.Num,
  662.                         Den      => Rval.Rbase ** (-Rval.Den) *
  663.                                     Rval.Num *
  664.                                     Lval.Den,
  665.                         Rbase    => 0,
  666.                         Negative => Rneg)));
  667.  
  668.          else
  669.             return Store_Ureal (
  670.                      Normalize (
  671.                        (Num      => Lval.Num * Rval.Rbase ** Rval.Den,
  672.                         Den      => Rval.Num * Lval.Den,
  673.                         Rbase    => 0,
  674.                         Negative => Rneg)));
  675.          end if;
  676.  
  677.       elsif Is_Integer (Lval.Num, Rval.Num) then
  678.  
  679.          if Rval.Rbase = Lval.Rbase then
  680.             return Store_Ureal (
  681.                      (Num      => Lval.Num / Rval.Num,
  682.                       Den      => Lval.Den - Rval.Den,
  683.                       Rbase    => Lval.Rbase,
  684.                       Negative => Rneg));
  685.  
  686.          elsif Rval.Rbase = 0 then
  687.             return Store_Ureal (
  688.                      (Num      => (Lval.Num / Rval.Num) * Rval.Den,
  689.                       Den      => Lval.Den,
  690.                       Rbase    => Lval.Rbase,
  691.                       Negative => Rneg));
  692.  
  693.          elsif Rval.Den < 0 then
  694.             declare
  695.                Num, Den : Uint;
  696.  
  697.             begin
  698.                if Lval.Den < 0 then
  699.                   Num := (Lval.Num / Rval.Num) * (Lval.Rbase ** (-Lval.Den));
  700.                   Den := Rval.Rbase ** (-Rval.Den);
  701.                else
  702.                   Num := Lval.Num / Rval.Num;
  703.                   Den := (Lval.Rbase ** Lval.Den) *
  704.                          (Rval.Rbase ** (-Rval.Den));
  705.                end if;
  706.  
  707.                return Store_Ureal (
  708.                         (Num      => Num,
  709.                          Den      => Den,
  710.                          Rbase    => 0,
  711.                          Negative => Rneg));
  712.             end;
  713.  
  714.          else
  715.             return Store_Ureal (
  716.                      (Num      => (Lval.Num / Rval.Num) *
  717.                                   (Rval.Rbase ** Rval.Den),
  718.                       Den      => Lval.Den,
  719.                       Rbase    => Lval.Rbase,
  720.                       Negative => Rneg));
  721.          end if;
  722.  
  723.       else
  724.          declare
  725.             Num, Den : Uint;
  726.  
  727.          begin
  728.             if Lval.Den < 0 then
  729.                Num := Lval.Num * (Lval.Rbase ** (-Lval.Den));
  730.                Den := Rval.Num;
  731.  
  732.             else
  733.                Num := Lval.Num;
  734.                Den := Rval.Num * (Lval.Rbase ** Lval.Den);
  735.             end if;
  736.  
  737.             if Rval.Rbase /= 0 then
  738.                if Rval.Den < 0 then
  739.                   Den := Den * (Rval.Rbase ** (-Rval.Den));
  740.                else
  741.                   Num := Num * (Rval.Rbase ** Rval.Den);
  742.                end if;
  743.  
  744.             else
  745.                Num := Num * Rval.Den;
  746.             end if;
  747.  
  748.             return Store_Ureal (
  749.                      Normalize (
  750.                        (Num      => Num,
  751.                         Den      => Den,
  752.                         Rbase    => 0,
  753.                         Negative => Rneg)));
  754.          end;
  755.       end if;
  756.    end UR_Div;
  757.  
  758.    -----------
  759.    -- UR_Eq --
  760.    -----------
  761.  
  762.    function UR_Eq (Left, Right : Ureal) return Boolean is
  763.    begin
  764.       return not UR_Ne (Left, Right);
  765.    end UR_Eq;
  766.  
  767.    ---------------------
  768.    -- UR_Exponentiate --
  769.    ---------------------
  770.  
  771.    function UR_Exponentiate (Real : Ureal; N : Uint) return Ureal is
  772.       Val : Ureal_Entry := Ureals.Table (Real);
  773.       X   : Uint        := abs N;
  774.  
  775.    begin
  776.       --  If the exponent is negative then we raise the numerator and the
  777.       --  denominator (after normalization) to the absolute value of the
  778.       --  exponent and we return the reciprocal. An assert error will happen
  779.       --  if the numerator is zero.
  780.  
  781.       if N < 0 then
  782.          pragma Assert (Val.Num /= 0);
  783.          Val := Normalize (Val);
  784.  
  785.          return Store_Ureal (
  786.                  (Num      => Val.Den ** X,
  787.                   Den      => Val.Num ** X,
  788.                   Rbase    => 0,
  789.                   Negative => Val.Negative));
  790.  
  791.       --  If positive, we distinguish the case when the base is not zero, in
  792.       --  which case the new denominator is just the product of the old one
  793.       --  with the exponent,
  794.  
  795.       else
  796.          if Val.Rbase /= 0 then
  797.  
  798.             return Store_Ureal (
  799.                     (Num      => Val.Num ** X,
  800.                      Den      => Val.Den * X,
  801.                      Rbase    => Val.Rbase,
  802.                      Negative => Val.Negative));
  803.  
  804.          --  And when the base is zero, in which case we exponentiate
  805.          --  the old denominator.
  806.  
  807.          else
  808.             return Store_Ureal (
  809.                     (Num      => Val.Num ** X,
  810.                      Den      => Val.Den ** X,
  811.                      Rbase    => 0,
  812.                      Negative => Val.Negative));
  813.          end if;
  814.       end if;
  815.    end UR_Exponentiate;
  816.  
  817.    -------------------------
  818.    --  UR_From_Components --
  819.    -------------------------
  820.  
  821.    function UR_From_Components
  822.      (Num      : Uint;
  823.       Den      : Uint;
  824.       Rbase    : Nat := 0;
  825.       Negative : Boolean := False)
  826.       return     Ureal
  827.    is
  828.    begin
  829.       return Store_Ureal (
  830.                (Num      => Num,
  831.                 Den      => Den,
  832.                 Rbase    => Rbase,
  833.                 Negative => Negative));
  834.    end UR_From_Components;
  835.  
  836.    ------------------
  837.    -- UR_From_Uint --
  838.    ------------------
  839.  
  840.    function UR_From_Uint (UI : Uint) return Ureal is
  841.    begin
  842.       return UR_From_Components
  843.         (abs UI, Uint_1, Negative => (UI < 0));
  844.    end UR_From_Uint;
  845.  
  846.    -----------
  847.    -- UR_Ge --
  848.    -----------
  849.  
  850.    function UR_Ge (Left, Right : Ureal) return Boolean is
  851.    begin
  852.       return not (Left < Right);
  853.    end UR_Ge;
  854.  
  855.    -----------
  856.    -- UR_Gt --
  857.    -----------
  858.  
  859.    function UR_Gt (Left, Right : Ureal) return Boolean is
  860.    begin
  861.       return (Right < Left);
  862.    end UR_Gt;
  863.  
  864.    --------------------
  865.    -- UR_Is_Negative --
  866.    --------------------
  867.  
  868.    function UR_Is_Negative (Real : Ureal) return Boolean is
  869.    begin
  870.       return Ureals.Table (Real).Negative
  871.         and then Ureals.Table (Real).Num /= 0;
  872.    end UR_Is_Negative;
  873.  
  874.    --------------------
  875.    -- UR_Is_Positive --
  876.    --------------------
  877.  
  878.    function UR_Is_Positive (Real : Ureal) return Boolean is
  879.    begin
  880.       return not Ureals.Table (Real).Negative
  881.         and then Ureals.Table (Real).Num /= 0;
  882.    end UR_Is_Positive;
  883.  
  884.    ----------------
  885.    -- UR_Is_Zero --
  886.    ----------------
  887.  
  888.    function UR_Is_Zero (Real : Ureal) return Boolean is
  889.    begin
  890.       return Ureals.Table (Real).Num = 0;
  891.    end UR_Is_Zero;
  892.  
  893.    -----------
  894.    -- UR_Le --
  895.    -----------
  896.  
  897.    function UR_Le (Left, Right : Ureal) return Boolean is
  898.    begin
  899.       return not (Right < Left);
  900.    end UR_Le;
  901.  
  902.    -----------
  903.    -- UR_Lt --
  904.    -----------
  905.  
  906.    function UR_Lt (Left, Right : Ureal) return Boolean is
  907.    begin
  908.       --  An operand is not less than itself
  909.  
  910.       if Same (Left, Right) then
  911.          return False;
  912.  
  913.       --  Deal with zero cases
  914.  
  915.       elsif UR_Is_Zero (Left) then
  916.          return UR_Is_Positive (Right);
  917.  
  918.       elsif UR_Is_Zero (Right) then
  919.          return Ureals.Table (Left).Negative;
  920.  
  921.       --  Different signs are decisive (note we dealt with zero cases)
  922.  
  923.       elsif Ureals.Table (Left).Negative
  924.         and then not Ureals.Table (Right).Negative
  925.       then
  926.          return True;
  927.  
  928.       elsif not Ureals.Table (Left).Negative
  929.         and then Ureals.Table (Right).Negative
  930.       then
  931.          return False;
  932.  
  933.       --  Signs are same, do rapid check based on worst case estimates of
  934.       --  decimal exponent, which will often be decisive. Precise test
  935.       --  depends on whether operands are positive or negative.
  936.  
  937.       elsif Decimal_Exponent_Hi (Left) < Decimal_Exponent_Lo (Right) then
  938.          return UR_Is_Positive (Left);
  939.  
  940.       elsif Decimal_Exponent_Lo (Left) > Decimal_Exponent_Hi (Right) then
  941.          return UR_Is_Negative (Left);
  942.  
  943.       --  If we fall through, full gruesome test is required. This happens
  944.       --  if the numbers are close together, or in some wierd (/=10) base.
  945.  
  946.       else
  947.          declare
  948.             Imrk   : constant Uintp.Save_Mark  := Mark;
  949.             Rmrk   : constant Urealp.Save_Mark := Mark;
  950.             Lval   : Ureal_Entry;
  951.             Rval   : Ureal_Entry;
  952.             Result : Boolean;
  953.  
  954.          begin
  955.             Lval := Ureals.Table (Left);
  956.             Rval := Ureals.Table (Right);
  957.  
  958.             --  An optimization. If both numbers are based, then subtract
  959.             --  common value of base to avoid unnecessarily giant numbers
  960.  
  961.             if Lval.Rbase = Rval.Rbase and then Lval.Rbase /= 0 then
  962.                if Lval.Den < Rval.Den then
  963.                   Rval.Den := Rval.Den - Lval.Den;
  964.                   Lval.Den := Uint_0;
  965.                else
  966.                   Lval.Den := Lval.Den - Rval.Den;
  967.                   Rval.Den := Uint_0;
  968.                end if;
  969.             end if;
  970.  
  971.             Lval := Normalize (Lval);
  972.             Rval := Normalize (Rval);
  973.  
  974.             if Lval.Negative then
  975.                Result := (Lval.Num * Rval.Den) > (Rval.Num * Lval.Den);
  976.             else
  977.                Result := (Lval.Num * Rval.Den) < (Rval.Num * Lval.Den);
  978.             end if;
  979.  
  980.             Release (Imrk);
  981.             Release (Rmrk);
  982.             return Result;
  983.          end;
  984.       end if;
  985.    end UR_Lt;
  986.  
  987.    ------------
  988.    -- UR_Max --
  989.    ------------
  990.  
  991.    function UR_Max (Left, Right : Ureal) return Ureal is
  992.    begin
  993.       if Left >= Right then
  994.          return Left;
  995.       else
  996.          return Right;
  997.       end if;
  998.    end UR_Max;
  999.  
  1000.    ------------
  1001.    -- UR_Min --
  1002.    ------------
  1003.  
  1004.    function UR_Min (Left, Right : Ureal) return Ureal is
  1005.    begin
  1006.       if Left <= Right then
  1007.          return Left;
  1008.       else
  1009.          return Right;
  1010.       end if;
  1011.    end UR_Min;
  1012.  
  1013.    ------------
  1014.    -- UR_Mul --
  1015.    ------------
  1016.  
  1017.    function UR_Mul (Left : Uint; Right : Ureal) return Ureal is
  1018.    begin
  1019.       return UR_From_Uint (Left) * Right;
  1020.    end UR_Mul;
  1021.  
  1022.    function UR_Mul (Left : Ureal; Right : Uint) return Ureal is
  1023.    begin
  1024.       return Left * UR_From_Uint (Right);
  1025.    end UR_Mul;
  1026.  
  1027.    function UR_Mul (Left, Right : Ureal) return Ureal is
  1028.       Lval : constant Ureal_Entry := Ureals.Table (Left);
  1029.       Rval : constant Ureal_Entry := Ureals.Table (Right);
  1030.       Num  : Uint                 := Lval.Num * Rval.Num;
  1031.       Den  : Uint;
  1032.       Rneg : constant Boolean     := Lval.Negative xor Rval.Negative;
  1033.  
  1034.    begin
  1035.       if Lval.Rbase = 0 then
  1036.          if Rval.Rbase = 0 then
  1037.             return Store_Ureal (
  1038.                      Normalize (
  1039.                         (Num      => Num,
  1040.                          Den      => Lval.Den * Rval.Den,
  1041.                          Rbase    => 0,
  1042.                          Negative => Rneg)));
  1043.  
  1044.          elsif Is_Integer (Num, Lval.Den) then
  1045.             return Store_Ureal (
  1046.                      (Num      => Num / Lval.Den,
  1047.                       Den      => Rval.Den,
  1048.                       Rbase    => Rval.Rbase,
  1049.                       Negative => Rneg));
  1050.  
  1051.          elsif Rval.Den < 0 then
  1052.             return Store_Ureal (
  1053.                      Normalize (
  1054.                        (Num      => Num * (Rval.Rbase ** (-Rval.Den)),
  1055.                         Den      => Lval.Den,
  1056.                         Rbase    => 0,
  1057.                         Negative => Rneg)));
  1058.  
  1059.          else
  1060.             return Store_Ureal (
  1061.                      Normalize (
  1062.                        (Num      => Num,
  1063.                         Den      => Lval.Den * (Rval.Rbase ** Rval.Den),
  1064.                         Rbase    => 0,
  1065.                         Negative => Rneg)));
  1066.          end if;
  1067.  
  1068.       elsif Lval.Rbase = Rval.Rbase then
  1069.          return Store_Ureal (
  1070.                   (Num      => Num,
  1071.                    Den      => Lval.Den + Rval.Den,
  1072.                    Rbase    => Lval.Rbase,
  1073.                    Negative => Rneg));
  1074.  
  1075.       elsif Rval.Rbase = 0 then
  1076.          if Is_Integer (Num, Rval.Den) then
  1077.             return Store_Ureal (
  1078.                      (Num      => Num / Rval.Den,
  1079.                       Den      => Lval.Den,
  1080.                       Rbase    => Lval.Rbase,
  1081.                       Negative => Rneg));
  1082.  
  1083.  
  1084.          elsif Lval.Den < 0 then
  1085.             return Store_Ureal (
  1086.                      Normalize (
  1087.                        (Num      => Num * (Lval.Rbase ** (-Lval.Den)),
  1088.                         Den      => Rval.Den,
  1089.                         Rbase    => 0,
  1090.                         Negative => Rneg)));
  1091.  
  1092.          else
  1093.             return Store_Ureal (
  1094.                      Normalize (
  1095.                        (Num      => Num,
  1096.                         Den      => Rval.Den * (Lval.Rbase ** Lval.Den),
  1097.                         Rbase    => 0,
  1098.                         Negative => Rneg)));
  1099.          end if;
  1100.  
  1101.       else
  1102.          Den := Uint_1;
  1103.  
  1104.          if Lval.Den < 0 then
  1105.             Num := Num * (Lval.Rbase ** (-Lval.Den));
  1106.          else
  1107.             Den := Den * (Lval.Rbase ** Lval.Den);
  1108.          end if;
  1109.  
  1110.          if Rval.Den < 0 then
  1111.             Num := Num * (Rval.Rbase ** (-Rval.Den));
  1112.          else
  1113.             Den := Den * (Rval.Rbase ** Rval.Den);
  1114.          end if;
  1115.  
  1116.          return Store_Ureal (
  1117.                   Normalize (
  1118.                     (Num      => Num,
  1119.                      Den      => Den,
  1120.                      Rbase    => 0,
  1121.                      Negative => Rneg)));
  1122.       end if;
  1123.  
  1124.    end UR_Mul;
  1125.  
  1126.    -----------
  1127.    -- UR_Ne --
  1128.    -----------
  1129.  
  1130.    function UR_Ne (Left, Right : Ureal) return Boolean is
  1131.    begin
  1132.       --  Quick processing for case of identical Ureal values (note that
  1133.       --  this also deals with comparing two No_Ureal values).
  1134.  
  1135.       if Same (Left, Right) then
  1136.          return False;
  1137.  
  1138.       --  Deal with case of one or other operand is No_Ureal, but not both
  1139.  
  1140.       elsif Same (Left, No_Ureal) or else Same (Right, No_Ureal) then
  1141.          return True;
  1142.  
  1143.       --  Do quick check based on number of decimal digits
  1144.  
  1145.       elsif Decimal_Exponent_Hi (Left) < Decimal_Exponent_Lo (Right) or else
  1146.             Decimal_Exponent_Lo (Left) > Decimal_Exponent_Hi (Right)
  1147.       then
  1148.          return True;
  1149.  
  1150.       --  Otherwise full comparison is required
  1151.  
  1152.       else
  1153.          declare
  1154.             Imrk   : constant Uintp.Save_Mark  := Mark;
  1155.             Rmrk   : constant Urealp.Save_Mark := Mark;
  1156.             Lval   : constant Ureal_Entry := Normalize (Ureals.Table (Left));
  1157.             Rval   : constant Ureal_Entry := Normalize (Ureals.Table (Right));
  1158.             Result : Boolean;
  1159.  
  1160.          begin
  1161.             if UR_Is_Zero (Left) then
  1162.                return not UR_Is_Zero (Right);
  1163.  
  1164.             elsif UR_Is_Zero (Right) then
  1165.                return not UR_Is_Zero (Left);
  1166.  
  1167.             --  Both operands are non-zero
  1168.  
  1169.             else
  1170.                Result :=
  1171.                   Rval.Negative /= Lval.Negative
  1172.                    or else Rval.Num /= Lval.Num
  1173.                    or else Rval.Den /= Lval.Den;
  1174.                Release (Imrk);
  1175.                Release (Rmrk);
  1176.                return Result;
  1177.             end if;
  1178.          end;
  1179.       end if;
  1180.    end UR_Ne;
  1181.  
  1182.    ---------------
  1183.    -- UR_Negate --
  1184.    ---------------
  1185.  
  1186.    function UR_Negate (Real : Ureal) return Ureal is
  1187.    begin
  1188.       return Store_Ureal (
  1189.                (Num      => Ureals.Table (Real).Num,
  1190.                 Den      => Ureals.Table (Real).Den,
  1191.                 Rbase    => Ureals.Table (Real).Rbase,
  1192.                 Negative => not Ureals.Table (Real).Negative));
  1193.    end UR_Negate;
  1194.  
  1195.    ------------
  1196.    -- UR_Sub --
  1197.    ------------
  1198.  
  1199.    function UR_Sub (Left : Uint; Right : Ureal) return Ureal is
  1200.    begin
  1201.       return UR_From_Uint (Left) + UR_Negate (Right);
  1202.    end UR_Sub;
  1203.  
  1204.    function UR_Sub (Left : Ureal; Right : Uint) return Ureal is
  1205.    begin
  1206.       return Left + UR_From_Uint (-Right);
  1207.    end UR_Sub;
  1208.  
  1209.    function UR_Sub (Left, Right : Ureal) return Ureal is
  1210.    begin
  1211.       return Left + UR_Negate (Right);
  1212.    end UR_Sub;
  1213.  
  1214.    ----------------
  1215.    -- UR_To_Uint --
  1216.    ----------------
  1217.  
  1218.    function UR_To_Uint (Real : Ureal) return Uint is
  1219.       Val : Ureal_Entry := Normalize (Ureals.Table (Real));
  1220.       Res : Uint;
  1221.  
  1222.    begin
  1223.       Res := (Val.Num + (Val.Den / 2)) / Val.Den;
  1224.  
  1225.       if Val.Negative then
  1226.          return UI_Negate (Res);
  1227.       else
  1228.          return Res;
  1229.       end if;
  1230.    end UR_To_Uint;
  1231.  
  1232.    --------------
  1233.    -- UR_Trunc --
  1234.    --------------
  1235.  
  1236.    function UR_Trunc (Real : Ureal) return Uint is
  1237.       Val : constant Ureal_Entry := Normalize (Ureals.Table (Real));
  1238.  
  1239.    begin
  1240.       return Val.Num / Val.Den;
  1241.    end UR_Trunc;
  1242.  
  1243.    --------------
  1244.    -- UR_Write --
  1245.    --------------
  1246.  
  1247.    procedure UR_Write (Real : Ureal) is
  1248.       Val : constant Ureal_Entry := Ureals.Table (Real);
  1249.  
  1250.    begin
  1251.       --  If value is negative, we precede the constant by a minus sign
  1252.       --  and add an extra layer of parentheses on the outside since the
  1253.       --  minus sign is part of the value, not a negation operator.
  1254.  
  1255.       if Val.Negative then
  1256.          Write_Str ("(-");
  1257.       end if;
  1258.  
  1259.       --  Constants in base 10 can be written in normal Ada literal style
  1260.       --  If the literal is negative enclose in parens to emphasize that
  1261.       --  it is part of the constant, and not a separate negation operator
  1262.  
  1263.       if Val.Rbase = 10 then
  1264.  
  1265.          UI_Write (Val.Num / 10);
  1266.          Write_Char ('.');
  1267.          UI_Write (Val.Num mod 10);
  1268.  
  1269.          if Val.Den /= 0 then
  1270.             Write_Char ('E');
  1271.             UI_Write (1 - Val.Den);
  1272.          end if;
  1273.  
  1274.       --  Constants in a base other than 10 can still be easily written
  1275.       --  in normal Ada literal style if the numerator is one.
  1276.  
  1277.       elsif Val.Rbase /= 0 and then Val.Num = 1 then
  1278.          Write_Int (Val.Rbase);
  1279.          Write_Str ("#1.0#E");
  1280.          UI_Write (-Val.Den);
  1281.  
  1282.       --  Other constants with a base other than 10 are written using one
  1283.       --  of the following forms, depending on the sign of the number
  1284.       --  and the sign of the exponent (= minus denominator value)
  1285.  
  1286.       --    (numerator.0*base**exponent)
  1287.       --    (numerator.0*base**(-exponent))
  1288.  
  1289.       elsif Val.Rbase /= 0 then
  1290.          Write_Char ('(');
  1291.          UI_Write (Val.Num);
  1292.          Write_Str (".0*");
  1293.          Write_Int (Val.Rbase);
  1294.          Write_Str ("**");
  1295.  
  1296.          if Val.Den <= 0 then
  1297.             UI_Write (-Val.Den);
  1298.  
  1299.          else
  1300.             Write_Str ("(-");
  1301.             UI_Write (Val.Den);
  1302.             Write_Char (')');
  1303.          end if;
  1304.  
  1305.          Write_Char (')');
  1306.  
  1307.       --  Rational constants with a denominator of 1 can be written as
  1308.       --  a real literal for the numerator integer.
  1309.  
  1310.       elsif Val.Den = 1 then
  1311.          UI_Write (Val.Num);
  1312.          Write_Str (".0");
  1313.  
  1314.       --  Non-based (rational) constants are written in (num/den) style
  1315.  
  1316.       else
  1317.          Write_Char ('(');
  1318.          UI_Write (Val.Num);
  1319.          Write_Str (".0/");
  1320.          UI_Write (Val.Den);
  1321.          Write_Str (".0)");
  1322.       end if;
  1323.  
  1324.       --  Add trailing paren for negative values
  1325.  
  1326.       if Val.Negative then
  1327.          Write_Char (')');
  1328.       end if;
  1329.  
  1330.    end UR_Write;
  1331.  
  1332. end Urealp;
  1333.