digits.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. from collections import defaultdict
  2. from sympy.utilities.iterables import multiset, is_palindromic as _palindromic
  3. from sympy.utilities.misc import as_int
  4. def digits(n, b=10, digits=None):
  5. """
  6. Return a list of the digits of ``n`` in base ``b``. The first
  7. element in the list is ``b`` (or ``-b`` if ``n`` is negative).
  8. Examples
  9. ========
  10. >>> from sympy.ntheory.digits import digits
  11. >>> digits(35)
  12. [10, 3, 5]
  13. If the number is negative, the negative sign will be placed on the
  14. base (which is the first element in the returned list):
  15. >>> digits(-35)
  16. [-10, 3, 5]
  17. Bases other than 10 (and greater than 1) can be selected with ``b``:
  18. >>> digits(27, b=2)
  19. [2, 1, 1, 0, 1, 1]
  20. Use the ``digits`` keyword if a certain number of digits is desired:
  21. >>> digits(35, digits=4)
  22. [10, 0, 0, 3, 5]
  23. Parameters
  24. ==========
  25. n: integer
  26. The number whose digits are returned.
  27. b: integer
  28. The base in which digits are computed.
  29. digits: integer (or None for all digits)
  30. The number of digits to be returned (padded with zeros, if
  31. necessary).
  32. See Also
  33. ========
  34. sympy.core.intfunc.num_digits, count_digits
  35. """
  36. b = as_int(b)
  37. n = as_int(n)
  38. if b < 2:
  39. raise ValueError("b must be greater than 1")
  40. else:
  41. x, y = abs(n), []
  42. while x >= b:
  43. x, r = divmod(x, b)
  44. y.append(r)
  45. y.append(x)
  46. y.append(-b if n < 0 else b)
  47. y.reverse()
  48. ndig = len(y) - 1
  49. if digits is not None:
  50. if ndig > digits:
  51. raise ValueError(
  52. "For %s, at least %s digits are needed." % (n, ndig))
  53. elif ndig < digits:
  54. y[1:1] = [0]*(digits - ndig)
  55. return y
  56. def count_digits(n, b=10):
  57. """
  58. Return a dictionary whose keys are the digits of ``n`` in the
  59. given base, ``b``, with keys indicating the digits appearing in the
  60. number and values indicating how many times that digit appeared.
  61. Examples
  62. ========
  63. >>> from sympy.ntheory import count_digits
  64. >>> count_digits(1111339)
  65. {1: 4, 3: 2, 9: 1}
  66. The digits returned are always represented in base-10
  67. but the number itself can be entered in any format that is
  68. understood by Python; the base of the number can also be
  69. given if it is different than 10:
  70. >>> n = 0xFA; n
  71. 250
  72. >>> count_digits(_)
  73. {0: 1, 2: 1, 5: 1}
  74. >>> count_digits(n, 16)
  75. {10: 1, 15: 1}
  76. The default dictionary will return a 0 for any digit that did
  77. not appear in the number. For example, which digits appear 7
  78. times in ``77!``:
  79. >>> from sympy import factorial
  80. >>> c77 = count_digits(factorial(77))
  81. >>> [i for i in range(10) if c77[i] == 7]
  82. [1, 3, 7, 9]
  83. See Also
  84. ========
  85. sympy.core.intfunc.num_digits, digits
  86. """
  87. rv = defaultdict(int, multiset(digits(n, b)).items())
  88. rv.pop(b) if b in rv else rv.pop(-b) # b or -b is there
  89. return rv
  90. def is_palindromic(n, b=10):
  91. """return True if ``n`` is the same when read from left to right
  92. or right to left in the given base, ``b``.
  93. Examples
  94. ========
  95. >>> from sympy.ntheory import is_palindromic
  96. >>> all(is_palindromic(i) for i in (-11, 1, 22, 121))
  97. True
  98. The second argument allows you to test numbers in other
  99. bases. For example, 88 is palindromic in base-10 but not
  100. in base-8:
  101. >>> is_palindromic(88, 8)
  102. False
  103. On the other hand, a number can be palindromic in base-8 but
  104. not in base-10:
  105. >>> 0o121, is_palindromic(0o121)
  106. (81, False)
  107. Or it might be palindromic in both bases:
  108. >>> oct(121), is_palindromic(121, 8) and is_palindromic(121)
  109. ('0o171', True)
  110. """
  111. return _palindromic(digits(n, b), 1)