OLD | NEW |
(Empty) | |
| 1 # -*- coding: utf-8 -*- |
| 2 # |
| 3 # Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu> |
| 4 # |
| 5 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 # you may not use this file except in compliance with the License. |
| 7 # You may obtain a copy of the License at |
| 8 # |
| 9 # https://www.apache.org/licenses/LICENSE-2.0 |
| 10 # |
| 11 # Unless required by applicable law or agreed to in writing, software |
| 12 # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 # See the License for the specific language governing permissions and |
| 15 # limitations under the License. |
| 16 |
| 17 """Common functionality shared by several modules.""" |
| 18 |
| 19 |
| 20 def bit_size(num): |
| 21 """ |
| 22 Number of bits needed to represent a integer excluding any prefix |
| 23 0 bits. |
| 24 |
| 25 As per definition from https://wiki.python.org/moin/BitManipulation and |
| 26 to match the behavior of the Python 3 API. |
| 27 |
| 28 Usage:: |
| 29 |
| 30 >>> bit_size(1023) |
| 31 10 |
| 32 >>> bit_size(1024) |
| 33 11 |
| 34 >>> bit_size(1025) |
| 35 11 |
| 36 |
| 37 :param num: |
| 38 Integer value. If num is 0, returns 0. Only the absolute value of the |
| 39 number is considered. Therefore, signed integers will be abs(num) |
| 40 before the number's bit length is determined. |
| 41 :returns: |
| 42 Returns the number of bits in the integer. |
| 43 """ |
| 44 if num == 0: |
| 45 return 0 |
| 46 if num < 0: |
| 47 num = -num |
| 48 |
| 49 # Make sure this is an int and not a float. |
| 50 num & 1 |
| 51 |
| 52 hex_num = "%x" % num |
| 53 return ((len(hex_num) - 1) * 4) + { |
| 54 '0': 0, '1': 1, '2': 2, '3': 2, |
| 55 '4': 3, '5': 3, '6': 3, '7': 3, |
| 56 '8': 4, '9': 4, 'a': 4, 'b': 4, |
| 57 'c': 4, 'd': 4, 'e': 4, 'f': 4, |
| 58 }[hex_num[0]] |
| 59 |
| 60 |
| 61 def _bit_size(number): |
| 62 """ |
| 63 Returns the number of bits required to hold a specific long number. |
| 64 """ |
| 65 if number < 0: |
| 66 raise ValueError('Only nonnegative numbers possible: %s' % number) |
| 67 |
| 68 if number == 0: |
| 69 return 0 |
| 70 |
| 71 # This works, even with very large numbers. When using math.log(number, 2), |
| 72 # you'll get rounding errors and it'll fail. |
| 73 bits = 0 |
| 74 while number: |
| 75 bits += 1 |
| 76 number >>= 1 |
| 77 |
| 78 return bits |
| 79 |
| 80 |
| 81 def byte_size(number): |
| 82 """ |
| 83 Returns the number of bytes required to hold a specific long number. |
| 84 |
| 85 The number of bytes is rounded up. |
| 86 |
| 87 Usage:: |
| 88 |
| 89 >>> byte_size(1 << 1023) |
| 90 128 |
| 91 >>> byte_size((1 << 1024) - 1) |
| 92 128 |
| 93 >>> byte_size(1 << 1024) |
| 94 129 |
| 95 |
| 96 :param number: |
| 97 An unsigned integer |
| 98 :returns: |
| 99 The number of bytes required to hold a specific long number. |
| 100 """ |
| 101 quanta, mod = divmod(bit_size(number), 8) |
| 102 if mod or number == 0: |
| 103 quanta += 1 |
| 104 return quanta |
| 105 # return int(math.ceil(bit_size(number) / 8.0)) |
| 106 |
| 107 |
| 108 def extended_gcd(a, b): |
| 109 """Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb |
| 110 """ |
| 111 # r = gcd(a,b) i = multiplicitive inverse of a mod b |
| 112 # or j = multiplicitive inverse of b mod a |
| 113 # Neg return values for i or j are made positive mod b or a respectively |
| 114 # Iterateive Version is faster and uses much less stack space |
| 115 x = 0 |
| 116 y = 1 |
| 117 lx = 1 |
| 118 ly = 0 |
| 119 oa = a # Remember original a/b to remove |
| 120 ob = b # negative values from return results |
| 121 while b != 0: |
| 122 q = a // b |
| 123 (a, b) = (b, a % b) |
| 124 (x, lx) = ((lx - (q * x)), x) |
| 125 (y, ly) = ((ly - (q * y)), y) |
| 126 if lx < 0: |
| 127 lx += ob # If neg wrap modulo orignal b |
| 128 if ly < 0: |
| 129 ly += oa # If neg wrap modulo orignal a |
| 130 return a, lx, ly # Return only positive values |
| 131 |
| 132 |
| 133 def inverse(x, n): |
| 134 """Returns x^-1 (mod n) |
| 135 |
| 136 >>> inverse(7, 4) |
| 137 3 |
| 138 >>> (inverse(143, 4) * 143) % 4 |
| 139 1 |
| 140 """ |
| 141 |
| 142 (divider, inv, _) = extended_gcd(x, n) |
| 143 |
| 144 if divider != 1: |
| 145 raise ValueError("x (%d) and n (%d) are not relatively prime" % (x, n)) |
| 146 |
| 147 return inv |
| 148 |
| 149 |
| 150 def crt(a_values, modulo_values): |
| 151 """Chinese Remainder Theorem. |
| 152 |
| 153 Calculates x such that x = a[i] (mod m[i]) for each i. |
| 154 |
| 155 :param a_values: the a-values of the above equation |
| 156 :param modulo_values: the m-values of the above equation |
| 157 :returns: x such that x = a[i] (mod m[i]) for each i |
| 158 |
| 159 |
| 160 >>> crt([2, 3], [3, 5]) |
| 161 8 |
| 162 |
| 163 >>> crt([2, 3, 2], [3, 5, 7]) |
| 164 23 |
| 165 |
| 166 >>> crt([2, 3, 0], [7, 11, 15]) |
| 167 135 |
| 168 """ |
| 169 |
| 170 m = 1 |
| 171 x = 0 |
| 172 |
| 173 for modulo in modulo_values: |
| 174 m *= modulo |
| 175 |
| 176 for (m_i, a_i) in zip(modulo_values, a_values): |
| 177 M_i = m // m_i |
| 178 inv = inverse(M_i, m_i) |
| 179 |
| 180 x = (x + a_i * M_i * inv) % m |
| 181 |
| 182 return x |
| 183 |
| 184 |
| 185 if __name__ == '__main__': |
| 186 import doctest |
| 187 |
| 188 doctest.testmod() |
OLD | NEW |