Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

This is rather a discussion around the answer, not an answer going to the point. (Because "7 digits as declared" is not really clear. And sometimes, why not have more, when more can be easily given?!)


Let us first see what is numerical_approx doing in detail. A first word of warning is obtained when asking for the documentation of this function. We can ask for the doc string via

sage: a = 1/14
sage: a.numerical_approx?

Bur asking for more...

sage: a.numerical_approx??

we get

def numerical_approx(self, prec=None, digits=None, algorithm=None):
    """
    Return a numerical approximation of ``self`` with ``prec`` bits
    (or decimal ``digits``) of precision.

    No guarantee is made about the accuracy of the result.

    INPUT:

    - ``prec`` -- precision in bits

    - ``digits`` -- precision in decimal digits (only used if
      ``prec`` is not given)

    - ``algorithm`` -- which algorithm to use to compute this
      approximation (the accepted algorithms depend on the object)

    If neither ``prec`` nor ``digits`` is given, the default
    precision is 53 bits (roughly 16 digits).

    EXAMPLES::

        sage: (2/3).numerical_approx()
        0.666666666666667
        sage: pi.n(digits=10)
        3.141592654
        sage: pi.n(prec=20)
        3.1416

    TESTS:

    Check that :trac:`14778` is fixed::

        sage: (0).n(algorithm='foo')
        0.000000000000000
    """
    from sage.arith.numerical_approx import numerical_approx_generic
    if prec is None:
        prec = digits_to_bits(digits)
    return numerical_approx_generic(self, prec)

So the digits argument is taken and used to see how many bits "would correspond" to this digits precision. In our case, if we convert to a binary number the result...

sage: a = 1/14
sage: an = a.numerical_approx(digits=7)
sage: print('{:.50f}'.format(float(an)))
0.07142857182770967483520507812500000000000000000000

If we use the prec option instead for some sensible values...

sage: for prec in [15..35]:
....:     print(f'a.n(prec={prec}) is {float(a.n(prec=prec)):.50f}')
a.n(prec=15) is 0.07143020629882812500000000000000000000000000000000
a.n(prec=16) is 0.07142829895019531250000000000000000000000000000000
a.n(prec=17) is 0.07142829895019531250000000000000000000000000000000
a.n(prec=18) is 0.07142877578735351562500000000000000000000000000000
a.n(prec=19) is 0.07142853736877441406250000000000000000000000000000
a.n(prec=20) is 0.07142853736877441406250000000000000000000000000000
a.n(prec=21) is 0.07142859697341918945312500000000000000000000000000
a.n(prec=22) is 0.07142856717109680175781250000000000000000000000000
a.n(prec=23) is 0.07142856717109680175781250000000000000000000000000
a.n(prec=24) is 0.07142857462167739868164062500000000000000000000000
a.n(prec=25) is 0.07142857089638710021972656250000000000000000000000
a.n(prec=26) is 0.07142857089638710021972656250000000000000000000000
a.n(prec=27) is 0.07142857182770967483520507812500000000000000000000
a.n(prec=28) is 0.07142857136204838752746582031250000000000000000000
a.n(prec=29) is 0.07142857136204838752746582031250000000000000000000
a.n(prec=30) is 0.07142857147846370935440063476562500000000000000000
a.n(prec=31) is 0.07142857142025604844093322753906250000000000000000
a.n(prec=32) is 0.07142857142025604844093322753906250000000000000000
a.n(prec=33) is 0.07142857143480796366930007934570312500000000000000
a.n(prec=34) is 0.07142857142753200605511665344238281250000000000000
a.n(prec=35) is 0.07142857142753200605511665344238281250000000000000

So a.n(digits=7) uses the precision...

sage: IR = RealField(3000)
sage: for prec in [1..50]:
....:     if IR(a.n(prec=prec)) == IR(a.n(digits=7)):
....:         print(prec)
27

Note that the print of the a.n() objects is using the str or repr functionality implemented in the corresponding class, which is:

sage: a.n(prec=300)
0.0714285714285714285714285714285714285714285714285714285714285714285714285714285714285714286
sage: type(_)
<class 'sage.rings.real_mpfr.RealNumber'>
sage: a.n(digits=7)
0.07142857
sage: type(_)
<class 'sage.rings.real_mpfr.RealNumber'>

To have "the own print", i converted above to (the class / type of) IR or to float.


Now to the question. "How to get 7 digits as declared?"

We have always "more digits" if we want to, to display $7$ and only $7$ digits in a printed message, use the corresponding print functionality. We use as intermediate most simply the float converter.

sage: print(f'{float(a):.7f}')
0.0714286
sage: print(f'{RR(a):.7f}')
0.0714286

Note that the printed value is rounded. If this is not wanted, than let us go this way...

sage: import decimal
sage: d = decimal.Decimal(float(a.n(80)))
sage: d
Decimal('0.0714285714285714246063463406244409270584583282470703125')
sage: c = decimal.getcontext().copy()
sage: c.prec = int(7)
sage: c.rounding = decimal.ROUND_DOWN
sage: d.normalize(c)
Decimal('0.07142857')
sage: d.normalize(c).as_tuple()
DecimalTuple(sign=0, digits=(7, 1, 4, 2, 8, 5, 7), exponent=-8)

Well, we get $7$ significant decimals...