Revision history [back]

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...