OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright 2012 Google Inc. All Rights Reserved. |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | 2 |
5 #include "vm/bigint_operations.h" | 3 #include "vm/bigint_operations.h" |
6 | 4 |
7 #include <openssl/crypto.h> | 5 #include "platform/utils.h" |
8 | 6 |
9 #include "platform/utils.h" | |
10 #include "vm/bigint_store.h" | |
11 #include "vm/double_internals.h" | 7 #include "vm/double_internals.h" |
12 #include "vm/exceptions.h" | 8 #include "vm/exceptions.h" |
13 #include "vm/zone.h" | 9 #include "vm/zone.h" |
14 | 10 |
15 namespace dart { | 11 namespace dart { |
16 | 12 |
17 bool Bigint::IsZero() const { return BN_is_zero(BNAddr()); } | |
18 bool Bigint::IsNegative() const { return !!BNAddr()->neg; } | |
19 | |
20 | |
21 void Bigint::SetSign(bool is_negative) const { | |
22 BIGNUM* bn = MutableBNAddr(); | |
23 // Danger Will Robinson! Use of OpenSSL internals! | |
24 // FIXME(benl): can be changed to use BN_set_negative() on more | |
25 // recent OpenSSL releases (> 1.0.0). | |
26 if (!is_negative || BN_is_zero(bn)) { | |
27 bn->neg = 0; | |
28 } else { | |
29 bn->neg = 1; | |
30 } | |
31 } | |
32 | |
33 | |
34 BIGNUM* BigintOperations::TmpBN() { | |
35 BigintStore* store = BigintStore::Get(); | |
36 if (store->bn_ == NULL) { | |
37 store->bn_ = BN_new(); | |
38 } | |
39 return store->bn_; | |
40 } | |
41 | |
42 | |
43 BN_CTX* BigintOperations::TmpBNCtx() { | |
44 BigintStore* store = BigintStore::Get(); | |
45 if (store->bn_ctx_ == NULL) { | |
46 store->bn_ctx_ = BN_CTX_new(); | |
47 } | |
48 return store->bn_ctx_; | |
49 } | |
50 | |
51 | |
52 RawBigint* BigintOperations::NewFromSmi(const Smi& smi, Heap::Space space) { | 13 RawBigint* BigintOperations::NewFromSmi(const Smi& smi, Heap::Space space) { |
53 intptr_t value = smi.Value(); | 14 intptr_t value = smi.Value(); |
54 bool is_negative = value < 0; | 15 if (value == 0) { |
| 16 return Zero(); |
| 17 } |
55 | 18 |
| 19 bool is_negative = (value < 0); |
56 if (is_negative) { | 20 if (is_negative) { |
57 value = -value; | 21 value = -value; |
58 } | 22 } |
| 23 // Assert that there are no overflows. Smis reserve a bit for themselves, but |
| 24 // protect against future changes. |
| 25 ASSERT(-Smi::kMinValue > 0); |
59 | 26 |
60 BN_set_word(TmpBN(), value); | 27 // A single digit of a Bigint might not be sufficient to store a Smi. |
| 28 // Count number of needed Digits. |
| 29 intptr_t digit_count = 0; |
| 30 intptr_t count_value = value; |
| 31 while (count_value > 0) { |
| 32 digit_count++; |
| 33 count_value >>= kDigitBitSize; |
| 34 } |
61 | 35 |
62 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN(), space)); | 36 // Allocate a bigint of the correct size and copy the bits. |
| 37 const Bigint& result = Bigint::Handle(Bigint::Allocate(digit_count, space)); |
| 38 for (int i = 0; i < digit_count; i++) { |
| 39 result.SetChunkAt(i, static_cast<Chunk>(value & kDigitMask)); |
| 40 value >>= kDigitBitSize; |
| 41 } |
63 result.SetSign(is_negative); | 42 result.SetSign(is_negative); |
64 | 43 ASSERT(IsClamped(result)); |
65 return result.raw(); | 44 return result.raw(); |
66 } | 45 } |
67 | 46 |
68 | 47 |
69 RawBigint* BigintOperations::NewFromInt64(int64_t value, Heap::Space space) { | 48 RawBigint* BigintOperations::NewFromInt64(int64_t value, Heap::Space space) { |
70 bool is_negative = value < 0; | 49 bool is_negative = value < 0; |
71 | 50 |
72 if (is_negative) { | 51 if (is_negative) { |
73 value = -value; | 52 value = -value; |
74 } | 53 } |
75 | 54 |
76 const Bigint& result = Bigint::Handle(NewFromUint64(value, space)); | 55 const Bigint& result = Bigint::Handle(NewFromUint64(value, space)); |
77 result.SetSign(is_negative); | 56 result.SetSign(is_negative); |
78 | 57 |
79 return result.raw(); | 58 return result.raw(); |
80 } | 59 } |
81 | 60 |
82 | 61 |
83 RawBigint* BigintOperations::NewFromUint64(uint64_t value, Heap::Space space) { | 62 RawBigint* BigintOperations::NewFromUint64(uint64_t value, Heap::Space space) { |
84 const int kNumBytes = sizeof(value); | 63 if (value == 0) { |
85 unsigned char pch[kNumBytes]; | 64 return Zero(); |
86 for (int i = kNumBytes - 1; i >= 0; i--) { | |
87 unsigned char c = value & 0xFF; | |
88 value >>=8; | |
89 pch[i] = c; | |
90 } | 65 } |
91 BN_bin2bn(pch, kNumBytes, TmpBN()); | 66 // A single digit of a Bigint might not be sufficient to store the value. |
92 return Bigint::New(TmpBN(), space); | 67 // Count number of needed Digits. |
| 68 intptr_t digit_count = 0; |
| 69 uint64_t count_value = value; |
| 70 while (count_value > 0) { |
| 71 digit_count++; |
| 72 count_value >>= kDigitBitSize; |
| 73 } |
| 74 |
| 75 // Allocate a bigint of the correct size and copy the bits. |
| 76 const Bigint& result = Bigint::Handle(Bigint::Allocate(digit_count, space)); |
| 77 for (int i = 0; i < digit_count; i++) { |
| 78 result.SetChunkAt(i, static_cast<Chunk>(value & kDigitMask)); |
| 79 value >>= kDigitBitSize; |
| 80 } |
| 81 result.SetSign(false); |
| 82 ASSERT(IsClamped(result)); |
| 83 return result.raw(); |
93 } | 84 } |
94 | 85 |
95 | 86 |
96 RawBigint* BigintOperations::NewFromCString(const char* str, | 87 RawBigint* BigintOperations::NewFromCString(const char* str, |
97 Heap::Space space) { | 88 Heap::Space space) { |
98 ASSERT(str != NULL); | 89 ASSERT(str != NULL); |
99 if (str[0] == '\0') { | 90 if (str[0] == '\0') { |
100 return NewFromInt64(0, space); | 91 return Zero(); |
101 } | 92 } |
102 | 93 |
103 // If the string starts with '-' recursively restart the whole operation | 94 // If the string starts with '-' recursively restart the whole operation |
104 // without the character and then toggle the sign. | 95 // without the character and then toggle the sign. |
105 // This allows multiple leading '-' (which will cancel each other out), but | 96 // This allows multiple leading '-' (which will cancel each other out), but |
106 // we have added an assert, to make sure that the returned result of the | 97 // we have added an assert, to make sure that the returned result of the |
107 // recursive call is not negative. | 98 // recursive call is not negative. |
108 // We don't catch leading '-'s for zero. Ex: "--0", or "---". | 99 // We don't catch leading '-'s for zero. Ex: "--0", or "---". |
109 if (str[0] == '-') { | 100 if (str[0] == '-') { |
110 const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space)); | 101 const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space)); |
111 if (!result.IsNull()) { | 102 result.ToggleSign(); |
112 result.ToggleSign(); | 103 ASSERT(result.IsZero() || result.IsNegative()); |
113 // FIXME(benl): this will fail if there is more than one leading '-'. | 104 ASSERT(IsClamped(result)); |
114 ASSERT(result.IsZero() || result.IsNegative()); | |
115 } | |
116 return result.raw(); | 105 return result.raw(); |
117 } | 106 } |
118 | 107 |
119 intptr_t str_length = strlen(str); | 108 intptr_t str_length = strlen(str); |
120 if ((str_length > 2) && | 109 if ((str_length > 2) && |
121 (str[0] == '0') && | 110 (str[0] == '0') && |
122 ((str[1] == 'x') || (str[1] == 'X'))) { | 111 ((str[1] == 'x') || (str[1] == 'X'))) { |
123 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space)); | 112 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space)); |
| 113 ASSERT(IsClamped(result)); |
124 return result.raw(); | 114 return result.raw(); |
125 } else { | 115 } else { |
126 return FromDecimalCString(str, space); | 116 return FromDecimalCString(str); |
127 } | 117 } |
128 } | 118 } |
129 | 119 |
130 | 120 |
| 121 RawBigint* BigintOperations::FromHexCString(const char* hex_string, |
| 122 Heap::Space space) { |
| 123 // If the string starts with '-' recursively restart the whole operation |
| 124 // without the character and then toggle the sign. |
| 125 // This allows multiple leading '-' (which will cancel each other out), but |
| 126 // we have added an assert, to make sure that the returned result of the |
| 127 // recursive call is not negative. |
| 128 // We don't catch leading '-'s for zero. Ex: "--0", or "---". |
| 129 if (hex_string[0] == '-') { |
| 130 const Bigint& value = Bigint::Handle(FromHexCString(&hex_string[1], space)); |
| 131 value.ToggleSign(); |
| 132 ASSERT(value.IsZero() || value.IsNegative()); |
| 133 ASSERT(IsClamped(value)); |
| 134 return value.raw(); |
| 135 } |
| 136 |
| 137 ASSERT(kDigitBitSize % 4 == 0); |
| 138 const int kHexCharsPerDigit = kDigitBitSize / 4; |
| 139 |
| 140 intptr_t hex_length = strlen(hex_string); |
| 141 // Round up. |
| 142 intptr_t bigint_length = ((hex_length - 1) / kHexCharsPerDigit) + 1; |
| 143 const Bigint& result = |
| 144 Bigint::Handle(Bigint::Allocate(bigint_length, space)); |
| 145 // The bigint's least significant digit (lsd) is at position 0, whereas the |
| 146 // given string has it's lsd at the last position. |
| 147 // The hex_i index, pointing into the string, starts therefore at the end, |
| 148 // whereas the bigint-index (i) starts at 0. |
| 149 intptr_t hex_i = hex_length - 1; |
| 150 for (intptr_t i = 0; i < bigint_length; i++) { |
| 151 Chunk digit = 0; |
| 152 int shift = 0; |
| 153 for (int j = 0; j < kHexCharsPerDigit; j++) { |
| 154 // Reads a block of hexadecimal digits and stores it in 'digit'. |
| 155 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456". |
| 156 if (hex_i < 0) { |
| 157 break; |
| 158 } |
| 159 ASSERT(hex_i >= 0); |
| 160 char c = hex_string[hex_i--]; |
| 161 ASSERT(Utils::IsHexDigit(c)); |
| 162 digit += static_cast<Chunk>(Utils::HexDigitToInt(c)) << shift; |
| 163 shift += 4; |
| 164 } |
| 165 result.SetChunkAt(i, digit); |
| 166 } |
| 167 ASSERT(hex_i == -1); |
| 168 Clamp(result); |
| 169 return result.raw(); |
| 170 } |
| 171 |
| 172 |
| 173 RawBigint* BigintOperations::FromDecimalCString(const char* str, |
| 174 Heap::Space space) { |
| 175 // Read 8 digits a time. 10^8 < 2^27. |
| 176 const int kDigitsPerIteration = 8; |
| 177 const Chunk kTenMultiplier = 100000000; |
| 178 ASSERT(kDigitBitSize >= 27); |
| 179 |
| 180 intptr_t str_length = strlen(str); |
| 181 intptr_t str_pos = 0; |
| 182 |
| 183 // Read first digit separately. This avoids a multiplication and addition. |
| 184 // The first digit might also not have kDigitsPerIteration decimal digits. |
| 185 int first_digit_decimal_digits = str_length % kDigitsPerIteration; |
| 186 Chunk digit = 0; |
| 187 for (intptr_t i = 0; i < first_digit_decimal_digits; i++) { |
| 188 char c = str[str_pos++]; |
| 189 ASSERT(('0' <= c) && (c <= '9')); |
| 190 digit = digit * 10 + c - '0'; |
| 191 } |
| 192 Bigint& result = Bigint::Handle(Bigint::Allocate(1, space)); |
| 193 result.SetChunkAt(0, digit); |
| 194 Clamp(result); // Multiplication requires the inputs to be clamped. |
| 195 |
| 196 // Read kDigitsPerIteration at a time, and store it in 'increment'. |
| 197 // Then multiply the temporary result by 10^kDigitsPerIteration and add |
| 198 // 'increment' to the new result. |
| 199 const Bigint& increment = Bigint::Handle(Bigint::Allocate(1, space)); |
| 200 while (str_pos < str_length - 1) { |
| 201 Chunk digit = 0; |
| 202 for (intptr_t i = 0; i < kDigitsPerIteration; i++) { |
| 203 char c = str[str_pos++]; |
| 204 ASSERT(('0' <= c) && (c <= '9')); |
| 205 digit = digit * 10 + c - '0'; |
| 206 } |
| 207 result ^= MultiplyWithDigit(result, kTenMultiplier); |
| 208 if (digit != 0) { |
| 209 increment.SetChunkAt(0, digit); |
| 210 result ^= Add(result, increment); |
| 211 } |
| 212 } |
| 213 Clamp(result); |
| 214 return result.raw(); |
| 215 } |
| 216 |
| 217 |
131 RawBigint* BigintOperations::NewFromDouble(double d, Heap::Space space) { | 218 RawBigint* BigintOperations::NewFromDouble(double d, Heap::Space space) { |
132 if ((-1.0 < d) && (d < 1.0)) { | 219 if ((-1.0 < d) && (d < 1.0)) { |
133 // Shortcut for small numbers. Also makes the right-shift below | 220 // Shortcut for small numbers. Also makes the right-shift below |
134 // well specified. | 221 // well specified. |
135 Smi& zero = Smi::Handle(Smi::New(0)); | 222 Smi& zero = Smi::Handle(Smi::New(0)); |
136 return NewFromSmi(zero, space); | 223 return NewFromSmi(zero, space); |
137 } | 224 } |
138 DoubleInternals internals = DoubleInternals(d); | 225 DoubleInternals internals = DoubleInternals(d); |
139 if (internals.IsSpecial()) { | 226 if (internals.IsSpecial()) { |
140 GrowableArray<const Object*> exception_arguments; | 227 GrowableArray<const Object*> exception_arguments; |
(...skipping 19 matching lines...) Expand all Loading... |
160 Bigint::Handle(NewFromInt64(static_cast<int64_t>(significand), space)); | 247 Bigint::Handle(NewFromInt64(static_cast<int64_t>(significand), space)); |
161 result.SetSign(sign < 0); | 248 result.SetSign(sign < 0); |
162 if (exponent > 0) { | 249 if (exponent > 0) { |
163 return ShiftLeft(result, exponent); | 250 return ShiftLeft(result, exponent); |
164 } else { | 251 } else { |
165 return result.raw(); | 252 return result.raw(); |
166 } | 253 } |
167 } | 254 } |
168 | 255 |
169 | 256 |
170 RawBigint* BigintOperations::FromHexCString(const char* hex_string, | 257 const char* BigintOperations::ToHexCString(intptr_t length, |
171 Heap::Space space) { | 258 bool is_negative, |
172 BIGNUM *bn = TmpBN(); | 259 void* data, |
173 BN_hex2bn(&bn, hex_string); | 260 uword (*allocator)(intptr_t size)) { |
174 ASSERT(bn == TmpBN()); | 261 NoGCScope no_gc; |
175 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN(), space)); | |
176 return result.raw(); | |
177 } | |
178 | 262 |
| 263 ASSERT(kDigitBitSize % 4 == 0); |
| 264 const int kHexCharsPerDigit = kDigitBitSize / 4; |
179 | 265 |
180 RawBigint* BigintOperations::FromDecimalCString(const char* str, | 266 intptr_t chunk_length = length; |
181 Heap::Space space) { | 267 Chunk* chunk_data = reinterpret_cast<Chunk*>(data); |
182 BIGNUM *bn = TmpBN(); | 268 if (length == 0) { |
183 int len = BN_dec2bn(&bn, str); | 269 const char* zero = "0x0"; |
184 if (len == 0) { | 270 const int kLength = strlen(zero); |
185 return Bigint::null(); | 271 char* result = reinterpret_cast<char*>(allocator(kLength + 1)); |
| 272 ASSERT(result != NULL); |
| 273 memmove(result, zero, kLength); |
| 274 result[kLength] = '\0'; |
| 275 return result; |
186 } | 276 } |
187 ASSERT(bn == TmpBN()); | 277 ASSERT(chunk_data != NULL); |
188 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN(), space)); | |
189 return result.raw(); | |
190 } | |
191 | 278 |
192 | 279 // Compute the number of hex-digits that are needed to represent the |
193 const char* BigintOperations::ToHexCString(const BIGNUM *bn, | 280 // leading bigint-digit. All other digits need exactly kHexCharsPerDigit |
194 uword (*allocator)(intptr_t size)) { | 281 // characters. |
195 char* str = BN_bn2hex(bn); | 282 int leading_hex_digits = 0; |
196 char* to_free = str; | 283 Chunk leading_digit = chunk_data[chunk_length - 1]; |
197 intptr_t neg = 0; | 284 while (leading_digit != 0) { |
198 if (str[0] == '-') { | 285 leading_hex_digits++; |
199 ++str; | 286 leading_digit >>= 4; |
200 neg = 1; | |
201 } | 287 } |
202 if (str[0] == '0' && str[1] != '\0') { | 288 // Sum up the space that is needed for the string-representation. |
203 ++str; | 289 intptr_t required_size = 0; |
| 290 if (is_negative) { |
| 291 required_size++; // For the leading "-". |
204 } | 292 } |
205 intptr_t length = strlen(str) + 3 + neg; | 293 required_size += 2; // For the "0x". |
206 char *result = reinterpret_cast<char*>(allocator(length)); | 294 required_size += leading_hex_digits; |
207 if (neg) { | 295 required_size += (chunk_length - 1) * kHexCharsPerDigit; |
208 result[0] = '-'; | 296 required_size++; // For the trailing '\0'. |
209 result[1] = '0'; | 297 char* result = reinterpret_cast<char*>(allocator(required_size)); |
210 result[2] = 'x'; | 298 // Print the number into the string. |
211 // memcpy would suffice | 299 // Start from the last position. |
212 memmove(result + 3, str, length - 3); | 300 intptr_t pos = required_size - 1; |
213 } else { | 301 result[pos--] = '\0'; |
214 result[0] = '0'; | 302 for (intptr_t i = 0; i < (chunk_length - 1); i++) { |
215 result[1] = 'x'; | 303 // Print all non-leading characters (which are printed with |
216 // memcpy would suffice | 304 // kHexCharsPerDigit characters. |
217 memmove(result + 2, str, length - 2); | 305 Chunk digit = chunk_data[i]; |
| 306 for (int j = 0; j < kHexCharsPerDigit; j++) { |
| 307 result[pos--] = Utils::IntToHexDigit(static_cast<int>(digit & 0xF)); |
| 308 digit >>= 4; |
| 309 } |
218 } | 310 } |
219 OPENSSL_free(to_free); | 311 // Print the leading digit. |
220 return result; | 312 leading_digit = chunk_data[chunk_length - 1]; |
221 } | 313 while (leading_digit != 0) { |
222 | 314 result[pos--] = Utils::IntToHexDigit(static_cast<int>(leading_digit & 0xF)); |
223 | 315 leading_digit >>= 4; |
224 const char* BigintOperations::ToDecCString(const Bigint& bigint, | 316 } |
225 uword (*allocator)(intptr_t size)) { | 317 result[pos--] = 'x'; |
226 return ToDecCString(bigint.BNAddr(), allocator); | 318 result[pos--] = '0'; |
227 } | 319 if (is_negative) { |
228 | 320 result[pos--] = '-'; |
229 | 321 } |
230 const char* BigintOperations::ToDecCString(const BIGNUM *bn, | 322 ASSERT(pos == -1); |
231 uword (*allocator)(intptr_t size)) { | |
232 char* str = BN_bn2dec(bn); | |
233 intptr_t length = strlen(str) + 1; // '\0'-terminated. | |
234 char* result = reinterpret_cast<char*>(allocator(length)); | |
235 memmove(result, str, length); | |
236 OPENSSL_free(str); | |
237 return result; | 323 return result; |
238 } | 324 } |
239 | 325 |
240 | 326 |
241 const char* BigintOperations::ToHexCString(const Bigint& bigint, | 327 const char* BigintOperations::ToHexCString(const Bigint& bigint, |
242 uword (*allocator)(intptr_t size)) { | 328 uword (*allocator)(intptr_t size)) { |
243 return ToHexCString(bigint.BNAddr(), allocator); | 329 NoGCScope no_gc; |
| 330 |
| 331 intptr_t length = bigint.Length(); |
| 332 return ToHexCString(length, |
| 333 bigint.IsNegative(), |
| 334 length ? bigint.ChunkAddr(0) : NULL, |
| 335 allocator); |
244 } | 336 } |
245 | 337 |
246 | 338 |
247 bool BigintOperations::FitsIntoSmi(const Bigint& bigint) { | 339 bool BigintOperations::FitsIntoSmi(const Bigint& bigint) { |
248 ASSERT(!bigint.IsNull()); | 340 intptr_t bigint_length = bigint.Length(); |
249 const BIGNUM *bn = bigint.BNAddr(); | 341 if (bigint_length == 0) { |
250 int bits = BN_num_bits(bn); | |
251 // Special case for kMinValue as the absolute value is 1 bit longer | |
252 // than anything else | |
253 if (bits == Smi::kBits + 1 && BN_abs_is_word(bn, -Smi::kMinValue) | |
254 && bigint.IsNegative()) { | |
255 return true; | 342 return true; |
256 } | 343 } |
257 // All other cases must have no more bits than the size of an Smi | 344 if ((bigint_length == 1) && |
258 if (bits > Smi::kBits) { | 345 (static_cast<size_t>(kDigitBitSize) < |
| 346 (sizeof(intptr_t) * kBitsPerByte))) { |
| 347 return true; |
| 348 } |
| 349 |
| 350 uintptr_t limit; |
| 351 if (bigint.IsNegative()) { |
| 352 limit = static_cast<uintptr_t>(-Smi::kMinValue); |
| 353 } else { |
| 354 limit = static_cast<uintptr_t>(Smi::kMaxValue); |
| 355 } |
| 356 bool bigint_is_greater = false; |
| 357 // Consume the least-significant digits of the bigint. |
| 358 // If bigint_is_greater is set, then the processed sub-part of the bigint is |
| 359 // greater than the corresponding part of the limit. |
| 360 for (int i = 0; i < bigint_length - 1; i++) { |
| 361 Chunk limit_digit = static_cast<Chunk>(limit & kDigitMask); |
| 362 Chunk bigint_digit = bigint.GetChunkAt(i); |
| 363 if (limit_digit < bigint_digit) { |
| 364 bigint_is_greater = true; |
| 365 } else if (limit_digit > bigint_digit) { |
| 366 bigint_is_greater = false; |
| 367 } // else don't change the boolean. |
| 368 limit >>= kDigitBitSize; |
| 369 |
| 370 // Bail out if the bigint is definitely too big. |
| 371 if (limit == 0) { |
| 372 return false; |
| 373 } |
| 374 } |
| 375 Chunk most_significant_digit = bigint.GetChunkAt(bigint_length - 1); |
| 376 if (limit > most_significant_digit) { |
| 377 return true; |
| 378 } |
| 379 if (limit < most_significant_digit) { |
259 return false; | 380 return false; |
260 } | 381 } |
261 return true; | 382 return !bigint_is_greater; |
262 } | 383 } |
263 | 384 |
264 | 385 |
265 RawSmi* BigintOperations::ToSmi(const Bigint& bigint) { | 386 RawSmi* BigintOperations::ToSmi(const Bigint& bigint) { |
266 ASSERT(FitsIntoSmi(bigint)); | 387 ASSERT(FitsIntoSmi(bigint)); |
267 unsigned char bytes[kBitsPerWord / kBitsPerByte]; | |
268 ASSERT(BN_num_bytes(bigint.BNAddr()) <= static_cast<int>(sizeof bytes)); | |
269 int n = BN_bn2bin(bigint.BNAddr(), bytes); | |
270 ASSERT(n >= 0); | |
271 intptr_t value = 0; | 388 intptr_t value = 0; |
272 ASSERT(n <= static_cast<int>(sizeof value)); | 389 for (int i = bigint.Length() - 1; i >= 0; i--) { |
273 for (int i = 0; i < n; ++i) { | 390 value <<= kDigitBitSize; |
274 value <<= 8; | 391 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); |
275 value |= bytes[i]; | |
276 } | 392 } |
277 if (bigint.IsNegative()) { | 393 if (bigint.IsNegative()) { |
278 value = -value; | 394 value = -value; |
279 } | 395 } |
280 return Smi::New(value); | 396 return Smi::New(value); |
281 } | 397 } |
282 | 398 |
283 | 399 |
284 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) { | 400 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) { |
285 // TODO(floitsch/benl): This is a quick and dirty implementation to unblock | 401 // TODO(floitsch/benl): This is a quick and dirty implementation to unblock |
286 // other areas of the code. It does not handle all bit-twiddling correctly. | 402 // other areas of the code. It does not handle all bit-twiddling correctly. |
| 403 const double shift_value = (1 << kDigitBitSize); |
287 double value = 0.0; | 404 double value = 0.0; |
288 for (int i = bigint.NumberOfBits() - 1; i >= 0; --i) { | 405 for (int i = bigint.Length() - 1; i >= 0; i--) { |
289 value *= 2; | 406 value *= shift_value; |
290 value += static_cast<double>(bigint.Bit(i)); | 407 value += static_cast<double>(bigint.GetChunkAt(i)); |
291 } | 408 } |
292 if (bigint.IsNegative()) { | 409 if (bigint.IsNegative()) { |
293 value = -value; | 410 value = -value; |
294 } | 411 } |
295 return Double::New(value); | 412 return Double::New(value); |
296 } | 413 } |
297 | 414 |
298 | 415 |
299 bool BigintOperations::FitsIntoInt64(const Bigint& bigint) { | 416 bool BigintOperations::FitsIntoMint(const Bigint& bigint) { |
300 const BIGNUM *bn = bigint.BNAddr(); | 417 intptr_t bigint_length = bigint.Length(); |
301 int bits = BN_num_bits(bn); | 418 if (bigint_length == 0) { |
302 if (bits <= 63) return true; | 419 return true; |
303 if (bits > 64) return false; | |
304 if (!bigint.IsNegative()) return false; | |
305 // Special case for negative values, since Int64 representation may lose | |
306 // one bit. | |
307 ASSERT(bigint.Bit(63) != 0); | |
308 for (int i = 0; i < 63; i++) { | |
309 // Verify that all 63 least significant bits are 0. | |
310 if (bigint.Bit(i) != 0) return false; | |
311 } | 420 } |
312 return true; | 421 if ((bigint_length < 3) && |
| 422 (static_cast<size_t>(kDigitBitSize) < |
| 423 (sizeof(intptr_t) * kBitsPerByte))) { |
| 424 return true; |
| 425 } |
| 426 |
| 427 uint64_t limit; |
| 428 if (bigint.IsNegative()) { |
| 429 limit = static_cast<uint64_t>(Mint::kMinValue); |
| 430 } else { |
| 431 limit = static_cast<uint64_t>(Mint::kMaxValue); |
| 432 } |
| 433 bool bigint_is_greater = false; |
| 434 // Consume the least-significant digits of the bigint. |
| 435 // If bigint_is_greater is set, then the processed sub-part of the bigint is |
| 436 // greater than the corresponding part of the limit. |
| 437 for (int i = 0; i < bigint_length - 1; i++) { |
| 438 Chunk limit_digit = static_cast<Chunk>(limit & kDigitMask); |
| 439 Chunk bigint_digit = bigint.GetChunkAt(i); |
| 440 if (limit_digit < bigint_digit) { |
| 441 bigint_is_greater = true; |
| 442 } else if (limit_digit > bigint_digit) { |
| 443 bigint_is_greater = false; |
| 444 } // else don't change the boolean. |
| 445 limit >>= kDigitBitSize; |
| 446 |
| 447 // Bail out if the bigint is definitely too big. |
| 448 if (limit == 0) { |
| 449 return false; |
| 450 } |
| 451 } |
| 452 Chunk most_significant_digit = bigint.GetChunkAt(bigint_length - 1); |
| 453 if (limit > most_significant_digit) { |
| 454 return true; |
| 455 } |
| 456 if (limit < most_significant_digit) { |
| 457 return false; |
| 458 } |
| 459 return !bigint_is_greater; |
313 } | 460 } |
314 | 461 |
315 | 462 |
316 uint64_t BigintOperations::AbsToUint64(const Bigint& bigint) { | 463 uint64_t BigintOperations::AbsToUint64(const Bigint& bigint) { |
317 unsigned char bytes[8]; | |
318 ASSERT(BN_num_bytes(bigint.BNAddr()) <= static_cast<int>(sizeof bytes)); | |
319 int n = BN_bn2bin(bigint.BNAddr(), bytes); | |
320 ASSERT(n >= 0); | |
321 uint64_t value = 0; | 464 uint64_t value = 0; |
322 ASSERT(n <= static_cast<int>(sizeof value)); | 465 for (int i = bigint.Length() - 1; i >= 0; i--) { |
323 for (int i = 0; i < n; ++i) { | 466 value <<= kDigitBitSize; |
324 value <<= 8; | 467 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); |
325 value |= bytes[i]; | |
326 } | 468 } |
327 return value; | 469 return value; |
328 } | 470 } |
329 | 471 |
330 | 472 |
331 int64_t BigintOperations::ToInt64(const Bigint& bigint) { | 473 int64_t BigintOperations::ToMint(const Bigint& bigint) { |
332 ASSERT(FitsIntoInt64(bigint)); | 474 ASSERT(FitsIntoMint(bigint)); |
333 int64_t value = AbsToUint64(bigint); | 475 int64_t value = AbsToUint64(bigint); |
334 if (bigint.IsNegative()) { | 476 if (bigint.IsNegative()) { |
335 value = -value; | 477 value = -value; |
336 } | 478 } |
337 return value; | 479 return value; |
338 } | 480 } |
339 | 481 |
340 | 482 |
341 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) { | 483 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) { |
342 const BIGNUM *bn = bigint.BNAddr(); | |
343 if (bigint.IsNegative()) return false; | 484 if (bigint.IsNegative()) return false; |
344 int bits = BN_num_bits(bn); | 485 intptr_t b_length = bigint.Length(); |
345 if (bits > 64) return false; | 486 int num_bits = CountBits(bigint.GetChunkAt(b_length - 1)); |
| 487 num_bits += (kDigitBitSize * (b_length - 1)); |
| 488 if (num_bits > 64) return false; |
346 return true; | 489 return true; |
347 } | 490 } |
348 | 491 |
349 | 492 |
350 uint64_t BigintOperations::ToUint64(const Bigint& bigint) { | 493 uint64_t BigintOperations::ToUint64(const Bigint& bigint) { |
351 ASSERT(FitsIntoUint64(bigint)); | 494 ASSERT(FitsIntoUint64(bigint)); |
352 return AbsToUint64(bigint); | 495 return AbsToUint64(bigint); |
353 } | 496 } |
354 | 497 |
355 | 498 |
356 RawBigint* BigintOperations::Add(const Bigint& a, const Bigint& b) { | 499 RawBigint* BigintOperations::Multiply(const Bigint& a, const Bigint& b) { |
357 int status = BN_add(TmpBN(), a.BNAddr(), b.BNAddr()); | 500 ASSERT(IsClamped(a)); |
358 if (status == 0) { | 501 ASSERT(IsClamped(b)); |
359 GrowableArray<const Object*> exception_arguments; | 502 |
360 exception_arguments.Add( | 503 intptr_t a_length = a.Length(); |
361 &Object::ZoneHandle(String::New("BigintOperations::Add"))); | 504 intptr_t b_length = b.Length(); |
362 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); | 505 intptr_t result_length = a_length + b_length; |
363 } | 506 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
364 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); | 507 |
| 508 if (a.IsNegative() != b.IsNegative()) { |
| 509 result.ToggleSign(); |
| 510 } |
| 511 |
| 512 // Comba multiplication: compute each column separately. |
| 513 // Example: r = a2a1a0 * b2b1b0. |
| 514 // r = 1 * a0b0 + |
| 515 // 10 * (a1b0 + a0b1) + |
| 516 // 100 * (a2b0 + a1b1 + a0b2) + |
| 517 // 1000 * (a2b1 + a1b2) + |
| 518 // 10000 * a2b2 |
| 519 // |
| 520 // Each column will be accumulated in an integer of type DoubleChunk. We |
| 521 // must guarantee that the column-sum will not overflow. |
| 522 // |
| 523 // In the worst case we have to accumulate k = Min(a.length, b.length) |
| 524 // products plus the carry from the previous round. |
| 525 // Each bigint-digit is smaller than beta = 2^kDigitBitSize. |
| 526 // Each product is at most (beta - 1)^2. |
| 527 // If we want to use Comba multiplication the following condition must hold: |
| 528 // k * (beta - 1)^2 + (2^(kDoubleChunkBitSize - kDigitBitSize) - 1) < |
| 529 // 2^kDoubleChunkBitSize. |
| 530 const DoubleChunk square = |
| 531 static_cast<DoubleChunk>(kDigitMaxValue) * kDigitMaxValue; |
| 532 const DoubleChunk kDoubleChunkMaxValue = static_cast<DoubleChunk>(-1); |
| 533 const DoubleChunk left_over_carry = kDoubleChunkMaxValue >> kDigitBitSize; |
| 534 const intptr_t kMaxDigits = (kDoubleChunkMaxValue - left_over_carry) / square; |
| 535 if (Utils::Minimum(a_length, b_length) > kMaxDigits) { |
| 536 UNIMPLEMENTED(); |
| 537 } |
| 538 |
| 539 DoubleChunk accumulator = 0; // Accumulates the result of one column. |
| 540 for (intptr_t i = 0; i < result_length; i++) { |
| 541 // Example: r = a2a1a0 * b2b1b0. |
| 542 // For i == 0, compute a0b0. |
| 543 // i == 1, a1b0 + a0b1 + overflow from i == 0. |
| 544 // i == 2, a2b0 + a1b1 + a0b2 + overflow from i == 1. |
| 545 // ... |
| 546 // The indices into a and b are such that their sum equals i. |
| 547 intptr_t a_index = Utils::Minimum(a_length - 1, i); |
| 548 intptr_t b_index = i - a_index; |
| 549 ASSERT(a_index + b_index == i); |
| 550 |
| 551 // Instead of testing for a_index >= 0 && b_index < b_length we compute the |
| 552 // number of iterations first. |
| 553 intptr_t iterations = Utils::Minimum(b_length - b_index, a_index + 1); |
| 554 for (intptr_t j = 0; j < iterations; j++) { |
| 555 DoubleChunk chunk_a = a.GetChunkAt(a_index); |
| 556 DoubleChunk chunk_b = b.GetChunkAt(b_index); |
| 557 accumulator += chunk_a * chunk_b; |
| 558 a_index--; |
| 559 b_index++; |
| 560 } |
| 561 result.SetChunkAt(i, static_cast<Chunk>(accumulator & kDigitMask)); |
| 562 accumulator >>= kDigitBitSize; |
| 563 } |
| 564 ASSERT(accumulator == 0); |
| 565 |
| 566 Clamp(result); |
365 return result.raw(); | 567 return result.raw(); |
366 } | 568 } |
367 | 569 |
368 | 570 |
369 RawBigint* BigintOperations::Subtract(const Bigint& a, const Bigint& b) { | |
370 int status = BN_sub(TmpBN(), a.BNAddr(), b.BNAddr()); | |
371 if (status == 0) { | |
372 GrowableArray<const Object*> exception_arguments; | |
373 exception_arguments.Add( | |
374 &Object::ZoneHandle(String::New("BigintOperations::Subtract"))); | |
375 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); | |
376 } | |
377 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); | |
378 return result.raw(); | |
379 } | |
380 | |
381 | |
382 RawBigint* BigintOperations::Multiply(const Bigint& a, const Bigint& b) { | |
383 int status = BN_mul(TmpBN(), a.BNAddr(), b.BNAddr(), TmpBNCtx()); | |
384 if (status == 0) { | |
385 GrowableArray<const Object*> exception_arguments; | |
386 exception_arguments.Add( | |
387 &Object::ZoneHandle(String::New("BigintOperations::Multiply"))); | |
388 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); | |
389 } | |
390 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); | |
391 return result.raw(); | |
392 } | |
393 | |
394 | |
395 RawBigint* BigintOperations::Divide(const Bigint& a, const Bigint& b) { | 571 RawBigint* BigintOperations::Divide(const Bigint& a, const Bigint& b) { |
396 int status = BN_div(TmpBN(), NULL, a.BNAddr(), b.BNAddr(), TmpBNCtx()); | 572 Bigint& quotient = Bigint::Handle(); |
397 if (status == 0) { | 573 Bigint& remainder = Bigint::Handle(); |
398 GrowableArray<const Object*> exception_arguments; | 574 DivideRemainder(a, b, "ient, &remainder); |
399 exception_arguments.Add( | |
400 &Object::ZoneHandle(String::New("BigintOperations::Divide"))); | |
401 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); | |
402 } | |
403 const Bigint& quotient = Bigint::Handle(Bigint::New(TmpBN())); | |
404 return quotient.raw(); | 575 return quotient.raw(); |
405 } | 576 } |
406 | 577 |
407 | 578 |
408 RawBigint* BigintOperations::Modulo(const Bigint& a, const Bigint& b) { | 579 RawBigint* BigintOperations::Modulo(const Bigint& a, const Bigint& b) { |
409 int status = BN_nnmod(TmpBN(), a.BNAddr(), b.BNAddr(), TmpBNCtx()); | 580 Bigint& quotient = Bigint::Handle(); |
410 if (status == 0) { | 581 Bigint& modulo = Bigint::Handle(); |
411 GrowableArray<const Object*> exception_arguments; | 582 DivideRemainder(a, b, "ient, &modulo); |
412 exception_arguments.Add( | |
413 &Object::ZoneHandle(String::New("BigintOperations::Modulo"))); | |
414 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); | |
415 } | |
416 const Bigint& modulo = Bigint::Handle(Bigint::New(TmpBN())); | |
417 return modulo.raw(); | 583 return modulo.raw(); |
418 } | 584 } |
419 | 585 |
420 | 586 |
421 RawBigint* BigintOperations::Remainder(const Bigint& a, const Bigint& b) { | 587 RawBigint* BigintOperations::Remainder(const Bigint& a, const Bigint& b) { |
422 int status = BN_div(NULL, TmpBN(), a.BNAddr(), b.BNAddr(), TmpBNCtx()); | 588 Bigint& quotient = Bigint::Handle(); |
423 if (status == 0) { | 589 Bigint& remainder = Bigint::Handle(); |
424 GrowableArray<const Object*> exception_arguments; | 590 DivideRemainder(a, b, "ient, &remainder); |
425 exception_arguments.Add( | |
426 &Object::ZoneHandle(String::New("BigintOperations::Remainder"))); | |
427 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); | |
428 } | |
429 const Bigint& remainder = Bigint::Handle(Bigint::New(TmpBN())); | |
430 return remainder.raw(); | 591 return remainder.raw(); |
431 } | 592 } |
432 | 593 |
433 | 594 |
434 RawBigint* BigintOperations::ShiftLeft(const Bigint& bigint, intptr_t amount) { | 595 RawBigint* BigintOperations::ShiftLeft(const Bigint& bigint, intptr_t amount) { |
435 int status = BN_lshift(TmpBN(), bigint.BNAddr(), amount); | 596 ASSERT(IsClamped(bigint)); |
436 if (status == 0) { | 597 ASSERT(amount >= 0); |
437 GrowableArray<const Object*> exception_arguments; | 598 intptr_t bigint_length = bigint.Length(); |
438 exception_arguments.Add( | 599 if (bigint.IsZero()) { |
439 &Object::ZoneHandle(String::New("BigintOperations::ShiftLeft"))); | 600 return Zero(); |
440 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); | 601 } |
441 } | 602 // TODO(floitsch): can we reuse the input? |
442 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); | 603 if (amount == 0) { |
443 return result.raw(); | 604 return Copy(bigint); |
| 605 } |
| 606 intptr_t digit_shift = amount / kDigitBitSize; |
| 607 intptr_t bit_shift = amount % kDigitBitSize; |
| 608 if (bit_shift == 0) { |
| 609 const Bigint& result = |
| 610 Bigint::Handle(Bigint::Allocate(bigint_length + digit_shift)); |
| 611 for (intptr_t i = 0; i < digit_shift; i++) { |
| 612 result.SetChunkAt(i, 0); |
| 613 } |
| 614 for (intptr_t i = 0; i < bigint_length; i++) { |
| 615 result.SetChunkAt(i + digit_shift, bigint.GetChunkAt(i)); |
| 616 } |
| 617 if (bigint.IsNegative()) { |
| 618 result.ToggleSign(); |
| 619 } |
| 620 return result.raw(); |
| 621 } else { |
| 622 const Bigint& result = |
| 623 Bigint::Handle(Bigint::Allocate(bigint_length + digit_shift + 1)); |
| 624 for (intptr_t i = 0; i < digit_shift; i++) { |
| 625 result.SetChunkAt(i, 0); |
| 626 } |
| 627 Chunk carry = 0; |
| 628 for (intptr_t i = 0; i < bigint_length; i++) { |
| 629 Chunk digit = bigint.GetChunkAt(i); |
| 630 Chunk shifted_digit = ((digit << bit_shift) & kDigitMask) + carry; |
| 631 result.SetChunkAt(i + digit_shift, shifted_digit); |
| 632 carry = digit >> (kDigitBitSize - bit_shift); |
| 633 } |
| 634 result.SetChunkAt(bigint_length + digit_shift, carry); |
| 635 if (bigint.IsNegative()) { |
| 636 result.ToggleSign(); |
| 637 } |
| 638 Clamp(result); |
| 639 return result.raw(); |
| 640 } |
444 } | 641 } |
445 | 642 |
446 | 643 |
447 RawBigint* BigintOperations::ShiftRight(const Bigint& bigint, intptr_t amount) { | 644 RawBigint* BigintOperations::ShiftRight(const Bigint& bigint, intptr_t amount) { |
| 645 ASSERT(IsClamped(bigint)); |
448 ASSERT(amount >= 0); | 646 ASSERT(amount >= 0); |
449 int status = BN_rshift(TmpBN(), bigint.BNAddr(), amount); | 647 intptr_t bigint_length = bigint.Length(); |
450 if (status == 0) { | 648 if (bigint.IsZero()) { |
451 GrowableArray<const Object*> exception_arguments; | 649 return Zero(); |
452 exception_arguments.Add( | 650 } |
453 &Object::ZoneHandle(String::New("BigintOperations::ShiftRight"))); | 651 // TODO(floitsch): can we reuse the input? |
454 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); | 652 if (amount == 0) { |
455 } | 653 return Copy(bigint); |
456 // OpenSSL doesn't take account of sign when shifting - this fixes it. | 654 } |
| 655 intptr_t digit_shift = amount / kDigitBitSize; |
| 656 intptr_t bit_shift = amount % kDigitBitSize; |
| 657 if (digit_shift >= bigint_length) { |
| 658 return bigint.IsNegative() ? MinusOne() : Zero(); |
| 659 } |
| 660 |
| 661 const Bigint& result = |
| 662 Bigint::Handle(Bigint::Allocate(bigint_length - digit_shift)); |
| 663 if (bit_shift == 0) { |
| 664 for (intptr_t i = 0; i < bigint_length - digit_shift; i++) { |
| 665 result.SetChunkAt(i, bigint.GetChunkAt(i + digit_shift)); |
| 666 } |
| 667 } else { |
| 668 Chunk carry = 0; |
| 669 for (intptr_t i = bigint_length - 1; i >= digit_shift; i--) { |
| 670 Chunk digit = bigint.GetChunkAt(i); |
| 671 Chunk shifted_digit = (digit >> bit_shift) + carry; |
| 672 result.SetChunkAt(i - digit_shift, shifted_digit); |
| 673 carry = (digit << (kDigitBitSize - bit_shift)) & kDigitMask; |
| 674 } |
| 675 Clamp(result); |
| 676 } |
| 677 |
457 if (bigint.IsNegative()) { | 678 if (bigint.IsNegative()) { |
458 for (intptr_t i = 0; i < amount; ++i) { | 679 result.ToggleSign(); |
459 if (bigint.IsBitSet(i)) { | 680 // If the input is negative then the result needs to be rounded down. |
460 int status = BN_sub_word(TmpBN(), 1); | 681 // Example: -5 >> 2 => -2 |
461 ASSERT(status == 1); | 682 bool needs_rounding = false; |
| 683 for (intptr_t i = 0; i < digit_shift; i++) { |
| 684 if (bigint.GetChunkAt(i) != 0) { |
| 685 needs_rounding = true; |
462 break; | 686 break; |
463 } | 687 } |
464 } | 688 } |
465 } | 689 if (!needs_rounding && (bit_shift > 0)) { |
466 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); | 690 Chunk digit = bigint.GetChunkAt(digit_shift); |
| 691 needs_rounding = (digit << (kChunkBitSize - bit_shift)) != 0; |
| 692 } |
| 693 if (needs_rounding) { |
| 694 Bigint& one = Bigint::Handle(One()); |
| 695 return Subtract(result, one); |
| 696 } |
| 697 } |
| 698 |
467 return result.raw(); | 699 return result.raw(); |
468 } | 700 } |
469 | 701 |
470 /* Bit operations are complicated by negatives: BIGNUMs don't use 2's | 702 |
471 * complement, but instead store the absolute value and a sign | 703 RawBigint* BigintOperations::BitAnd(const Bigint& a, const Bigint& b) { |
472 * indicator. However bit operations are defined on 2's complement | 704 ASSERT(IsClamped(a)); |
473 * representations. This function handles the necessary | 705 ASSERT(IsClamped(b)); |
474 * invert-and-carry operations to deal with the fact that -x = ~x + 1 | 706 |
475 * both on the operands and result. The actual operation performed is | 707 if (a.IsZero() || b.IsZero()) { |
476 * specified by the truth table |tt|, which is in the order of input | 708 return Zero(); |
477 * bits (00, 01, 10, 11). | 709 } |
478 */ | 710 if (a.IsNegative() && !b.IsNegative()) { |
479 RawBigint* BigintOperations::BitTT(const Bigint& a, const Bigint& b, | 711 return BitAnd(b, a); |
480 bool tt[4]) { | 712 } |
481 BN_zero(TmpBN()); | 713 if ((a.IsNegative() == b.IsNegative()) && (a.Length() < b.Length())) { |
482 int n; | 714 return BitAnd(b, a); |
483 int rflip = 0; | 715 } |
484 int rborrow = 0; | 716 |
485 // There's probably a clever way to figure out why these are what | 717 intptr_t a_length = a.Length(); |
486 // they are, but I confess I worked them out pragmatically. | 718 intptr_t b_length = b.Length(); |
487 if (a.IsNegative() && b.IsNegative()) { | 719 intptr_t min_length = Utils::Minimum(a_length, b_length); |
488 if (tt[3]) { | 720 intptr_t max_length = Utils::Maximum(a_length, b_length); |
489 rflip = -1; | 721 if (!b.IsNegative()) { |
490 rborrow = -1; | 722 ASSERT(!a.IsNegative()); |
491 } | 723 intptr_t result_length = min_length; |
492 if (tt[2] != tt[3]) { | 724 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
493 n = Utils::Maximum(a.NumberOfBits(), b.NumberOfBits()); | 725 |
| 726 for (intptr_t i = 0; i < min_length; i++) { |
| 727 result.SetChunkAt(i, a.GetChunkAt(i) & b.GetChunkAt(i)); |
| 728 } |
| 729 Clamp(result); |
| 730 return result.raw(); |
| 731 } |
| 732 |
| 733 // Bigints encode negative values by storing the absolute value and the sign |
| 734 // separately. To do bit operations we need to simulate numbers that are |
| 735 // implemented as two's complement. |
| 736 // The negation of a positive number x would be encoded as follows in |
| 737 // two's complement: n = ~(x - 1). |
| 738 // The inverse transformation is hence (~n) + 1. |
| 739 |
| 740 if (!a.IsNegative()) { |
| 741 ASSERT(b.IsNegative()); |
| 742 // The result will be positive. |
| 743 intptr_t result_length = a_length; |
| 744 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
| 745 Chunk borrow = 1; |
| 746 for (intptr_t i = 0; i < min_length; i++) { |
| 747 Chunk b_digit = b.GetChunkAt(i) - borrow; |
| 748 result.SetChunkAt(i, a.GetChunkAt(i) & (~b_digit) & kDigitMask); |
| 749 borrow = b_digit >> (kChunkBitSize - 1); |
| 750 } |
| 751 for (intptr_t i = min_length; i < a_length; i++) { |
| 752 result.SetChunkAt(i, a.GetChunkAt(i) & (kDigitMaxValue - borrow)); |
| 753 borrow = 0; |
| 754 } |
| 755 Clamp(result); |
| 756 return result.raw(); |
| 757 } |
| 758 |
| 759 ASSERT(a.IsNegative()); |
| 760 ASSERT(b.IsNegative()); |
| 761 // The result will be negative. |
| 762 // We need to convert a and b to two's complement. Do the bit-operation there, |
| 763 // and transform the resulting bits from two's complement back to separated |
| 764 // magnitude and sign. |
| 765 // a & b is therefore computed as ~((~(a - 1)) & (~(b - 1))) + 1 which is |
| 766 // equal to ((a-1) | (b-1)) + 1. |
| 767 intptr_t result_length = max_length + 1; |
| 768 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
| 769 result.ToggleSign(); |
| 770 Chunk a_borrow = 1; |
| 771 Chunk b_borrow = 1; |
| 772 Chunk result_carry = 1; |
| 773 ASSERT(a_length >= b_length); |
| 774 for (intptr_t i = 0; i < b_length; i++) { |
| 775 Chunk a_digit = a.GetChunkAt(i) - a_borrow; |
| 776 Chunk b_digit = b.GetChunkAt(i) - b_borrow; |
| 777 Chunk result_chunk = ((a_digit | b_digit) & kDigitMask) + result_carry; |
| 778 result.SetChunkAt(i, result_chunk & kDigitMask); |
| 779 a_borrow = a_digit >> (kChunkBitSize - 1); |
| 780 b_borrow = b_digit >> (kChunkBitSize - 1); |
| 781 result_carry = result_chunk >> kDigitBitSize; |
| 782 } |
| 783 for (intptr_t i = b_length; i < a_length; i++) { |
| 784 Chunk a_digit = a.GetChunkAt(i) - a_borrow; |
| 785 Chunk b_digit = -b_borrow; |
| 786 Chunk result_chunk = ((a_digit | b_digit) & kDigitMask) + result_carry; |
| 787 result.SetChunkAt(i, result_chunk & kDigitMask); |
| 788 a_borrow = a_digit >> (kChunkBitSize - 1); |
| 789 b_borrow = 0; |
| 790 result_carry = result_chunk >> kDigitBitSize; |
| 791 } |
| 792 Chunk a_digit = -a_borrow; |
| 793 Chunk b_digit = -b_borrow; |
| 794 Chunk result_chunk = ((a_digit | b_digit) & kDigitMask) + result_carry; |
| 795 result.SetChunkAt(a_length, result_chunk & kDigitMask); |
| 796 Clamp(result); |
| 797 return result.raw(); |
| 798 } |
| 799 |
| 800 |
| 801 RawBigint* BigintOperations::BitOr(const Bigint& a, const Bigint& b) { |
| 802 ASSERT(IsClamped(a)); |
| 803 ASSERT(IsClamped(b)); |
| 804 |
| 805 if (a.IsNegative() && !b.IsNegative()) { |
| 806 return BitOr(b, a); |
| 807 } |
| 808 if ((a.IsNegative() == b.IsNegative()) && (a.Length() < b.Length())) { |
| 809 return BitOr(b, a); |
| 810 } |
| 811 |
| 812 intptr_t a_length = a.Length(); |
| 813 intptr_t b_length = b.Length(); |
| 814 intptr_t min_length = Utils::Minimum(a_length, b_length); |
| 815 intptr_t max_length = Utils::Maximum(a_length, b_length); |
| 816 if (!b.IsNegative()) { |
| 817 ASSERT(!a.IsNegative()); |
| 818 intptr_t result_length = max_length; |
| 819 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
| 820 |
| 821 ASSERT(a_length >= b_length); |
| 822 for (intptr_t i = 0; i < b_length; i++) { |
| 823 result.SetChunkAt(i, a.GetChunkAt(i) | b.GetChunkAt(i)); |
| 824 } |
| 825 for (intptr_t i = b_length; i < a_length; i++) { |
| 826 result.SetChunkAt(i, a.GetChunkAt(i)); |
| 827 } |
| 828 return result.raw(); |
| 829 } |
| 830 |
| 831 // Bigints encode negative values by storing the absolute value and the sign |
| 832 // separately. To do bit operations we need to simulate numbers that are |
| 833 // implemented as two's complement. |
| 834 // The negation of a positive number x would be encoded as follows in |
| 835 // two's complement: n = ~(x - 1). |
| 836 // The inverse transformation is hence (~n) + 1. |
| 837 |
| 838 if (!a.IsNegative()) { |
| 839 ASSERT(b.IsNegative()); |
| 840 if (a.IsZero()) { |
| 841 return Copy(b); |
| 842 } |
| 843 // The result will be negative. |
| 844 // We need to convert b to two's complement. Do the bit-operation there, |
| 845 // and transform the resulting bits from two's complement back to separated |
| 846 // magnitude and sign. |
| 847 // a | b is therefore computed as ~((a & (~(b - 1))) + 1 which is |
| 848 // equal to ((~a) & (b-1)) + 1. |
| 849 intptr_t result_length = b_length; |
| 850 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
| 851 result.ToggleSign(); |
| 852 Chunk borrow = 1; |
| 853 Chunk result_carry = 1; |
| 854 for (intptr_t i = 0; i < min_length; i++) { |
| 855 Chunk a_digit = a.GetChunkAt(i); |
| 856 Chunk b_digit = b.GetChunkAt(i) - borrow; |
| 857 Chunk result_digit = ((~a_digit) & b_digit & kDigitMask) + result_carry; |
| 858 result.SetChunkAt(i, result_digit & kDigitMask); |
| 859 borrow = b_digit >> (kChunkBitSize - 1); |
| 860 result_carry = result_digit >> kDigitBitSize; |
| 861 } |
| 862 ASSERT(result_carry == 0); |
| 863 for (intptr_t i = min_length; i < b_length; i++) { |
| 864 Chunk b_digit = b.GetChunkAt(i) - borrow; |
| 865 Chunk result_digit = (b_digit & kDigitMask) + result_carry; |
| 866 result.SetChunkAt(i, result_digit & kDigitMask); |
| 867 borrow = b_digit >> (kChunkBitSize - 1); |
| 868 result_carry = result_digit >> kDigitBitSize; |
| 869 } |
| 870 ASSERT(result_carry == 0); |
| 871 Clamp(result); |
| 872 return result.raw(); |
| 873 } |
| 874 |
| 875 ASSERT(a.IsNegative()); |
| 876 ASSERT(b.IsNegative()); |
| 877 // The result will be negative. |
| 878 // We need to convert a and b to two's complement. Do the bit-operation there, |
| 879 // and transform the resulting bits from two's complement back to separated |
| 880 // magnitude and sign. |
| 881 // a & b is therefore computed as ~((~(a - 1)) | (~(b - 1))) + 1 which is |
| 882 // equal to ((a-1) & (b-1)) + 1. |
| 883 intptr_t result_length = min_length + 1; |
| 884 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
| 885 result.ToggleSign(); |
| 886 Chunk a_borrow = 1; |
| 887 Chunk b_borrow = 1; |
| 888 Chunk result_carry = 1; |
| 889 ASSERT(a_length >= b_length); |
| 890 for (intptr_t i = 0; i < b_length; i++) { |
| 891 Chunk a_digit = a.GetChunkAt(i) - a_borrow; |
| 892 Chunk b_digit = b.GetChunkAt(i) - b_borrow; |
| 893 Chunk result_chunk = ((a_digit & b_digit) & kDigitMask) + result_carry; |
| 894 result.SetChunkAt(i, result_chunk & kDigitMask); |
| 895 a_borrow = a_digit >> (kChunkBitSize - 1); |
| 896 b_borrow = b_digit >> (kChunkBitSize - 1); |
| 897 result_carry = result_chunk >> kDigitBitSize; |
| 898 } |
| 899 result.SetChunkAt(a_length, result_carry); |
| 900 Clamp(result); |
| 901 return result.raw(); |
| 902 } |
| 903 |
| 904 |
| 905 RawBigint* BigintOperations::BitXor(const Bigint& a, const Bigint& b) { |
| 906 ASSERT(IsClamped(a)); |
| 907 ASSERT(IsClamped(b)); |
| 908 |
| 909 if (a.IsZero()) { |
| 910 return Copy(b); |
| 911 } |
| 912 if (b.IsZero()) { |
| 913 return Copy(a); |
| 914 } |
| 915 if (a.IsNegative() && !b.IsNegative()) { |
| 916 return BitXor(b, a); |
| 917 } |
| 918 if ((a.IsNegative() == b.IsNegative()) && (a.Length() < b.Length())) { |
| 919 return BitXor(b, a); |
| 920 } |
| 921 |
| 922 intptr_t a_length = a.Length(); |
| 923 intptr_t b_length = b.Length(); |
| 924 intptr_t min_length = Utils::Minimum(a_length, b_length); |
| 925 intptr_t max_length = Utils::Maximum(a_length, b_length); |
| 926 if (!b.IsNegative()) { |
| 927 ASSERT(!a.IsNegative()); |
| 928 intptr_t result_length = max_length; |
| 929 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
| 930 |
| 931 ASSERT(a_length >= b_length); |
| 932 for (intptr_t i = 0; i < b_length; i++) { |
| 933 result.SetChunkAt(i, a.GetChunkAt(i) ^ b.GetChunkAt(i)); |
| 934 } |
| 935 for (intptr_t i = b_length; i < a_length; i++) { |
| 936 result.SetChunkAt(i, a.GetChunkAt(i)); |
| 937 } |
| 938 Clamp(result); |
| 939 return result.raw(); |
| 940 } |
| 941 |
| 942 // Bigints encode negative values by storing the absolute value and the sign |
| 943 // separately. To do bit operations we need to simulate numbers that are |
| 944 // implemented as two's complement. |
| 945 // The negation of a positive number x would be encoded as follows in |
| 946 // two's complement: n = ~(x - 1). |
| 947 // The inverse transformation is hence (~n) + 1. |
| 948 |
| 949 if (!a.IsNegative()) { |
| 950 ASSERT(b.IsNegative()); |
| 951 // The result will be negative. |
| 952 // We need to convert b to two's complement. Do the bit-operation there, |
| 953 // and transform the resulting bits from two's complement back to separated |
| 954 // magnitude and sign. |
| 955 // a ^ b is therefore computed as ~((a ^ (~(b - 1))) + 1. |
| 956 intptr_t result_length = max_length + 1; |
| 957 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
| 958 result.ToggleSign(); |
| 959 Chunk borrow = 1; |
| 960 Chunk result_carry = 1; |
| 961 for (intptr_t i = 0; i < min_length; i++) { |
| 962 Chunk a_digit = a.GetChunkAt(i); |
| 963 Chunk b_digit = b.GetChunkAt(i) - borrow; |
| 964 Chunk result_digit = |
| 965 ((~(a_digit ^ ~b_digit)) & kDigitMask) + result_carry; |
| 966 result.SetChunkAt(i, result_digit & kDigitMask); |
| 967 borrow = b_digit >> (kChunkBitSize - 1); |
| 968 result_carry = result_digit >> kDigitBitSize; |
| 969 } |
| 970 for (intptr_t i = min_length; i < a_length; i++) { |
| 971 Chunk a_digit = a.GetChunkAt(i); |
| 972 Chunk b_digit = -borrow; |
| 973 Chunk result_digit = |
| 974 ((~(a_digit ^ ~b_digit)) & kDigitMask) + result_carry; |
| 975 result.SetChunkAt(i, result_digit & kDigitMask); |
| 976 borrow = b_digit >> (kChunkBitSize - 1); |
| 977 result_carry = result_digit >> kDigitBitSize; |
| 978 } |
| 979 for (intptr_t i = min_length; i < b_length; i++) { |
| 980 // a_digit = 0. |
| 981 Chunk b_digit = b.GetChunkAt(i) - borrow; |
| 982 Chunk result_digit = (b_digit & kDigitMask) + result_carry; |
| 983 result.SetChunkAt(i, result_digit & kDigitMask); |
| 984 borrow = b_digit >> (kChunkBitSize - 1); |
| 985 result_carry = result_digit >> kDigitBitSize; |
| 986 } |
| 987 result.SetChunkAt(max_length, result_carry); |
| 988 Clamp(result); |
| 989 return result.raw(); |
| 990 } |
| 991 |
| 992 ASSERT(a.IsNegative()); |
| 993 ASSERT(b.IsNegative()); |
| 994 // The result will be positive. |
| 995 // We need to convert a and b to two's complement, do the bit-operation there, |
| 996 // and simply store the result. |
| 997 // a ^ b is therefore computed as (~(a - 1)) ^ (~(b - 1)). |
| 998 intptr_t result_length = max_length; |
| 999 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
| 1000 Chunk a_borrow = 1; |
| 1001 Chunk b_borrow = 1; |
| 1002 ASSERT(a_length >= b_length); |
| 1003 for (intptr_t i = 0; i < b_length; i++) { |
| 1004 Chunk a_digit = a.GetChunkAt(i) - a_borrow; |
| 1005 Chunk b_digit = b.GetChunkAt(i) - b_borrow; |
| 1006 Chunk result_chunk = (~a_digit) ^ (~b_digit); |
| 1007 result.SetChunkAt(i, result_chunk & kDigitMask); |
| 1008 a_borrow = a_digit >> (kChunkBitSize - 1); |
| 1009 b_borrow = b_digit >> (kChunkBitSize - 1); |
| 1010 } |
| 1011 ASSERT(b_borrow == 0); |
| 1012 for (intptr_t i = b_length; i < a_length; i++) { |
| 1013 Chunk a_digit = a.GetChunkAt(i) - a_borrow; |
| 1014 result.SetChunkAt(i, (~a_digit) & kDigitMask); |
| 1015 a_borrow = a_digit >> (kChunkBitSize - 1); |
| 1016 } |
| 1017 ASSERT(a_borrow == 0); |
| 1018 Clamp(result); |
| 1019 return result.raw(); |
| 1020 } |
| 1021 |
| 1022 |
| 1023 RawBigint* BigintOperations::BitNot(const Bigint& bigint) { |
| 1024 if (bigint.IsZero()) { |
| 1025 return MinusOne(); |
| 1026 } |
| 1027 const Bigint& one_bigint = Bigint::Handle(One()); |
| 1028 if (bigint.IsNegative()) { |
| 1029 return UnsignedSubtract(bigint, one_bigint); |
| 1030 } else { |
| 1031 const Bigint& result = Bigint::Handle(UnsignedAdd(bigint, one_bigint)); |
| 1032 result.ToggleSign(); |
| 1033 return result.raw(); |
| 1034 } |
| 1035 } |
| 1036 |
| 1037 |
| 1038 int BigintOperations::Compare(const Bigint& a, const Bigint& b) { |
| 1039 bool a_is_negative = a.IsNegative(); |
| 1040 bool b_is_negative = b.IsNegative(); |
| 1041 if (a_is_negative != b_is_negative) { |
| 1042 return a_is_negative ? -1 : 1; |
| 1043 } |
| 1044 |
| 1045 if (a_is_negative) { |
| 1046 return -UnsignedCompare(a, b); |
| 1047 } |
| 1048 return UnsignedCompare(a, b); |
| 1049 } |
| 1050 |
| 1051 |
| 1052 RawBigint* BigintOperations::AddSubtract(const Bigint& a, |
| 1053 const Bigint& b, |
| 1054 bool negate_b) { |
| 1055 ASSERT(IsClamped(a)); |
| 1056 ASSERT(IsClamped(b)); |
| 1057 Bigint& result = Bigint::Handle(); |
| 1058 // We perform the subtraction by simulating a negation of the b-argument. |
| 1059 bool b_is_negative = negate_b ? !b.IsNegative() : b.IsNegative(); |
| 1060 |
| 1061 // If both are of the same sign, then we can compute the unsigned addition |
| 1062 // and then simply adjust the sign (if necessary). |
| 1063 // Ex: -3 + -5 -> -(3 + 5) |
| 1064 if (a.IsNegative() == b_is_negative) { |
| 1065 result = UnsignedAdd(a, b); |
| 1066 result.SetSign(b_is_negative); |
| 1067 ASSERT(IsClamped(result)); |
| 1068 return result.raw(); |
| 1069 } |
| 1070 |
| 1071 // The signs differ. |
| 1072 // Take the number with small magnitude and subtract its absolute value from |
| 1073 // the absolute value of the other number. Then adjust the sign, if necessary. |
| 1074 // The sign is the same as for the number with the greater magnitude. |
| 1075 // Ex: -8 + 3 -> -(8 - 3) |
| 1076 // 8 + -3 -> (8 - 3) |
| 1077 // -3 + 8 -> (8 - 3) |
| 1078 // 3 + -8 -> -(8 - 3) |
| 1079 int comp = UnsignedCompare(a, b); |
| 1080 if (comp < 0) { |
| 1081 result = UnsignedSubtract(b, a); |
| 1082 result.SetSign(b_is_negative); |
| 1083 } else if (comp > 0) { |
| 1084 result = UnsignedSubtract(a, b); |
| 1085 result.SetSign(a.IsNegative()); |
| 1086 } else { |
| 1087 return Zero(); |
| 1088 } |
| 1089 ASSERT(IsClamped(result)); |
| 1090 return result.raw(); |
| 1091 } |
| 1092 |
| 1093 |
| 1094 int BigintOperations::UnsignedCompare(const Bigint& a, const Bigint& b) { |
| 1095 ASSERT(IsClamped(a)); |
| 1096 ASSERT(IsClamped(b)); |
| 1097 intptr_t a_length = a.Length(); |
| 1098 intptr_t b_length = b.Length(); |
| 1099 if (a_length < b_length) return -1; |
| 1100 if (a_length > b_length) return 1; |
| 1101 for (intptr_t i = a_length - 1; i >= 0; i--) { |
| 1102 Chunk digit_a = a.GetChunkAt(i); |
| 1103 Chunk digit_b = b.GetChunkAt(i); |
| 1104 if (digit_a < digit_b) return -1; |
| 1105 if (digit_a > digit_b) return 1; |
| 1106 // Else look at the next digit. |
| 1107 } |
| 1108 return 0; // They are equal. |
| 1109 } |
| 1110 |
| 1111 |
| 1112 int BigintOperations::UnsignedCompareNonClamped( |
| 1113 const Bigint& a, const Bigint& b) { |
| 1114 intptr_t a_length = a.Length(); |
| 1115 intptr_t b_length = b.Length(); |
| 1116 while (a_length > b_length) { |
| 1117 if (a.GetChunkAt(a_length - 1) != 0) return 1; |
| 1118 a_length--; |
| 1119 } |
| 1120 while (b_length > a_length) { |
| 1121 if (b.GetChunkAt(b_length - 1) != 0) return -1; |
| 1122 b_length--; |
| 1123 } |
| 1124 for (intptr_t i = a_length - 1; i >= 0; i--) { |
| 1125 Chunk digit_a = a.GetChunkAt(i); |
| 1126 Chunk digit_b = b.GetChunkAt(i); |
| 1127 if (digit_a < digit_b) return -1; |
| 1128 if (digit_a > digit_b) return 1; |
| 1129 // Else look at the next digit. |
| 1130 } |
| 1131 return 0; // They are equal. |
| 1132 } |
| 1133 |
| 1134 |
| 1135 RawBigint* BigintOperations::UnsignedAdd(const Bigint& a, const Bigint& b) { |
| 1136 ASSERT(IsClamped(a)); |
| 1137 ASSERT(IsClamped(b)); |
| 1138 |
| 1139 intptr_t a_length = a.Length(); |
| 1140 intptr_t b_length = b.Length(); |
| 1141 if (a_length < b_length) { |
| 1142 return UnsignedAdd(b, a); |
| 1143 } |
| 1144 |
| 1145 // We might request too much space, in which case we will adjust the length |
| 1146 // afterwards. |
| 1147 intptr_t result_length = a_length + 1; |
| 1148 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
| 1149 |
| 1150 Chunk carry = 0; |
| 1151 // b has fewer digits than a. |
| 1152 ASSERT(b_length <= a_length); |
| 1153 for (intptr_t i = 0; i < b_length; i++) { |
| 1154 Chunk sum = a.GetChunkAt(i) + b.GetChunkAt(i) + carry; |
| 1155 result.SetChunkAt(i, sum & kDigitMask); |
| 1156 carry = sum >> kDigitBitSize; |
| 1157 } |
| 1158 // Copy over the remaining digits of a, but don't forget the carry. |
| 1159 for (intptr_t i = b_length; i < a_length; i++) { |
| 1160 Chunk sum = a.GetChunkAt(i) + carry; |
| 1161 result.SetChunkAt(i, sum & kDigitMask); |
| 1162 carry = sum >> kDigitBitSize; |
| 1163 } |
| 1164 // Shrink the result if there was no overflow. Otherwise apply the carry. |
| 1165 if (carry == 0) { |
| 1166 // TODO(floitsch): We change the size of bigint-objects here. |
| 1167 result.SetLength(a_length); |
| 1168 } else { |
| 1169 result.SetChunkAt(a_length, carry); |
| 1170 } |
| 1171 ASSERT(IsClamped(result)); |
| 1172 return result.raw(); |
| 1173 } |
| 1174 |
| 1175 |
| 1176 RawBigint* BigintOperations::UnsignedSubtract(const Bigint& a, |
| 1177 const Bigint& b) { |
| 1178 ASSERT(IsClamped(a)); |
| 1179 ASSERT(IsClamped(b)); |
| 1180 ASSERT(UnsignedCompare(a, b) >= 0); |
| 1181 |
| 1182 const int kSignBitPos = Bigint::kChunkSize * kBitsPerByte - 1; |
| 1183 |
| 1184 intptr_t a_length = a.Length(); |
| 1185 intptr_t b_length = b.Length(); |
| 1186 |
| 1187 // We might request too much space, in which case we will adjust the length |
| 1188 // afterwards. |
| 1189 intptr_t result_length = a_length; |
| 1190 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
| 1191 |
| 1192 Chunk borrow = 0; |
| 1193 ASSERT(b_length <= a_length); |
| 1194 for (intptr_t i = 0; i < b_length; i++) { |
| 1195 Chunk difference = a.GetChunkAt(i) - b.GetChunkAt(i) - borrow; |
| 1196 result.SetChunkAt(i, difference & kDigitMask); |
| 1197 borrow = difference >> kSignBitPos; |
| 1198 ASSERT((borrow == 0) || (borrow == 1)); |
| 1199 } |
| 1200 // Copy over the remaining digits of a, but don't forget the borrow. |
| 1201 for (intptr_t i = b_length; i < a_length; i++) { |
| 1202 Chunk difference = a.GetChunkAt(i) - borrow; |
| 1203 result.SetChunkAt(i, difference & kDigitMask); |
| 1204 borrow = (difference >> kSignBitPos); |
| 1205 ASSERT((borrow == 0) || (borrow == 1)); |
| 1206 } |
| 1207 ASSERT(borrow == 0); |
| 1208 Clamp(result); |
| 1209 return result.raw(); |
| 1210 } |
| 1211 |
| 1212 |
| 1213 RawBigint* BigintOperations::MultiplyWithDigit( |
| 1214 const Bigint& bigint, Chunk digit) { |
| 1215 // TODO(floitsch): implement MultiplyWithDigit. |
| 1216 ASSERT(digit <= kDigitMaxValue); |
| 1217 if (digit == 0) return Zero(); |
| 1218 |
| 1219 Bigint& tmp = Bigint::Handle(Bigint::Allocate(1)); |
| 1220 tmp.SetChunkAt(0, digit); |
| 1221 return Multiply(bigint, tmp); |
| 1222 } |
| 1223 |
| 1224 |
| 1225 void BigintOperations::DivideRemainder( |
| 1226 const Bigint& a, const Bigint& b, Bigint* quotient, Bigint* remainder) { |
| 1227 // TODO(floitsch): This function is very memory-intensive since all |
| 1228 // intermediate bigint results are allocated in new memory. It would be |
| 1229 // much more efficient to reuse the space of temporary intermediate variables. |
| 1230 ASSERT(IsClamped(a)); |
| 1231 ASSERT(IsClamped(b)); |
| 1232 ASSERT(!b.IsZero()); |
| 1233 |
| 1234 int comp = UnsignedCompare(a, b); |
| 1235 if (comp < 0) { |
| 1236 (*quotient) ^= Zero(); |
| 1237 (*remainder) ^= Copy(a); // TODO(floitsch): can we reuse the input? |
| 1238 return; |
| 1239 } else if (comp == 0) { |
| 1240 (*quotient) ^= One(); |
| 1241 quotient->SetSign(a.IsNegative() != b.IsNegative()); |
| 1242 (*remainder) ^= Zero(); |
| 1243 return; |
| 1244 } |
| 1245 |
| 1246 // High level description: |
| 1247 // The algorithm is basically the algorithm that is taught in school: |
| 1248 // Let a the dividend and b the divisor. We are looking for |
| 1249 // the quotient q = truncate(a / b), and |
| 1250 // the remainder r = a - q * b. |
| 1251 // School algorithm: |
| 1252 // q = 0 |
| 1253 // n = number_of_digits(a) - number_of_digits(b) |
| 1254 // for (i = n; i >= 0; i--) { |
| 1255 // Maximize k such that k*y*10^i is less than or equal to a and |
| 1256 // (k + 1)*y*10^i is greater. |
| 1257 // q = q + k * 10^i // Add new digit to result. |
| 1258 // a = a - k * b * 10^i |
| 1259 // } |
| 1260 // r = a |
| 1261 // |
| 1262 // Instead of working in base 10 we work in base kDigitBitSize. |
| 1263 |
| 1264 intptr_t b_length = b.Length(); |
| 1265 int normalization_shift = |
| 1266 kDigitBitSize - CountBits(b.GetChunkAt(b_length - 1)); |
| 1267 Bigint& dividend = Bigint::Handle(ShiftLeft(a, normalization_shift)); |
| 1268 const Bigint& divisor = Bigint::Handle(ShiftLeft(b, normalization_shift)); |
| 1269 dividend.SetSign(false); |
| 1270 divisor.SetSign(false); |
| 1271 |
| 1272 intptr_t dividend_length = dividend.Length(); |
| 1273 intptr_t divisor_length = b_length; |
| 1274 ASSERT(divisor_length == divisor.Length()); |
| 1275 |
| 1276 intptr_t quotient_length = dividend_length - divisor_length + 1; |
| 1277 *quotient ^= Bigint::Allocate(quotient_length); |
| 1278 quotient->SetSign(a.IsNegative() != b.IsNegative()); |
| 1279 |
| 1280 intptr_t quotient_pos = dividend_length - divisor_length; |
| 1281 // Find the first quotient-digit. |
| 1282 // The first digit must be computed separately from the other digits because |
| 1283 // the preconditions for the loop are not yet satisfied. |
| 1284 // For simplicity use a shifted divisor, so that the comparison and |
| 1285 // subtraction are easier. |
| 1286 int divisor_shift_amount = dividend_length - divisor_length; |
| 1287 Bigint& shifted_divisor = |
| 1288 Bigint::Handle(DigitsShiftLeft(divisor, divisor_shift_amount)); |
| 1289 Chunk first_quotient_digit = 0; |
| 1290 while (UnsignedCompare(dividend, shifted_divisor) >= 0) { |
| 1291 first_quotient_digit++; |
| 1292 dividend ^= Subtract(dividend, shifted_divisor); |
| 1293 } |
| 1294 quotient->SetChunkAt(quotient_pos--, first_quotient_digit); |
| 1295 |
| 1296 // Find the remainder of the digits. |
| 1297 |
| 1298 Chunk first_divisor_digit = divisor.GetChunkAt(divisor_length - 1); |
| 1299 // The short divisor only represents the first two digits of the divisor. |
| 1300 // If the divisor has only one digit, then the second part is zeroed out. |
| 1301 Bigint& short_divisor = Bigint::Handle(Bigint::Allocate(2)); |
| 1302 if (divisor_length > 1) { |
| 1303 short_divisor.SetChunkAt(0, divisor.GetChunkAt(divisor_length - 2)); |
| 1304 } else { |
| 1305 short_divisor.SetChunkAt(0, 0); |
| 1306 } |
| 1307 short_divisor.SetChunkAt(1, first_divisor_digit); |
| 1308 // The following bigint will be used inside the loop. It is allocated outside |
| 1309 // the loop to avoid repeated allocations. |
| 1310 Bigint& target = Bigint::Handle(Bigint::Allocate(3)); |
| 1311 // The dividend_length here must be from the initial dividend. |
| 1312 for (intptr_t i = dividend_length - 1; i >= divisor_length; i--) { |
| 1313 // Invariant: let t = i - divisor_length |
| 1314 // then dividend / (divisor << (t * kDigitBitSize)) <= kDigitMaxValue. |
| 1315 // Ex: dividend: 53451232, and divisor: 535 (with t == 5) is ok. |
| 1316 // dividend: 56822123, and divisor: 563 (with t == 5) is bad. |
| 1317 // dividend: 6822123, and divisor: 563 (with t == 5) is ok. |
| 1318 |
| 1319 // The dividend has changed. So recompute its length. |
| 1320 dividend_length = dividend.Length(); |
| 1321 Chunk dividend_digit; |
| 1322 if (i > dividend_length) { |
| 1323 quotient->SetChunkAt(quotient_pos--, 0); |
| 1324 continue; |
| 1325 } else if (i == dividend_length) { |
| 1326 dividend_digit = 0; |
494 } else { | 1327 } else { |
495 n = Utils::Minimum(a.NumberOfBits(), b.NumberOfBits()); | 1328 ASSERT(i + 1 == dividend_length); |
496 } | 1329 dividend_digit = dividend.GetChunkAt(i); |
497 } else if (a.IsNegative() || b.IsNegative()) { | 1330 } |
498 if (tt[2]) { | 1331 Chunk quotient_digit; |
499 rflip = rborrow = -1; | 1332 // Compute an estimate of the quotient_digit. The estimate will never |
500 } | 1333 // be too small. |
501 n = Utils::Maximum(a.NumberOfBits(), b.NumberOfBits()); | 1334 if (dividend_digit == first_divisor_digit) { |
502 } else { | 1335 // Small shortcut: the else-branch would compute a value > kDigitMaxValue. |
503 if (tt[2]) { | 1336 // However, by hypothesis, we know that the quotient_digit must fit into |
504 n = Utils::Maximum(a.NumberOfBits(), b.NumberOfBits()); | 1337 // a digit. Avoid going through repeated iterations of the adjustment |
| 1338 // loop by directly assigning kDigitMaxValue to the quotient_digit. |
| 1339 // Ex: 51235 / 523. |
| 1340 // 51 / 5 would yield 10 (if computed in the else branch). |
| 1341 // However we know that 9 is the maximal value. |
| 1342 quotient_digit = kDigitMaxValue; |
505 } else { | 1343 } else { |
506 n = Utils::Minimum(a.NumberOfBits(), b.NumberOfBits()); | 1344 // Compute the estimate by using two digits of the dividend and one of |
507 } | 1345 // the divisor. |
508 } | 1346 // Ex: 32421 / 535 |
509 bool aflip = false; | 1347 // 32 / 5 -> 6 |
510 int acarry = 0; | 1348 // The estimate would hence be 6. |
511 if (a.IsNegative()) { | 1349 DoubleChunk two_dividend_digits = dividend_digit; |
512 aflip = true; | 1350 two_dividend_digits <<= kDigitBitSize; |
513 acarry = 1; | 1351 two_dividend_digits += dividend.GetChunkAt(i - 1); |
514 } | 1352 DoubleChunk q = two_dividend_digits / first_divisor_digit; |
515 bool bflip = false; | 1353 if (q > kDigitMaxValue) q = kDigitMaxValue; |
516 int bcarry = 0; | 1354 quotient_digit = static_cast<Chunk>(q); |
517 if (b.IsNegative()) { | 1355 } |
518 bflip = true; | 1356 |
519 bcarry = 1; | 1357 // Refine estimation. |
520 } | 1358 quotient_digit++; // The following loop will start by decrementing. |
521 for (int i = 0 ; i < n ; ++i) { | 1359 Bigint& estimation_product = Bigint::Handle(); |
522 int ab = (a.Bit(i) ^ (aflip ? 1 : 0)) + acarry; | 1360 target.SetChunkAt(0, ((i - 2) < 0) ? 0 : dividend.GetChunkAt(i - 2)); |
523 ASSERT(ab <= 2 && ab >= 0); | 1361 target.SetChunkAt(1, ((i - 1) < 0) ? 0 : dividend.GetChunkAt(i - 1)); |
524 int bb = (b.Bit(i) ^ (bflip ? 1 : 0)) + bcarry; | 1362 target.SetChunkAt(2, dividend_digit); |
525 ASSERT(bb <= 2 && bb >= 0); | 1363 do { |
526 int r = tt[(ab & 1) + ((bb & 1) << 1)]; | 1364 quotient_digit = (quotient_digit - 1) & kDigitMask; |
527 r = r + rborrow; | 1365 estimation_product ^= MultiplyWithDigit(short_divisor, quotient_digit); |
528 ASSERT(r >= -1 && r <= 1); | 1366 } while (UnsignedCompareNonClamped(estimation_product, target) > 0); |
529 if ((r ^ rflip) & 1) { | 1367 // At this point the quotient_digit is fairly accurate. |
530 int status = BN_set_bit(TmpBN(), i); | 1368 // At the worst it is off by one. |
531 ASSERT(status == 1); | 1369 // Remove a multiple of the divisor. If the estimate is incorrect we will |
532 } | 1370 // subtract the divisor another time. |
533 acarry = ab >> 1; | 1371 // Let t = i - divisor_length. |
534 bcarry = bb >> 1; | 1372 // dividend -= (quotient_digit * divisor) << (t * kDigitBitSize); |
535 rborrow = r >> 1; | 1373 shifted_divisor ^= MultiplyWithDigit(divisor, quotient_digit); |
536 } | 1374 shifted_divisor ^= DigitsShiftLeft(shifted_divisor, i - divisor_length); |
537 if (rborrow) { | 1375 dividend = Subtract(dividend, shifted_divisor); |
538 int status = BN_set_bit(TmpBN(), n); | 1376 if (dividend.IsNegative()) { |
539 ASSERT(status == 1); | 1377 // The estimation was still too big. |
540 } | 1378 quotient_digit--; |
541 if (rflip) { | 1379 // TODO(floitsch): allocate space for the shifted_divisor once and reuse |
542 // FIXME(benl): can be changed to use BN_set_negative() on more | 1380 // it at every iteration. |
543 // recent OpenSSL releases (> 1.0.0). | 1381 shifted_divisor ^= DigitsShiftLeft(divisor, i - divisor_length); |
544 ASSERT(!BN_is_zero(TmpBN())); | 1382 // TODO(floitsch): reuse the space of the previous dividend. |
545 TmpBN()->neg = 1; | 1383 dividend = Add(dividend, shifted_divisor); |
546 } | 1384 } |
547 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); | 1385 quotient->SetChunkAt(quotient_pos--, quotient_digit); |
548 return result.raw(); | 1386 } |
549 } | 1387 ASSERT(quotient_pos == -1); |
550 | 1388 Clamp(*quotient); |
551 | 1389 *remainder ^= ShiftRight(dividend, normalization_shift); |
552 RawSmi* BigintOperations::BitOpWithSmi(Token::Kind kind, | 1390 remainder->SetSign(a.IsNegative()); |
553 const Bigint& bigint, | 1391 } |
554 const Smi& smi) { | 1392 |
555 ASSERT((kind == Token::kBIT_OR) || (kind == Token::kBIT_AND)); | 1393 |
556 intptr_t smi_value = smi.Value(); | 1394 void BigintOperations::Clamp(const Bigint& bigint) { |
557 intptr_t big_value = 0; | 1395 intptr_t length = bigint.Length(); |
558 // We take Smi::kBits + 1 (one more bit), in case bigint is negative. | 1396 while (length > 0 && (bigint.GetChunkAt(length - 1) == 0)) { |
559 ASSERT((Smi::kBits + 1) <= (sizeof(big_value) * kBitsPerByte)); | 1397 length--; |
560 intptr_t num_bits = bigint.NumberOfBits(); | 1398 } |
561 int n = Utils::Minimum(num_bits, Smi::kBits + 1); | 1399 // TODO(floitsch): We change the size of bigint-objects here. |
562 for (int i = n - 1; i >= 0; i--) { | 1400 bigint.SetLength(length); |
563 big_value <<= 1; | 1401 } |
564 big_value += bigint.Bit(i); | 1402 |
565 } | 1403 |
566 if (bigint.IsNegative()) { | 1404 RawBigint* BigintOperations::Copy(const Bigint& bigint) { |
567 big_value = -big_value; | 1405 intptr_t bigint_length = bigint.Length(); |
568 } | 1406 Bigint& copy = Bigint::Handle(Bigint::Allocate(bigint_length)); |
569 intptr_t result; | 1407 for (intptr_t i = 0; i < bigint_length; i++) { |
570 if (kind == Token::kBIT_OR) { | 1408 copy.SetChunkAt(i, bigint.GetChunkAt(i)); |
571 result = smi_value | big_value; | 1409 } |
572 } else { | 1410 copy.SetSign(bigint.IsNegative()); |
573 result = smi_value & big_value; | 1411 return copy.raw(); |
574 } | 1412 } |
575 ASSERT(Smi::IsValid(result)); | 1413 |
576 return Smi::New(result); | 1414 |
577 } | 1415 int BigintOperations::CountBits(Chunk digit) { |
578 | 1416 int result = 0; |
579 | 1417 while (digit != 0) { |
580 RawBigint* BigintOperations::BitAnd(const Bigint& a, const Bigint& b) { | 1418 digit >>= 1; |
581 static bool tt_and[] = { false, false, false, true }; | 1419 result++; |
582 return BitTT(a, b, tt_and); | 1420 } |
583 } | 1421 return result; |
584 | |
585 | |
586 RawInteger* BigintOperations::BitAndWithSmi(const Bigint& bigint, | |
587 const Smi& smi) { | |
588 if (smi.IsNegative()) { | |
589 Bigint& other = Bigint::Handle(NewFromSmi(smi)); | |
590 return BitAnd(bigint, other); | |
591 } | |
592 return BitOpWithSmi(Token::kBIT_AND, bigint, smi); | |
593 } | |
594 | |
595 | |
596 RawBigint* BigintOperations::BitOr(const Bigint& a, const Bigint& b) { | |
597 static bool tt_or[] = { false, true, true, true }; | |
598 return BitTT(a, b, tt_or); | |
599 } | |
600 | |
601 | |
602 RawInteger* BigintOperations::BitOrWithSmi(const Bigint& bigint, | |
603 const Smi& smi) { | |
604 if (!smi.IsNegative()) { | |
605 Bigint& other = Bigint::Handle(NewFromSmi(smi)); | |
606 return BitOr(bigint, other); | |
607 } | |
608 return BitOpWithSmi(Token::kBIT_OR, bigint, smi); | |
609 } | |
610 | |
611 | |
612 RawBigint* BigintOperations::BitXor(const Bigint& a, const Bigint& b) { | |
613 static bool tt_xor[] = { false, true, true, false }; | |
614 return BitTT(a, b, tt_xor); | |
615 } | |
616 | |
617 | |
618 RawInteger* BigintOperations::BitXorWithSmi(const Bigint& bigint, | |
619 const Smi& smi) { | |
620 Bigint& other = Bigint::Handle(NewFromSmi(smi)); | |
621 return BitXor(bigint, other); | |
622 } | |
623 | |
624 | |
625 RawBigint* BigintOperations::BitNot(const Bigint& bigint) { | |
626 const Bigint& one_bigint = Bigint::Handle(One()); | |
627 const Bigint& result = Bigint::Handle(Add(bigint, one_bigint)); | |
628 result.ToggleSign(); | |
629 return result.raw(); | |
630 } | |
631 | |
632 | |
633 int BigintOperations::Compare(const Bigint& a, const Bigint& b) { | |
634 return BN_cmp(a.BNAddr(), b.BNAddr()); | |
635 } | 1422 } |
636 | 1423 |
637 } // namespace dart | 1424 } // namespace dart |
OLD | NEW |