m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

351 lines
9.8 KiB

6 months ago
  1. from sympy.core.numbers import Integer, Rational
  2. from sympy.core.singleton import S
  3. from sympy.core.sympify import _sympify
  4. from sympy.utilities.misc import as_int
  5. def continued_fraction(a):
  6. """Return the continued fraction representation of a Rational or
  7. quadratic irrational.
  8. Examples
  9. ========
  10. >>> from sympy.ntheory.continued_fraction import continued_fraction
  11. >>> from sympy import sqrt
  12. >>> continued_fraction((1 + 2*sqrt(3))/5)
  13. [0, 1, [8, 3, 34, 3]]
  14. See Also
  15. ========
  16. continued_fraction_periodic, continued_fraction_reduce, continued_fraction_convergents
  17. """
  18. e = _sympify(a)
  19. if all(i.is_Rational for i in e.atoms()):
  20. if e.is_Integer:
  21. return continued_fraction_periodic(e, 1, 0)
  22. elif e.is_Rational:
  23. return continued_fraction_periodic(e.p, e.q, 0)
  24. elif e.is_Pow and e.exp is S.Half and e.base.is_Integer:
  25. return continued_fraction_periodic(0, 1, e.base)
  26. elif e.is_Mul and len(e.args) == 2 and (
  27. e.args[0].is_Rational and
  28. e.args[1].is_Pow and
  29. e.args[1].base.is_Integer and
  30. e.args[1].exp is S.Half):
  31. a, b = e.args
  32. return continued_fraction_periodic(0, a.q, b.base, a.p)
  33. else:
  34. # this should not have to work very hard- no
  35. # simplification, cancel, etc... which should be
  36. # done by the user. e.g. This is a fancy 1 but
  37. # the user should simplify it first:
  38. # sqrt(2)*(1 + sqrt(2))/(sqrt(2) + 2)
  39. p, d = e.expand().as_numer_denom()
  40. if d.is_Integer:
  41. if p.is_Rational:
  42. return continued_fraction_periodic(p, d)
  43. # look for a + b*c
  44. # with c = sqrt(s)
  45. if p.is_Add and len(p.args) == 2:
  46. a, bc = p.args
  47. else:
  48. a = S.Zero
  49. bc = p
  50. if a.is_Integer:
  51. b = S.NaN
  52. if bc.is_Mul and len(bc.args) == 2:
  53. b, c = bc.args
  54. elif bc.is_Pow:
  55. b = Integer(1)
  56. c = bc
  57. if b.is_Integer and (
  58. c.is_Pow and c.exp is S.Half and
  59. c.base.is_Integer):
  60. # (a + b*sqrt(c))/d
  61. c = c.base
  62. return continued_fraction_periodic(a, d, c, b)
  63. raise ValueError(
  64. 'expecting a rational or quadratic irrational, not %s' % e)
  65. def continued_fraction_periodic(p, q, d=0, s=1):
  66. r"""
  67. Find the periodic continued fraction expansion of a quadratic irrational.
  68. Compute the continued fraction expansion of a rational or a
  69. quadratic irrational number, i.e. `\frac{p + s\sqrt{d}}{q}`, where
  70. `p`, `q \ne 0` and `d \ge 0` are integers.
  71. Returns the continued fraction representation (canonical form) as
  72. a list of integers, optionally ending (for quadratic irrationals)
  73. with list of integers representing the repeating digits.
  74. Parameters
  75. ==========
  76. p : int
  77. the rational part of the number's numerator
  78. q : int
  79. the denominator of the number
  80. d : int, optional
  81. the irrational part (discriminator) of the number's numerator
  82. s : int, optional
  83. the coefficient of the irrational part
  84. Examples
  85. ========
  86. >>> from sympy.ntheory.continued_fraction import continued_fraction_periodic
  87. >>> continued_fraction_periodic(3, 2, 7)
  88. [2, [1, 4, 1, 1]]
  89. Golden ratio has the simplest continued fraction expansion:
  90. >>> continued_fraction_periodic(1, 2, 5)
  91. [[1]]
  92. If the discriminator is zero or a perfect square then the number will be a
  93. rational number:
  94. >>> continued_fraction_periodic(4, 3, 0)
  95. [1, 3]
  96. >>> continued_fraction_periodic(4, 3, 49)
  97. [3, 1, 2]
  98. See Also
  99. ========
  100. continued_fraction_iterator, continued_fraction_reduce
  101. References
  102. ==========
  103. .. [1] https://en.wikipedia.org/wiki/Periodic_continued_fraction
  104. .. [2] K. Rosen. Elementary Number theory and its applications.
  105. Addison-Wesley, 3 Sub edition, pages 379-381, January 1992.
  106. """
  107. from sympy.functions import sqrt, floor
  108. p, q, d, s = list(map(as_int, [p, q, d, s]))
  109. if d < 0:
  110. raise ValueError("expected non-negative for `d` but got %s" % d)
  111. if q == 0:
  112. raise ValueError("The denominator cannot be 0.")
  113. if not s:
  114. d = 0
  115. # check for rational case
  116. sd = sqrt(d)
  117. if sd.is_Integer:
  118. return list(continued_fraction_iterator(Rational(p + s*sd, q)))
  119. # irrational case with sd != Integer
  120. if q < 0:
  121. p, q, s = -p, -q, -s
  122. n = (p + s*sd)/q
  123. if n < 0:
  124. w = floor(-n)
  125. f = -n - w
  126. one_f = continued_fraction(1 - f) # 1-f < 1 so cf is [0 ... [...]]
  127. one_f[0] -= w + 1
  128. return one_f
  129. d *= s**2
  130. sd *= s
  131. if (d - p**2)%q:
  132. d *= q**2
  133. sd *= q
  134. p *= q
  135. q *= q
  136. terms = []
  137. pq = {}
  138. while (p, q) not in pq:
  139. pq[(p, q)] = len(terms)
  140. terms.append((p + sd)//q)
  141. p = terms[-1]*q - p
  142. q = (d - p**2)//q
  143. i = pq[(p, q)]
  144. return terms[:i] + [terms[i:]]
  145. def continued_fraction_reduce(cf):
  146. """
  147. Reduce a continued fraction to a rational or quadratic irrational.
  148. Compute the rational or quadratic irrational number from its
  149. terminating or periodic continued fraction expansion. The
  150. continued fraction expansion (cf) should be supplied as a
  151. terminating iterator supplying the terms of the expansion. For
  152. terminating continued fractions, this is equivalent to
  153. ``list(continued_fraction_convergents(cf))[-1]``, only a little more
  154. efficient. If the expansion has a repeating part, a list of the
  155. repeating terms should be returned as the last element from the
  156. iterator. This is the format returned by
  157. continued_fraction_periodic.
  158. For quadratic irrationals, returns the largest solution found,
  159. which is generally the one sought, if the fraction is in canonical
  160. form (all terms positive except possibly the first).
  161. Examples
  162. ========
  163. >>> from sympy.ntheory.continued_fraction import continued_fraction_reduce
  164. >>> continued_fraction_reduce([1, 2, 3, 4, 5])
  165. 225/157
  166. >>> continued_fraction_reduce([-2, 1, 9, 7, 1, 2])
  167. -256/233
  168. >>> continued_fraction_reduce([2, 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8]).n(10)
  169. 2.718281835
  170. >>> continued_fraction_reduce([1, 4, 2, [3, 1]])
  171. (sqrt(21) + 287)/238
  172. >>> continued_fraction_reduce([[1]])
  173. (1 + sqrt(5))/2
  174. >>> from sympy.ntheory.continued_fraction import continued_fraction_periodic
  175. >>> continued_fraction_reduce(continued_fraction_periodic(8, 5, 13))
  176. (sqrt(13) + 8)/5
  177. See Also
  178. ========
  179. continued_fraction_periodic
  180. """
  181. from sympy.core.exprtools import factor_terms
  182. from sympy.core.symbol import Dummy
  183. from sympy.solvers import solve
  184. period = []
  185. x = Dummy('x')
  186. def untillist(cf):
  187. for nxt in cf:
  188. if isinstance(nxt, list):
  189. period.extend(nxt)
  190. yield x
  191. break
  192. yield nxt
  193. a = S.Zero
  194. for a in continued_fraction_convergents(untillist(cf)):
  195. pass
  196. if period:
  197. y = Dummy('y')
  198. solns = solve(continued_fraction_reduce(period + [y]) - y, y)
  199. solns.sort()
  200. pure = solns[-1]
  201. rv = a.subs(x, pure).radsimp()
  202. else:
  203. rv = a
  204. if rv.is_Add:
  205. rv = factor_terms(rv)
  206. if rv.is_Mul and rv.args[0] == -1:
  207. rv = rv.func(*rv.args)
  208. return rv
  209. def continued_fraction_iterator(x):
  210. """
  211. Return continued fraction expansion of x as iterator.
  212. Examples
  213. ========
  214. >>> from sympy import Rational, pi
  215. >>> from sympy.ntheory.continued_fraction import continued_fraction_iterator
  216. >>> list(continued_fraction_iterator(Rational(3, 8)))
  217. [0, 2, 1, 2]
  218. >>> list(continued_fraction_iterator(Rational(-3, 8)))
  219. [-1, 1, 1, 1, 2]
  220. >>> for i, v in enumerate(continued_fraction_iterator(pi)):
  221. ... if i > 7:
  222. ... break
  223. ... print(v)
  224. 3
  225. 7
  226. 15
  227. 1
  228. 292
  229. 1
  230. 1
  231. 1
  232. References
  233. ==========
  234. .. [1] https://en.wikipedia.org/wiki/Continued_fraction
  235. """
  236. from sympy.functions import floor
  237. while True:
  238. i = floor(x)
  239. yield i
  240. x -= i
  241. if not x:
  242. break
  243. x = 1/x
  244. def continued_fraction_convergents(cf):
  245. """
  246. Return an iterator over the convergents of a continued fraction (cf).
  247. The parameter should be an iterable returning successive
  248. partial quotients of the continued fraction, such as might be
  249. returned by continued_fraction_iterator. In computing the
  250. convergents, the continued fraction need not be strictly in
  251. canonical form (all integers, all but the first positive).
  252. Rational and negative elements may be present in the expansion.
  253. Examples
  254. ========
  255. >>> from sympy.core import pi
  256. >>> from sympy import S
  257. >>> from sympy.ntheory.continued_fraction import \
  258. continued_fraction_convergents, continued_fraction_iterator
  259. >>> list(continued_fraction_convergents([0, 2, 1, 2]))
  260. [0, 1/2, 1/3, 3/8]
  261. >>> list(continued_fraction_convergents([1, S('1/2'), -7, S('1/4')]))
  262. [1, 3, 19/5, 7]
  263. >>> it = continued_fraction_convergents(continued_fraction_iterator(pi))
  264. >>> for n in range(7):
  265. ... print(next(it))
  266. 3
  267. 22/7
  268. 333/106
  269. 355/113
  270. 103993/33102
  271. 104348/33215
  272. 208341/66317
  273. See Also
  274. ========
  275. continued_fraction_iterator
  276. """
  277. p_2, q_2 = S.Zero, S.One
  278. p_1, q_1 = S.One, S.Zero
  279. for a in cf:
  280. p, q = a*p_1 + p_2, a*q_1 + q_2
  281. p_2, q_2 = p_1, q_1
  282. p_1, q_1 = p, q
  283. yield p/q