Ticket #12068: trac_12068-numer_denom_normal-ginac-fh.patch

File trac_12068-numer_denom_normal-ginac-fh.patch, 21.8 KB (added by hivert, 10 years ago)
  • sage/libs/ginac/decl.pxi

    # HG changeset patch
    # User Florent Hivert <Florent.Hivert@univ-rouen.fr>
    # Date 1322149917 -3600
    # Node ID 9d22a98f68c4e9865fb76582ce60875aaa0d471e
    # Parent  31d27bf810893643dc277fbe7f926c8645a832f2
    #12068: Numerator for symbolic expression should'nt use maxima
    trac 12068: denominator() for symbolic expressions recognizes more cases
    Wraps GiNaC ex.normal method and fixes a few doc typeset mistakes.
    
    diff --git a/sage/libs/ginac/decl.pxi b/sage/libs/ginac/decl.pxi
    a b cdef extern from "ginac_wrap.h": 
    3636
    3737    object GSymbol_to_str "_to_PyString<symbol>"(GSymbol *s)
    3838
    39     ctypedef struct GExPair "std::pair<ex, ex>"
     39    ctypedef struct GExPair "std::pair<ex, ex>":
     40        pass
    4041    ctypedef struct GExMap "exmap":
    4142        void insert(GExPair e)
    4243
    cdef extern from "ginac_wrap.h": 
    6970        GEx subs_map "subs" (GExMap map) except +
    7071        GEx coeff(GEx expr, int n)    except +
    7172        GEx lcoeff(GEx expr)          except +
    72         GEx tcoeff(GEx expr)          except +       
     73        GEx tcoeff(GEx expr)          except +
     74        GEx normal()                  except +
     75        GEx numer()                   except +
     76        GEx denom()                   except +
     77        GEx numer_denom()             except +
    7378        int degree(GEx expr)          except +
    7479        int ldegree(GEx expr)         except +
    7580        GEx rhs()                     except +
    cdef extern from "ginac_wrap.h": 
    8590
    8691    GExPair make_pair "std::make_pair" (GEx, GEx)
    8792
     93    ctypedef struct GNumeric "numeric":
     94        bint is_positive() except +
     95        bint is_negative() except +
     96
    8897    # Numericals
    8998    bint is_a_numeric "is_a<numeric>" (GEx e)
     99    GNumeric ex_to_numeric "ex_to<numeric>" (GEx e)
    90100    # given a GEx that is known to be a numeric, return reference to
    91101    # the underlying PyObject*.
    92102    object py_object_from_numeric(GEx e)     except +
    cdef extern from "ginac_wrap.h": 
    143153    unsigned info_nonnegint     "GiNaC::info_flags::nonnegint"
    144154    unsigned info_even          "GiNaC::info_flags::even"
    145155    unsigned info_odd           "GiNaC::info_flags::odd"
     156    unsigned info_rational_function "GiNaC::info_flags::rational_function"
    146157
    147158    # Constants
    148159    GEx g_Pi "Pi"
    cdef extern from "ginac_wrap.h": 
    216227    bint is_a_function "is_a<function>" (GEx e)
    217228    bint is_a_ncmul "is_a<ncmul>" (GEx e)
    218229
    219 
    220230    # Arithmetic
    221231    int ginac_error()
    222232    GEx gadd "ADD_WRAP" (GEx left, GEx right) except +
  • sage/symbolic/expression.pyx

    diff --git a/sage/symbolic/expression.pyx b/sage/symbolic/expression.pyx
    a b cdef class Expression(CommutativeRingEle 
    482482            sage: f = pi + I*e
    483483            sage: f._pari_init_()
    484484            '(Pi)+((exp(1))*(I))'
    485         """       
     485        """
    486486        from sage.symbolic.expression_conversions import InterfaceInit
    487487        return InterfaceInit(I)(self)
    488488       
    cdef class Expression(CommutativeRingEle 
    18611861        """
    18621862        Test this relation at several random values, attempting to find
    18631863        a contradiction. If this relation has no variables, it will also
    1864         test this relation after casting into the domain. 
    1865 
    1866         Because the interval fields never return false positives, we can be 
    1867         assured that if True or False is returned (and proof is False) then 
    1868         the answer is correct. 
    1869 
    1870         INPUT::
    1871        
    1872            ntests -- (default 20) the number of iterations to run
    1873            domain -- (optional) the domain from which to draw the random values
    1874                      defaults to CIF for equality testing and RIF for
    1875                      order testing
    1876            proof --  (default True) if False and the domain is an interval field,
    1877                      regard overlapping (potentially equal) intervals as equal,
    1878                      and return True if all tests succeeded.
     1864        test this relation after casting into the domain.
     1865
     1866        Because the interval fields never return false positives, we can be
     1867        assured that if True or False is returned (and proof is False) then
     1868        the answer is correct.
     1869
     1870        INPUT:
     1871
     1872        - ``ntests`` -- (default ``20``) the number of iterations to run
     1873        - ``domain`` -- (optional) the domain from which to draw the random
     1874          values defaults to ``CIF`` for equality testing and ``RIF`` for
     1875          order testing
     1876        - ``proof`` -- (default ``True``) if ``False`` and the domain is an
     1877          interval field, regard overlapping (potentially equal) intervals as
     1878          equal, and return ``True`` if all tests succeeded.
    18791879
    18801880        OUTPUT:
    18811881
    cdef class Expression(CommutativeRingEle 
    30503050            sage: a.expand('right')
    30513051            (16*x - 13)^2 == 9/2*x^2 + 15*x + 25/2
    30523052
    3053         TESTS:
    3054        
     3053        TESTS::
     3054
    30553055            sage: var('x,y')
    30563056            (x, y)
    30573057            sage: ((x + (2/3)*y)^3).expand()
    cdef class Expression(CommutativeRingEle 
    38003800        Returns the topmost operator in this expression.
    38013801
    38023802        EXAMPLES::
    3803        
     3803
    38043804            sage: x,y,z = var('x,y,z')
    38053805            sage: (x+y).operator()
    38063806            <built-in function add>
    cdef class Expression(CommutativeRingEle 
    38343834            D[0](f)(x)
    38353835            sage: a.operator()
    38363836            D[0](f)
    3837            
    3838         TESTS:
     3837
     3838        TESTS::
     3839
    38393840            sage: (x <= y).operator()
    38403841            <built-in function le>
    38413842            sage: (x == y).operator()
    cdef class Expression(CommutativeRingEle 
    45144515       
    45154516        .. warning::
    45164517
    4517            This is different from meth:`poly` which is used to rewrite
     4518           This is different from :meth:`poly` which is used to rewrite
    45184519           self as a polynomial in terms of one of the variables.
    45194520       
    45204521        INPUT:
    cdef class Expression(CommutativeRingEle 
    51545155
    51555156    def sqrt(self, hold=False):
    51565157        """
    5157         EXAMPLES:
     5158        Return the square root of this expression
     5159
     5160        EXAMPLES::
     5161
    51585162            sage: var('x, y')
    51595163            (x, y)
    51605164            sage: SR(2).sqrt()
    cdef class Expression(CommutativeRingEle 
    61156119        finally:
    61166120            sig_off()
    61176121        return new_Expression_from_GEx(self._parent, x)
    6118    
     6122
    61196123    def factorial(self, hold=False):
    61206124        """
    61216125        Return the factorial of self.
    6122        
     6126
    61236127        OUTPUT:
    61246128
    61256129        A symbolic expression.
    6126        
    6127         EXAMPLES:
     6130
     6131        EXAMPLES::
     6132
    61286133            sage: var('x, y')
    61296134            (x, y)
    61306135            sage: SR(5).factorial()
    cdef class Expression(CommutativeRingEle 
    61516156
    61526157            sage: a = SR(5).factorial(hold=True); a.simplify()
    61536158            120
    6154 
    61556159        """
    61566160        cdef GEx x
    61576161        try:
    cdef class Expression(CommutativeRingEle 
    61646168    def binomial(self, k, hold=False):
    61656169        """
    61666170        Return binomial coefficient "self choose k".
    6167        
     6171
    61686172        OUTPUT:
    61696173
    61706174        A symbolic expression.
    6171        
    6172         EXAMPLES:
     6175
     6176        EXAMPLES::
     6177
    61736178            sage: var('x, y')
    61746179            (x, y)
    61756180            sage: SR(5).binomial(SR(3))
    cdef class Expression(CommutativeRingEle 
    62036208        TESTS:
    62046209
    62056210        Check if we handle zero correctly (#8561)::
     6211
    62066212            sage: x.binomial(0)
    62076213            1
    62086214            sage: SR(0).binomial(0)
    cdef class Expression(CommutativeRingEle 
    63586364            Traceback (most recent call last):
    63596365            ...
    63606366            TypeError: log_gamma() got an unexpected keyword argument 'hold'
    6361 
    63626367        """
    63636368        cdef GEx x
    63646369        try:
    cdef class Expression(CommutativeRingEle 
    64156420            ((x - 1)*x + y^2)/(x^2 - 7) + (b + c)/a + 1/(x + 1)
    64166421        """
    64176422        return self.parent()(self._maxima_().combine())
    6418    
    6419     def numerator(self):
    6420         """
    6421         Returns the numerator of this symbolic expression.  If the
    6422         expression is not a quotient, then this will return the
    6423         expression itself.
    6424        
    6425         EXAMPLES::
    6426        
     6423
     6424    def normalize(self):
     6425        """
     6426        Return this expression normalized as a fraction
     6427
     6428        .. SEEALSO:
     6429
     6430            :meth:`numerator`, :meth:`denominator`,
     6431            :meth:`numerator_denominator`, :meth:`combine`
     6432
     6433        EXAMPLES::
     6434
     6435            sage: var('x, y, a, b, c')
     6436            (x, y, a, b, c)
     6437            sage: g = x + y/(x + 2)
     6438            sage: g.normalize()
     6439            (x^2 + 2*x + y)/(x + 2)
     6440
     6441            sage: f = x*(x-1)/(x^2 - 7) + y^2/(x^2-7) + 1/(x+1) + b/a + c/a
     6442            sage: f.normalize()
     6443            (a*x^3 + a*x*y^2 + b*x^3 + c*x^3 + a*x^2 + a*y^2 + b*x^2 + c*x^2 - a*x - 7*b*x - 7*c*x - 7*a - 7*b - 7*c)/((x + 1)*(x^2 - 7)*a)
     6444
     6445        ALGORITHM: Uses GiNaC.
     6446
     6447        """
     6448        return new_Expression_from_GEx(self._parent, self._gobj.normal())
     6449
     6450    def numerator(self, bint normalize = True):
     6451        """
     6452        Returns the numerator of this symbolic expression
     6453
     6454        INPUT:
     6455
     6456        - ``normalize`` -- (default: ``True``) a boolean.
     6457
     6458        If ``normalize`` is ``True``, the expression is first normalized to
     6459        have it as a fraction before getting the numerator.
     6460
     6461        If ``normalize`` is ``False``, the expression is kept and if it is not
     6462        a quotient, then this will return the expression itself.
     6463
     6464        .. SEEALSO::
     6465
     6466            :meth:`normalize`, :meth:`denominator`,
     6467            :meth:`numerator_denominator`, :meth:`combine`
     6468
     6469        EXAMPLES::
     6470
    64276471            sage: a, x, y = var('a,x,y')
    64286472            sage: f = x*(x-a)/((x^2 - y)*(x-a)); f
    64296473            x/(x^2 - y)
    cdef class Expression(CommutativeRingEle 
    64316475            x
    64326476            sage: f.denominator()
    64336477            x^2 - y
     6478            sage: f.numerator(normalize=False)
     6479            x
     6480            sage: f.denominator(normalize=False)
     6481            x^2 - y
    64346482
    64356483            sage: y = var('y')
    64366484            sage: g = x + y/(x + 2); g
    64376485            x + y/(x + 2)
    64386486            sage: g.numerator()
     6487            x^2 + 2*x + y
     6488            sage: g.denominator()
     6489            x + 2
     6490            sage: g.numerator(normalize=False)
    64396491            x + y/(x + 2)
    6440             sage: g.denominator()
     6492            sage: g.denominator(normalize=False)
    64416493            1
    64426494
    6443         """
    6444         return self.parent()(self._maxima_().num())
    6445 
    6446     def denominator(self):
    6447         """
    6448         Returns the denominator of this symbolic expression.  If the
    6449         expression is not a quotient, then this will just return 1.
    6450        
    6451         EXAMPLES::
    6452        
     6495        TESTS::
     6496
     6497            sage: ((x+y)^2/(x-y)^3*x^3).numerator(normalize=False)
     6498            (x + y)^2*x^3
     6499            sage: ((x+y)^2*x^3).numerator(normalize=False)
     6500            (x + y)^2*x^3
     6501            sage: (y/x^3).numerator(normalize=False)
     6502            y
     6503            sage: t = y/x^3/(x+y)^(1/2); t
     6504            y/(sqrt(x + y)*x^3)
     6505            sage: t.numerator(normalize=False)
     6506            y
     6507            sage: (1/x^3).numerator(normalize=False)
     6508            1
     6509            sage: (x^3).numerator(normalize=False)
     6510            x^3
     6511            sage: (y*x^sin(x)).numerator(normalize=False)
     6512            Traceback (most recent call last):
     6513            ...
     6514            TypeError: self is not a rational expression
     6515        """
     6516        cdef GExVector vec
     6517        cdef GEx oper, power
     6518        if normalize:
     6519            return new_Expression_from_GEx(self._parent, self._gobj.numer())
     6520        elif is_a_mul(self._gobj):
     6521            for i from 0 <= i < self._gobj.nops():
     6522                oper = self._gobj.op(i)
     6523                if not is_a_power(oper):
     6524                    vec.push_back(oper)
     6525                else:
     6526                    power = oper.op(1)
     6527                    if not is_a_numeric(power):
     6528                        raise TypeError, "self is not a rational expression"
     6529                    elif ex_to_numeric(power).is_positive():
     6530                        vec.push_back(oper)
     6531            return new_Expression_from_GEx(self._parent,
     6532                                           g_mul_construct(vec, True))
     6533        elif is_a_power(self._gobj):
     6534            power = self._gobj.op(1)
     6535            if is_a_numeric(power) and ex_to_numeric(power).is_negative():
     6536                return self._parent.one()
     6537        return self
     6538
     6539    def denominator(self, bint normalize=True):
     6540        """
     6541        Returns the denominator of this symbolic expression
     6542
     6543        INPUT:
     6544
     6545        - ``normalize`` -- (default: ``True``) a boolean.
     6546
     6547        If ``normalize`` is ``True``, the expression is first normalized to
     6548        have it as a fraction before getting the denominator.
     6549
     6550        If ``normalize`` is ``False``, the expression is kept and if it is not
     6551        a quotient, then this will just return 1.
     6552
     6553        .. SEEALSO::
     6554
     6555            :meth:`normalize`, :meth:`numerator`,
     6556            :meth:`numerator_denominator`, :meth:`combine`
     6557
     6558        EXAMPLES::
     6559
    64536560            sage: x, y, z, theta = var('x, y, z, theta')
    64546561            sage: f = (sqrt(x) + sqrt(y) + sqrt(z))/(x^10 - y^10 - sqrt(theta))
     6562            sage: f.numerator()
     6563            sqrt(x) + sqrt(y) + sqrt(z)
    64556564            sage: f.denominator()
     6565            -sqrt(theta) + x^10 - y^10
     6566
     6567            sage: f.numerator(normalize=False)
     6568            -(sqrt(x) + sqrt(y) + sqrt(z))
     6569            sage: f.denominator(normalize=False)
    64566570            sqrt(theta) - x^10 + y^10
    64576571
    64586572            sage: y = var('y')
    64596573            sage: g = x + y/(x + 2); g
    64606574            x + y/(x + 2)
    6461             sage: g.numerator()
     6575            sage: g.numerator(normalize=False)
    64626576            x + y/(x + 2)
    6463             sage: g.denominator()
     6577            sage: g.denominator(normalize=False)
    64646578            1
    6465         """
    6466         return self.parent()(self._maxima_().denom())
     6579
     6580        TESTS::
     6581
     6582            sage: ((x+y)^2/(x-y)^3*x^3).denominator(normalize=False)
     6583            (x - y)^3
     6584            sage: ((x+y)^2*x^3).denominator(normalize=False)
     6585            1
     6586            sage: (y/x^3).denominator(normalize=False)
     6587            x^3
     6588            sage: t = y/x^3/(x+y)^(1/2); t
     6589            y/(sqrt(x + y)*x^3)
     6590            sage: t.denominator(normalize=False)
     6591            sqrt(x + y)*x^3
     6592            sage: (1/x^3).denominator(normalize=False)
     6593            x^3
     6594            sage: (x^3).denominator(normalize=False)
     6595            1
     6596            sage: (y*x^sin(x)).denominator(normalize=False)
     6597            Traceback (most recent call last):
     6598            ...
     6599            TypeError: self is not a rational expression
     6600        """
     6601        cdef GExVector vec
     6602        cdef GEx oper, ex, power
     6603        if normalize:
     6604            return new_Expression_from_GEx(self._parent, self._gobj.denom())
     6605        elif is_a_mul(self._gobj):
     6606            for i from 0 <= i < self._gobj.nops():
     6607                oper = self._gobj.op(i)
     6608                if is_a_power(oper):
     6609                    ex = oper.op(0)
     6610                    power = oper.op(1)
     6611                    if not is_a_numeric(power):
     6612                        raise TypeError, "self is not a rational expression"
     6613                    elif ex_to_numeric(power).is_negative():
     6614                        vec.push_back(g_pow(ex, g_abs(power)))
     6615            return new_Expression_from_GEx(self._parent,
     6616                                           g_mul_construct(vec, False))
     6617        elif is_a_power(self._gobj):
     6618            power = self._gobj.op(1)
     6619            if is_a_numeric(power) and ex_to_numeric(power).is_negative():
     6620                return new_Expression_from_GEx(self._parent,
     6621                        g_pow(self._gobj.op(0), g_abs(power)))
     6622
     6623        return self._parent.one()
     6624
     6625    def numerator_denominator(self, bint normalize=True):
     6626        """
     6627        Returns the numerator and the denominator of this symbolic expression
     6628
     6629        INPUT:
     6630
     6631        - ``normalize`` -- (default: ``True``) a boolean.
     6632
     6633        If ``normalize`` is ``True``, the expression is first normalized to
     6634        have it as a fraction before getting the numerator and denominator.
     6635
     6636        If ``normalize`` is ``False``, the expression is kept and if it is not
     6637        a quotient, then this will return the expression itself together with
     6638        1.
     6639
     6640        .. SEEALSO::
     6641
     6642            :meth:`normalize`, :meth:`numerator`, :meth:`denominator`,
     6643            :meth:`combine`
     6644
     6645        EXAMPLE::
     6646
     6647            sage: x, y, a = var("x y a")
     6648            sage: ((x+y)^2/(x-y)^3*x^3).numerator_denominator()
     6649            ((x + y)^2*x^3, (x - y)^3)
     6650
     6651            sage: ((x+y)^2/(x-y)^3*x^3).numerator_denominator(False)
     6652            ((x + y)^2*x^3, (x - y)^3)
     6653
     6654            sage: g = x + y/(x + 2)
     6655            sage: g.numerator_denominator()
     6656            (x^2 + 2*x + y, x + 2)
     6657            sage: g.numerator_denominator(normalize=False)
     6658            (x + y/(x + 2), 1)
     6659
     6660            sage: g = x^2*(x + 2)
     6661            sage: g.numerator_denominator()
     6662            ((x + 2)*x^2, 1)
     6663            sage: g.numerator_denominator(normalize=False)
     6664            ((x + 2)*x^2, 1)
     6665
     6666        TESTS::
     6667
     6668            sage: ((x+y)^2/(x-y)^3*x^3).numerator_denominator(normalize=False)
     6669            ((x + y)^2*x^3, (x - y)^3)
     6670            sage: ((x+y)^2*x^3).numerator_denominator(normalize=False)
     6671            ((x + y)^2*x^3, 1)
     6672            sage: (y/x^3).numerator_denominator(normalize=False)
     6673            (y, x^3)
     6674            sage: t = y/x^3/(x+y)^(1/2); t
     6675            y/(sqrt(x + y)*x^3)
     6676            sage: t.numerator_denominator(normalize=False)
     6677            (y, sqrt(x + y)*x^3)
     6678            sage: (1/x^3).numerator_denominator(normalize=False)
     6679            (1, x^3)
     6680            sage: (x^3).numerator_denominator(normalize=False)
     6681            (x^3, 1)
     6682            sage: (y*x^sin(x)).numerator_denominator(normalize=False)
     6683            Traceback (most recent call last):
     6684            ...
     6685            TypeError: self is not a rational expression
     6686        """
     6687        cdef GExVector vecnumer, vecdenom
     6688        cdef GEx oper, ex, power
     6689        cdef GNumeric power_num
     6690        if normalize:
     6691            ex = self._gobj.numer_denom()
     6692            return (new_Expression_from_GEx(self._parent, ex.op(0)),
     6693                    new_Expression_from_GEx(self._parent, ex.op(1)))
     6694        elif is_a_mul(self._gobj):
     6695            for i from 0 <= i < self._gobj.nops():
     6696                oper = self._gobj.op(i)
     6697                if is_a_power(oper):   # oper = ex^power
     6698                    ex = oper.op(0)
     6699                    power = oper.op(1)
     6700                    if not is_a_numeric(power):
     6701                        raise TypeError, "self is not a rational expression"
     6702                    elif is_a_numeric(power):
     6703                        power_num = ex_to_numeric(power)
     6704                        if power_num.is_positive():
     6705                            vecnumer.push_back(oper)
     6706                        else:
     6707                            vecdenom.push_back(g_pow(ex, g_abs(power)))
     6708                else:
     6709                    vecnumer.push_back(oper)
     6710            return (new_Expression_from_GEx(self._parent,
     6711                                            g_mul_construct(vecnumer, False)),
     6712                    new_Expression_from_GEx(self._parent,
     6713                                            g_mul_construct(vecdenom, False)))
     6714        elif is_a_power(self._gobj):
     6715            power = self._gobj.op(1)
     6716            if is_a_numeric(power) and ex_to_numeric(power).is_positive():
     6717                return (self, self._parent.one())
     6718            else:
     6719                return (self._parent.one(),
     6720                        new_Expression_from_GEx(self._parent,
     6721                               g_pow(self._gobj.op(0), g_abs(power))))
     6722        else:
     6723            return (self, self._parent.one())
    64676724
    64686725    def partial_fraction(self, var=None):
    64696726        r"""
    cdef class Expression(CommutativeRingEle 
    68957152        Simplifies symbolic expression, which can contain logs.
    68967153
    68977154        Recursively scans the expression self, transforming
    6898         subexpressions of the form a1*log(b1) + a2*log(b2) + c into
    6899         log(b1^a1 * b2^a2) + c and simplifies inside logarithm. User
    6900         can specify, which conditions must satisfy a1 and a2 to use
     7155        subexpressions of the form `a1 \log(b1) + a2 \log(b2) + c` into
     7156        `\log( b1^{a1} b2^{a2} ) + c` and simplifies inside logarithm. User
     7157        can specify, which conditions must satisfy `a1` and `a2` to use
    69017158        this transformation in optional parameter ``algorithm``.
    69027159
    69037160        INPUT:
    6904        
     7161
    69057162        - ``self`` - expression to be simplified
    69067163
    69077164        - ``algorithm`` - (default: None) optional, governs the condition
    6908           on a1 and a2 which must be satisfied to contract expression
    6909           a1*log(b1) + a2*log(b2). Values are
    6910          
    6911           - None (use Maxima default, integers), 
    6912 
    6913           - 'one' (1 and -1), 
    6914 
    6915           - 'ratios' (integers and fractions of integers), 
    6916 
    6917           - 'constants' (constants), 
    6918 
    6919           - 'all' (all expressions). 
     7165          on `a1` and `a2` which must be satisfied to contract expression
     7166          `a1 \log(b1) + a2 \log(b2)`. Values are
     7167
     7168          - None (use Maxima default, integers),
     7169
     7170          - 'one' (1 and -1),
     7171
     7172          - 'ratios' (integers and fractions of integers),
     7173
     7174          - 'constants' (constants),
     7175
     7176          - 'all' (all expressions).
    69207177
    69217178          See also examples below.
    6922            
     7179
    69237180        DETAILS: This uses the Maxima logcontract() command. From the
    69247181        Maxima documentation: "Recursively scans the expression expr,
    69257182        transforming subexpressions of the form a1*log(b1) +
    cdef class Expression(CommutativeRingEle 
    72917548
    72927549        INPUT:
    72937550
    7294             - `self` -- the symbolic expression converting from
    7295             - `target` -- (default None) the symbolic expression converting to
     7551            - ``self`` -- the symbolic expression converting from
     7552            - ``target`` -- (default None) the symbolic expression
     7553                         converting to
    72967554
    72977555        OUTPUT:
    72987556