digits.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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. """
  33. b = as_int(b)
  34. n = as_int(n)
  35. if b < 2:
  36. raise ValueError("b must be greater than 1")
  37. else:
  38. x, y = abs(n), []
  39. while x >= b:
  40. x, r = divmod(x, b)
  41. y.append(r)
  42. y.append(x)
  43. y.append(-b if n < 0 else b)
  44. y.reverse()
  45. ndig = len(y) - 1
  46. if digits is not None:
  47. if ndig > digits:
  48. raise ValueError(
  49. "For %s, at least %s digits are needed." % (n, ndig))
  50. elif ndig < digits:
  51. y[1:1] = [0]*(digits - ndig)
  52. return y
  53. def count_digits(n, b=10):
  54. """
  55. Return a dictionary whose keys are the digits of ``n`` in the
  56. given base, ``b``, with keys indicating the digits appearing in the
  57. number and values indicating how many times that digit appeared.
  58. Examples
  59. ========
  60. >>> from sympy.ntheory import count_digits
  61. >>> count_digits(1111339)
  62. {1: 4, 3: 2, 9: 1}
  63. The digits returned are always represented in base-10
  64. but the number itself can be entered in any format that is
  65. understood by Python; the base of the number can also be
  66. given if it is different than 10:
  67. >>> n = 0xFA; n
  68. 250
  69. >>> count_digits(_)
  70. {0: 1, 2: 1, 5: 1}
  71. >>> count_digits(n, 16)
  72. {10: 1, 15: 1}
  73. The default dictionary will return a 0 for any digit that did
  74. not appear in the number. For example, which digits appear 7
  75. times in ``77!``:
  76. >>> from sympy import factorial
  77. >>> c77 = count_digits(factorial(77))
  78. >>> [i for i in range(10) if c77[i] == 7]
  79. [1, 3, 7, 9]
  80. """
  81. rv = defaultdict(int, multiset(digits(n, b)).items())
  82. rv.pop(b) if b in rv else rv.pop(-b) # b or -b is there
  83. return rv
  84. def is_palindromic(n, b=10):
  85. """return True if ``n`` is the same when read from left to right
  86. or right to left in the given base, ``b``.
  87. Examples
  88. ========
  89. >>> from sympy.ntheory import is_palindromic
  90. >>> all(is_palindromic(i) for i in (-11, 1, 22, 121))
  91. True
  92. The second argument allows you to test numbers in other
  93. bases. For example, 88 is palindromic in base-10 but not
  94. in base-8:
  95. >>> is_palindromic(88, 8)
  96. False
  97. On the other hand, a number can be palindromic in base-8 but
  98. not in base-10:
  99. >>> 0o121, is_palindromic(0o121)
  100. (81, False)
  101. Or it might be palindromic in both bases:
  102. >>> oct(121), is_palindromic(121, 8) and is_palindromic(121)
  103. ('0o171', True)
  104. """
  105. return _palindromic(digits(n, b), 1)