fork download
  1. import math
  2.  
  3. def safe_newton_sqrt(k, eps, guess_init=None, maxiter=10000):
  4. if k < 0:
  5. raise ValueError("k < 0: real square root does not exist")
  6. if guess_init is None:
  7.  
  8. guess = k/2.0 if k != 0 else 0.5
  9. else:
  10. guess = guess_init
  11. if guess == 0:
  12. guess = 0.5
  13.  
  14. iterations = 0
  15. for _ in range(maxiter):
  16. dval = 2.0 * guess
  17. if abs(dval) < 1e-16:
  18.  
  19. guess += 1e-6
  20. dval = 2.0 * guess
  21. val = guess*guess - k
  22. new_guess = guess - val / dval
  23. iterations += 1
  24. if abs(new_guess - guess) < eps:
  25. return {'approx': new_guess, 'iterations': iterations}
  26. guess = new_guess
  27. raise RuntimeError("Newton did not converge within maxiter")
  28.  
  29. def safe_bisection_sqrt(k, eps):
  30. if k < 0:
  31. raise ValueError("k < 0: real square root does not exist")
  32. a = 0.0
  33. b = max(1.0, k)
  34. fa = a*a - k
  35. fb = b*b - k
  36. if fa * fb > 0:
  37.  
  38. b = max(b, 1.0)
  39. fb = b*b - k
  40. if fa * fb > 0:
  41. raise ValueError("Cannot find sign change for bisection on interval [0, max(1,k)]")
  42. iterations = 0
  43. while (b - a)/2.0 > eps:
  44. m = (a + b)/2.0
  45. fm = m*m - k
  46. iterations += 1
  47. if fm == 0:
  48. return {'approx': m, 'iterations': iterations}
  49. if fa * fm < 0:
  50. b, fb = m, fm
  51. else:
  52. a, fa = m, fm
  53. return {'approx': (a+b)/2.0, 'iterations': iterations}
  54.  
  55. # 使用例
  56. k = 24.0
  57. eps = 1e-6
  58. print(safe_newton_sqrt(k, eps))
  59. print(safe_bisection_sqrt(k, eps))
  60.  
Success #stdin #stdout 0.05s 63544KB
stdin
Standard input is empty
stdout
{'approx': 4.898979485566356, 'iterations': 6}
{'approx': 4.89897894859314, 'iterations': 24}