1

I need to make a program that read 2 input: 1st contains a non-negative integer n, not greater than 1 billion (109), 2nd contains a non-negative integer k (the desired precision measured in fractional digits), not greater than 10 thousand (104). The program should print out a single number to the standard output. That number should be the square root of n, taken with precision of k fractional digits, always rounding down whenever some rounding is needed. (In case when k = 0 the result should be rounded down to the nearest integer).

This is my second task and I wrote the below code to calculate it using the Newton's Method.

The program can freely assume that the input will meet the above conditions

The progam works but the number of decimal positions is not correct always, to solve this, I tried to add some condition in order to increase the getcontext().prec of one unity according to the first number read. But did not solve the problem since for: - x < 10^2 : Result correct - x >= 10^2 & x < 10^4: Resul correct unitl x = 3000, then, the decimal position are incorrect of -1.

from decimal import *
from _decimal import Decimal



def sqrt(x):

    last_guess = x/2.0
    error = (1/(10**y))

    while True:
        guess = Decimal((last_guess + x/last_guess )/2)
        if abs(Decimal(guess) - Decimal(last_guess)) < error:  # example threshold
            return Decimal(guess)
        last_guess = Decimal(guess)
        print(last_guess)


x = int(input("Calculate the square root  of : "))

y = int(input("Decimal positions : "))

if x < 10**2:
    getcontext().prec = y + 1

if x >= 10**2 and x < 10**4:
    getcontext().prec = y + 2

if x >= 10**4 and x < 10**6:
    getcontext().prec = y + 3

if x >= 10**6 and x < 10**8:
    getcontext().prec = y + 4

if x >= 10**8 and x < 10**10:
    getcontext().prec = y + 5

if x >= 10**10 and x < 10**12:
    getcontext().prec = y + 6

if x >= 10**12 and x < 10**14:
    getcontext().prec = y + 7

a =sqrt(x)

if x < 10**2:
    getcontext().prec = y + 1

if x >= 10**2 and x < 10**4:
    getcontext().prec = y + 2

if x >= 10**4 and x < 10**6:
    getcontext().prec = y + 3

if x >= 10**6 and x < 10**8:
    getcontext().prec = y + 4

if x >= 10**8 and x < 10**10:
    getcontext().prec = y + 5

if x >= 10**10 and x < 10**12:
    getcontext().prec = y + 6

if x >= 10**12 and x < 10**14:
    getcontext().prec = y + 7


print("The square root of ",x," is : ", Decimal(a))
# print("The original number: ", Decimal(a)**2)

For the input

8765 8

your program should print out

93.62157870

For the input

3000 3

your program should print out

54,772

Cristofor
  • 2,077
  • 2
  • 15
  • 23
Alex
  • 93
  • 1
  • 1
  • 6
  • If you're using Python 3.8, `math.isqrt(n * 100**k)` already gives you all the correct digits; no need for Newton's method. (E.g., `math.isqrt(8765 * 100**8)` gives `9362157870`. I leave it to you to figure out how to print this with the decimal point in the right place. – Mark Dickinson Nov 03 '19 at 18:28
  • Thank you for your answer, but it's required. – Alex Nov 04 '19 at 18:28

2 Answers2

0

Try this. If you run into the same issue comment on it and I will try to see what's going on. I also have a question: Do you want k to be the number of decimal places after the '.' or just the number of total places? The program I have here will make it so the precision after the '.' is always the precision you want. After the program I will show you the other way to do it.

from decimal import *
import sys

print("If you want to stop the program, press q")

while True:
    n_int = input("Calculate the square root of: ")

    if str(n_int) == 'q':
        sys.exit()
    else:
        k_dec = int(input("Decimal positions: "))
        n_int = int(n_int)

    temp = Context(prec=k_dec,rounding=ROUND_FLOOR,
                   Emax=999999999,Emin=0)
    setcontext(temp)
    with_k = Decimal(n_int).sqrt()

    after_dec = k_dec - len(str(with_k).split('.')[1])
    context = Context(prec=(k_dec + after_dec),rounding=ROUND_FLOOR,
                      Emax=999999999,Emin=0)

    # prec in Decimal includes __.___ = 5 and __._ = 3 

    setcontext(context)
    sqrt = Decimal(n_int).sqrt()

    if k_dec == 0:
        sqrt = sqrt.to_integral_exact()

    print(f"sqrt: {sqrt}")

If you want the TOTAL number of decimal places to be just delete everything after the with_k = Decimal(n_int).sqrt() and add print(f"sqrt {with_k}") after this line.

FilteredFrames
  • 182
  • 2
  • 8
0

Thank you for your answer but I must use the Newton Method, my code works but it does not input the correct decimal places always, for example:

CORRECT:

x = 10 y = 3 result: 3.162

CORRECT:

x = 1261 y = 3 result: 35,510

WRONG x= 26 y = 3 result: 5.10 ( should be 5,099 )

from decimal import *
from _decimal import Decimal

def sqrt(x):


error = (1/(10**(y+1)))
last_guess = x/2
while True:

    guess = Decimal((last_guess + x / last_guess) / 2)
    if abs(Decimal(guess) - Decimal(last_guess)) < error:
        return Decimal(guess)
    elif guess == last_guess:
        print("guess=last_guess")
        print(" a * a = ", Decimal(guess**2))
        print(guess)

    else:
        last_guess = Decimal(guess)

    # Enter values

    x = int(input("Calculate the square root of: "))

    y = int(input("Decimal positions : "))

    # set decimal places

    c= y


    getcontext().prec = y + 1

    # add one decimal place each time the square root of x increse of 10**2

    if x < 10**2:

        getcontext().prec = c + 1

    if x >= 10**2 and x < 10**4:

        getcontext().prec = c + 2

    if x >= 10**4 and x < 10**6:

        getcontext().prec = c + 3


    if x >= 10**6 and x < 10**8:

        getcontext().prec = c + 4

    if x >= 10**8 and x <= 10**9:

        getcontext().prec = c + 5

        # find the square root

    a =sqrt(x)


    print(Decimal(a))
Alex
  • 93
  • 1
  • 1
  • 6