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) < sizeof(intptr_t) * 8)) { |
Ivan Posva
2012/02/28 01:38:34
8 -> kBitsPerByte
siva
2012/02/28 18:22:18
Done.
| |
346 return true; | |
347 } | |
348 | |
349 uintptr_t limit; | |
350 if (bigint.IsNegative()) { | |
351 limit = static_cast<uintptr_t>(-Smi::kMinValue); | |
352 } else { | |
353 limit = static_cast<uintptr_t>(Smi::kMaxValue); | |
354 } | |
355 bool bigint_is_greater = false; | |
356 // Consume the least-significant digits of the bigint. | |
357 // If bigint_is_greater is set, then the processed sub-part of the bigint is | |
358 // greater than the corresponding part of the limit. | |
359 for (int i = 0; i < bigint_length - 1; i++) { | |
360 Chunk limit_digit = static_cast<Chunk>(limit & kDigitMask); | |
361 Chunk bigint_digit = bigint.GetChunkAt(i); | |
362 if (limit_digit < bigint_digit) { | |
363 bigint_is_greater = true; | |
364 } else if (limit_digit > bigint_digit) { | |
365 bigint_is_greater = false; | |
366 } // else don't change the boolean. | |
367 limit >>= kDigitBitSize; | |
368 | |
369 // Bail out if the bigint is definitely too big. | |
370 if (limit == 0) { | |
371 return false; | |
372 } | |
373 } | |
374 Chunk most_significant_digit = bigint.GetChunkAt(bigint_length - 1); | |
375 if (limit > most_significant_digit) { | |
376 return true; | |
377 } | |
378 if (limit < most_significant_digit) { | |
259 return false; | 379 return false; |
260 } | 380 } |
261 return true; | 381 return !bigint_is_greater; |
262 } | 382 } |
263 | 383 |
264 | 384 |
265 RawSmi* BigintOperations::ToSmi(const Bigint& bigint) { | 385 RawSmi* BigintOperations::ToSmi(const Bigint& bigint) { |
Ivan Posva
2012/02/28 01:38:34
Will we need a FitsIntoMint and ToMint as well?
siva
2012/02/28 18:22:18
They are FitsIntoInt64 and ToInt64 respectively.
| |
266 ASSERT(FitsIntoSmi(bigint)); | 386 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; | 387 intptr_t value = 0; |
272 ASSERT(n <= static_cast<int>(sizeof value)); | 388 for (int i = bigint.Length() - 1; i >= 0; i--) { |
273 for (int i = 0; i < n; ++i) { | 389 value <<= kDigitBitSize; |
274 value <<= 8; | 390 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); |
275 value |= bytes[i]; | |
276 } | 391 } |
277 if (bigint.IsNegative()) { | 392 if (bigint.IsNegative()) { |
278 value = -value; | 393 value = -value; |
279 } | 394 } |
280 return Smi::New(value); | 395 return Smi::New(value); |
281 } | 396 } |
282 | 397 |
283 | 398 |
284 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) { | 399 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) { |
285 // TODO(floitsch/benl): This is a quick and dirty implementation to unblock | 400 // 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. | 401 // other areas of the code. It does not handle all bit-twiddling correctly. |
402 const double shift_value = (1 << kDigitBitSize); | |
287 double value = 0.0; | 403 double value = 0.0; |
288 for (int i = bigint.NumberOfBits() - 1; i >= 0; --i) { | 404 for (int i = bigint.Length() - 1; i >= 0; i--) { |
289 value *= 2; | 405 value *= shift_value; |
290 value += static_cast<double>(bigint.Bit(i)); | 406 value += static_cast<double>(bigint.GetChunkAt(i)); |
291 } | 407 } |
292 if (bigint.IsNegative()) { | 408 if (bigint.IsNegative()) { |
293 value = -value; | 409 value = -value; |
294 } | 410 } |
295 return Double::New(value); | 411 return Double::New(value); |
296 } | 412 } |
297 | 413 |
298 | 414 |
299 bool BigintOperations::FitsIntoInt64(const Bigint& bigint) { | 415 bool BigintOperations::FitsIntoInt64(const Bigint& bigint) { |
300 const BIGNUM *bn = bigint.BNAddr(); | 416 intptr_t bigint_length = bigint.Length(); |
301 int bits = BN_num_bits(bn); | 417 if (bigint_length == 0) { |
302 if (bits <= 63) return true; | 418 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 } | 419 } |
312 return true; | 420 if ((bigint_length < 3) && |
421 (static_cast<size_t>(kDigitBitSize) < sizeof(intptr_t) * 8)) { | |
422 return true; | |
423 } | |
424 | |
425 uint64_t limit; | |
426 if (bigint.IsNegative()) { | |
427 limit = static_cast<uint64_t>(Mint::kMinValue); | |
428 } else { | |
429 limit = static_cast<uint64_t>(Mint::kMaxValue); | |
430 } | |
431 bool bigint_is_greater = false; | |
432 // Consume the least-significant digits of the bigint. | |
433 // If bigint_is_greater is set, then the processed sub-part of the bigint is | |
434 // greater than the corresponding part of the limit. | |
435 for (int i = 0; i < bigint_length - 1; i++) { | |
436 Chunk limit_digit = static_cast<Chunk>(limit & kDigitMask); | |
437 Chunk bigint_digit = bigint.GetChunkAt(i); | |
438 if (limit_digit < bigint_digit) { | |
439 bigint_is_greater = true; | |
440 } else if (limit_digit > bigint_digit) { | |
441 bigint_is_greater = false; | |
442 } // else don't change the boolean. | |
443 limit >>= kDigitBitSize; | |
444 | |
445 // Bail out if the bigint is definitely too big. | |
446 if (limit == 0) { | |
447 return false; | |
448 } | |
449 } | |
450 Chunk most_significant_digit = bigint.GetChunkAt(bigint_length - 1); | |
451 if (limit > most_significant_digit) { | |
452 return true; | |
453 } | |
454 if (limit < most_significant_digit) { | |
455 return false; | |
456 } | |
457 return !bigint_is_greater; | |
313 } | 458 } |
314 | 459 |
315 | 460 |
316 uint64_t BigintOperations::AbsToUint64(const Bigint& bigint) { | 461 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; | 462 uint64_t value = 0; |
322 ASSERT(n <= static_cast<int>(sizeof value)); | 463 for (int i = bigint.Length() - 1; i >= 0; i--) { |
323 for (int i = 0; i < n; ++i) { | 464 value <<= kDigitBitSize; |
324 value <<= 8; | 465 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); |
325 value |= bytes[i]; | |
326 } | 466 } |
327 return value; | 467 return value; |
328 } | 468 } |
329 | 469 |
330 | 470 |
331 int64_t BigintOperations::ToInt64(const Bigint& bigint) { | 471 int64_t BigintOperations::ToInt64(const Bigint& bigint) { |
332 ASSERT(FitsIntoInt64(bigint)); | 472 ASSERT(FitsIntoInt64(bigint)); |
333 int64_t value = AbsToUint64(bigint); | 473 int64_t value = AbsToUint64(bigint); |
334 if (bigint.IsNegative()) { | 474 if (bigint.IsNegative()) { |
335 value = -value; | 475 value = -value; |
336 } | 476 } |
337 return value; | 477 return value; |
338 } | 478 } |
339 | 479 |
340 | 480 |
341 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) { | 481 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) { |
342 const BIGNUM *bn = bigint.BNAddr(); | |
343 if (bigint.IsNegative()) return false; | 482 if (bigint.IsNegative()) return false; |
344 int bits = BN_num_bits(bn); | 483 intptr_t b_length = bigint.Length(); |
345 if (bits > 64) return false; | 484 int num_bits = CountBits(bigint.GetChunkAt(b_length - 1)); |
485 num_bits += (kDigitBitSize * (b_length - 1)); | |
486 if (num_bits > 64) return false; | |
346 return true; | 487 return true; |
347 } | 488 } |
348 | 489 |
349 | 490 |
350 uint64_t BigintOperations::ToUint64(const Bigint& bigint) { | 491 uint64_t BigintOperations::ToUint64(const Bigint& bigint) { |
351 ASSERT(FitsIntoUint64(bigint)); | 492 ASSERT(FitsIntoUint64(bigint)); |
352 return AbsToUint64(bigint); | 493 return AbsToUint64(bigint); |
353 } | 494 } |
354 | 495 |
355 | 496 |
356 RawBigint* BigintOperations::Add(const Bigint& a, const Bigint& b) { | 497 RawBigint* BigintOperations::Multiply(const Bigint& a, const Bigint& b) { |
357 int status = BN_add(TmpBN(), a.BNAddr(), b.BNAddr()); | 498 ASSERT(IsClamped(a)); |
358 if (status == 0) { | 499 ASSERT(IsClamped(b)); |
359 GrowableArray<const Object*> exception_arguments; | 500 |
360 exception_arguments.Add( | 501 intptr_t a_length = a.Length(); |
361 &Object::ZoneHandle(String::New("BigintOperations::Add"))); | 502 intptr_t b_length = b.Length(); |
362 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); | 503 intptr_t result_length = a_length + b_length; |
363 } | 504 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
364 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); | 505 |
506 if (a.IsNegative() != b.IsNegative()) { | |
507 result.ToggleSign(); | |
508 } | |
509 | |
510 // Comba multiplication: compute each column separately. | |
511 // Example: r = a2a1a0 * b2b1b0. | |
512 // r = 1 * a0b0 + | |
513 // 10 * (a1b0 + a0b1) + | |
514 // 100 * (a2b0 + a1b1 + a0b2) + | |
515 // 1000 * (a2b1 + a1b2) + | |
516 // 10000 * a2b2 | |
517 // | |
518 // Each column will be accumulated in an integer of type DoubleChunk. We | |
519 // must guarantee that the column-sum will not overflow. | |
520 // | |
521 // In the worst case we have to accumulate k = Min(a.length, b.length) | |
522 // products plus the carry from the previous round. | |
523 // Each bigint-digit is smaller than beta = 2^kDigitBitSize. | |
524 // Each product is at most (beta - 1)^2. | |
525 // If we want to use Comba multiplication the following condition must hold: | |
526 // k * (beta - 1)^2 + (2^(kDoubleChunkBitSize - kDigitBitSize) - 1) < | |
527 // 2^kDoubleChunkBitSize. | |
528 const DoubleChunk square = | |
529 static_cast<DoubleChunk>(kDigitMaxValue) * kDigitMaxValue; | |
530 const DoubleChunk kDoubleChunkMaxValue = static_cast<DoubleChunk>(-1); | |
531 const DoubleChunk left_over_carry = kDoubleChunkMaxValue >> kDigitBitSize; | |
532 const intptr_t kMaxDigits = (kDoubleChunkMaxValue - left_over_carry) / square; | |
533 if (Utils::Minimum(a_length, b_length) > kMaxDigits) { | |
534 UNIMPLEMENTED(); | |
535 } | |
536 | |
537 DoubleChunk accumulator = 0; // Accumulates the result of one column. | |
538 for (intptr_t i = 0; i < result_length; i++) { | |
539 // Example: r = a2a1a0 * b2b1b0. | |
540 // For i == 0, compute a0b0. | |
541 // i == 1, a1b0 + a0b1 + overflow from i == 0. | |
542 // i == 2, a2b0 + a1b1 + a0b2 + overflow from i == 1. | |
543 // ... | |
544 // The indices into a and b are such that their sum equals i. | |
545 intptr_t a_index = Utils::Minimum(a_length - 1, i); | |
546 intptr_t b_index = i - a_index; | |
547 ASSERT(a_index + b_index == i); | |
548 | |
549 // Instead of testing for a_index >= 0 && b_index < b_length we compute the | |
550 // number of iterations first. | |
551 intptr_t iterations = Utils::Minimum(b_length - b_index, a_index + 1); | |
552 for (intptr_t j = 0; j < iterations; j++) { | |
553 DoubleChunk chunk_a = a.GetChunkAt(a_index); | |
554 DoubleChunk chunk_b = b.GetChunkAt(b_index); | |
555 accumulator += chunk_a * chunk_b; | |
556 a_index--; | |
557 b_index++; | |
558 } | |
559 result.SetChunkAt(i, static_cast<Chunk>(accumulator & kDigitMask)); | |
560 accumulator >>= kDigitBitSize; | |
561 } | |
562 ASSERT(accumulator == 0); | |
563 | |
564 Clamp(result); | |
365 return result.raw(); | 565 return result.raw(); |
366 } | 566 } |
367 | 567 |
368 | 568 |
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) { | 569 RawBigint* BigintOperations::Divide(const Bigint& a, const Bigint& b) { |
396 int status = BN_div(TmpBN(), NULL, a.BNAddr(), b.BNAddr(), TmpBNCtx()); | 570 Bigint& quotient = Bigint::Handle(); |
397 if (status == 0) { | 571 Bigint& remainder = Bigint::Handle(); |
398 GrowableArray<const Object*> exception_arguments; | 572 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(); | 573 return quotient.raw(); |
405 } | 574 } |
406 | 575 |
407 | 576 |
408 RawBigint* BigintOperations::Modulo(const Bigint& a, const Bigint& b) { | 577 RawBigint* BigintOperations::Modulo(const Bigint& a, const Bigint& b) { |
409 int status = BN_nnmod(TmpBN(), a.BNAddr(), b.BNAddr(), TmpBNCtx()); | 578 Bigint& quotient = Bigint::Handle(); |
410 if (status == 0) { | 579 Bigint& modulo = Bigint::Handle(); |
411 GrowableArray<const Object*> exception_arguments; | 580 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(); | 581 return modulo.raw(); |
418 } | 582 } |
419 | 583 |
420 | 584 |
421 RawBigint* BigintOperations::Remainder(const Bigint& a, const Bigint& b) { | 585 RawBigint* BigintOperations::Remainder(const Bigint& a, const Bigint& b) { |
422 int status = BN_div(NULL, TmpBN(), a.BNAddr(), b.BNAddr(), TmpBNCtx()); | 586 Bigint& quotient = Bigint::Handle(); |
423 if (status == 0) { | 587 Bigint& remainder = Bigint::Handle(); |
424 GrowableArray<const Object*> exception_arguments; | 588 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(); | 589 return remainder.raw(); |
431 } | 590 } |
432 | 591 |
433 | 592 |
434 RawBigint* BigintOperations::ShiftLeft(const Bigint& bigint, intptr_t amount) { | 593 RawBigint* BigintOperations::ShiftLeft(const Bigint& bigint, intptr_t amount) { |
435 int status = BN_lshift(TmpBN(), bigint.BNAddr(), amount); | 594 ASSERT(IsClamped(bigint)); |
436 if (status == 0) { | 595 ASSERT(amount >= 0); |
437 GrowableArray<const Object*> exception_arguments; | 596 intptr_t bigint_length = bigint.Length(); |
438 exception_arguments.Add( | 597 if (bigint.IsZero()) { |
439 &Object::ZoneHandle(String::New("BigintOperations::ShiftLeft"))); | 598 return Zero(); |
440 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); | 599 } |
441 } | 600 // TODO(floitsch): can we reuse the input? |
442 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); | 601 if (amount == 0) { |
443 return result.raw(); | 602 return Copy(bigint); |
603 } | |
604 intptr_t digit_shift = amount / kDigitBitSize; | |
605 intptr_t bit_shift = amount % kDigitBitSize; | |
606 if (bit_shift == 0) { | |
607 const Bigint& result = | |
608 Bigint::Handle(Bigint::Allocate(bigint_length + digit_shift)); | |
609 for (intptr_t i = 0; i < digit_shift; i++) { | |
610 result.SetChunkAt(i, 0); | |
611 } | |
612 for (intptr_t i = 0; i < bigint_length; i++) { | |
613 result.SetChunkAt(i + digit_shift, bigint.GetChunkAt(i)); | |
614 } | |
615 if (bigint.IsNegative()) { | |
616 result.ToggleSign(); | |
617 } | |
618 return result.raw(); | |
619 } else { | |
620 const Bigint& result = | |
621 Bigint::Handle(Bigint::Allocate(bigint_length + digit_shift + 1)); | |
622 for (intptr_t i = 0; i < digit_shift; i++) { | |
623 result.SetChunkAt(i, 0); | |
624 } | |
625 Chunk carry = 0; | |
626 for (intptr_t i = 0; i < bigint_length; i++) { | |
627 Chunk digit = bigint.GetChunkAt(i); | |
628 Chunk shifted_digit = ((digit << bit_shift) & kDigitMask) + carry; | |
629 result.SetChunkAt(i + digit_shift, shifted_digit); | |
630 carry = digit >> (kDigitBitSize - bit_shift); | |
631 } | |
632 result.SetChunkAt(bigint_length + digit_shift, carry); | |
633 if (bigint.IsNegative()) { | |
634 result.ToggleSign(); | |
635 } | |
636 Clamp(result); | |
637 return result.raw(); | |
638 } | |
444 } | 639 } |
445 | 640 |
446 | 641 |
447 RawBigint* BigintOperations::ShiftRight(const Bigint& bigint, intptr_t amount) { | 642 RawBigint* BigintOperations::ShiftRight(const Bigint& bigint, intptr_t amount) { |
643 ASSERT(IsClamped(bigint)); | |
448 ASSERT(amount >= 0); | 644 ASSERT(amount >= 0); |
449 int status = BN_rshift(TmpBN(), bigint.BNAddr(), amount); | 645 intptr_t bigint_length = bigint.Length(); |
450 if (status == 0) { | 646 if (bigint.IsZero()) { |
451 GrowableArray<const Object*> exception_arguments; | 647 return Zero(); |
452 exception_arguments.Add( | 648 } |
453 &Object::ZoneHandle(String::New("BigintOperations::ShiftRight"))); | 649 // TODO(floitsch): can we reuse the input? |
454 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); | 650 if (amount == 0) { |
455 } | 651 return Copy(bigint); |
456 // OpenSSL doesn't take account of sign when shifting - this fixes it. | 652 } |
653 intptr_t digit_shift = amount / kDigitBitSize; | |
654 intptr_t bit_shift = amount % kDigitBitSize; | |
655 if (digit_shift >= bigint_length) { | |
656 return bigint.IsNegative() ? MinusOne() : Zero(); | |
657 } | |
658 | |
659 const Bigint& result = | |
660 Bigint::Handle(Bigint::Allocate(bigint_length - digit_shift)); | |
661 if (bit_shift == 0) { | |
662 for (intptr_t i = 0; i < bigint_length - digit_shift; i++) { | |
663 result.SetChunkAt(i, bigint.GetChunkAt(i + digit_shift)); | |
664 } | |
665 } else { | |
666 Chunk carry = 0; | |
667 for (intptr_t i = bigint_length - 1; i >= digit_shift; i--) { | |
668 Chunk digit = bigint.GetChunkAt(i); | |
669 Chunk shifted_digit = (digit >> bit_shift) + carry; | |
670 result.SetChunkAt(i - digit_shift, shifted_digit); | |
671 carry = (digit << (kDigitBitSize - bit_shift)) & kDigitMask; | |
672 } | |
673 Clamp(result); | |
674 } | |
675 | |
457 if (bigint.IsNegative()) { | 676 if (bigint.IsNegative()) { |
458 for (intptr_t i = 0; i < amount; ++i) { | 677 result.ToggleSign(); |
459 if (bigint.IsBitSet(i)) { | 678 // If the input is negative then the result needs to be rounded down. |
460 int status = BN_sub_word(TmpBN(), 1); | 679 // Example: -5 >> 2 => -2 |
461 ASSERT(status == 1); | 680 bool needs_rounding = false; |
681 for (intptr_t i = 0; i < digit_shift; i++) { | |
682 if (bigint.GetChunkAt(i) != 0) { | |
683 needs_rounding = true; | |
462 break; | 684 break; |
463 } | 685 } |
464 } | 686 } |
465 } | 687 if (!needs_rounding && (bit_shift > 0)) { |
466 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); | 688 Chunk digit = bigint.GetChunkAt(digit_shift); |
689 needs_rounding = (digit << (kChunkBitSize - bit_shift)) != 0; | |
690 } | |
691 if (needs_rounding) { | |
692 Bigint& one = Bigint::Handle(One()); | |
693 return Subtract(result, one); | |
694 } | |
695 } | |
696 | |
467 return result.raw(); | 697 return result.raw(); |
468 } | 698 } |
469 | 699 |
470 /* Bit operations are complicated by negatives: BIGNUMs don't use 2's | 700 |
471 * complement, but instead store the absolute value and a sign | 701 RawBigint* BigintOperations::BitAnd(const Bigint& a, const Bigint& b) { |
472 * indicator. However bit operations are defined on 2's complement | 702 ASSERT(IsClamped(a)); |
473 * representations. This function handles the necessary | 703 ASSERT(IsClamped(b)); |
474 * invert-and-carry operations to deal with the fact that -x = ~x + 1 | 704 |
475 * both on the operands and result. The actual operation performed is | 705 if (a.IsZero() || b.IsZero()) { |
476 * specified by the truth table |tt|, which is in the order of input | 706 return Zero(); |
477 * bits (00, 01, 10, 11). | 707 } |
478 */ | 708 if (a.IsNegative() && !b.IsNegative()) { |
479 RawBigint* BigintOperations::BitTT(const Bigint& a, const Bigint& b, | 709 return BitAnd(b, a); |
480 bool tt[4]) { | 710 } |
481 BN_zero(TmpBN()); | 711 if ((a.IsNegative() == b.IsNegative()) && (a.Length() < b.Length())) { |
482 int n; | 712 return BitAnd(b, a); |
483 int rflip = 0; | 713 } |
484 int rborrow = 0; | 714 |
485 // There's probably a clever way to figure out why these are what | 715 intptr_t a_length = a.Length(); |
486 // they are, but I confess I worked them out pragmatically. | 716 intptr_t b_length = b.Length(); |
487 if (a.IsNegative() && b.IsNegative()) { | 717 intptr_t min_length = Utils::Minimum(a_length, b_length); |
488 if (tt[3]) { | 718 intptr_t max_length = Utils::Maximum(a_length, b_length); |
489 rflip = -1; | 719 if (!b.IsNegative()) { |
490 rborrow = -1; | 720 ASSERT(!a.IsNegative()); |
491 } | 721 intptr_t result_length = min_length; |
492 if (tt[2] != tt[3]) { | 722 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); |
493 n = Utils::Maximum(a.NumberOfBits(), b.NumberOfBits()); | 723 |
724 for (intptr_t i = 0; i < min_length; i++) { | |
725 result.SetChunkAt(i, a.GetChunkAt(i) & b.GetChunkAt(i)); | |
726 } | |
727 Clamp(result); | |
728 return result.raw(); | |
729 } | |
730 | |
731 // Bigints encode negative values by storing the absolute value and the sign | |
732 // separately. To do bit operations we need to simulate numbers that are | |
733 // implemented as two's complement. | |
734 // The negation of a positive number x would be encoded as follows in | |
735 // two's complement: n = ~(x - 1). | |
736 // The inverse transformation is hence (~n) + 1. | |
737 | |
738 if (!a.IsNegative()) { | |
739 ASSERT(b.IsNegative()); | |
740 // The result will be positive. | |
741 intptr_t result_length = a_length; | |
742 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); | |
743 Chunk borrow = 1; | |
744 for (intptr_t i = 0; i < min_length; i++) { | |
745 Chunk b_digit = b.GetChunkAt(i) - borrow; | |
746 result.SetChunkAt(i, a.GetChunkAt(i) & (~b_digit) & kDigitMask); | |
747 borrow = b_digit >> (kChunkBitSize - 1); | |
748 } | |
749 for (intptr_t i = min_length; i < a_length; i++) { | |
750 result.SetChunkAt(i, a.GetChunkAt(i) & (kDigitMaxValue - borrow)); | |
751 borrow = 0; | |
752 } | |
753 Clamp(result); | |
754 return result.raw(); | |
755 } | |
756 | |
757 ASSERT(a.IsNegative()); | |
758 ASSERT(b.IsNegative()); | |
759 // The result will be negative. | |
760 // We need to convert a and b to two's complement. Do the bit-operation there, | |
761 // and transform the resulting bits from two's complement back to separated | |
762 // magnitude and sign. | |
763 // a & b is therefore computed as ~((~(a - 1)) & (~(b - 1))) + 1 which is | |
764 // equal to ((a-1) | (b-1)) + 1. | |
765 intptr_t result_length = max_length + 1; | |
766 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); | |
767 result.ToggleSign(); | |
768 Chunk a_borrow = 1; | |
769 Chunk b_borrow = 1; | |
770 Chunk result_carry = 1; | |
771 ASSERT(a_length >= b_length); | |
772 for (intptr_t i = 0; i < b_length; i++) { | |
773 Chunk a_digit = a.GetChunkAt(i) - a_borrow; | |
774 Chunk b_digit = b.GetChunkAt(i) - b_borrow; | |
775 Chunk result_chunk = ((a_digit | b_digit) & kDigitMask) + result_carry; | |
776 result.SetChunkAt(i, result_chunk & kDigitMask); | |
777 a_borrow = a_digit >> (kChunkBitSize - 1); | |
778 b_borrow = b_digit >> (kChunkBitSize - 1); | |
779 result_carry = result_chunk >> kDigitBitSize; | |
780 } | |
781 for (intptr_t i = b_length; i < a_length; i++) { | |
782 Chunk a_digit = a.GetChunkAt(i) - a_borrow; | |
783 Chunk b_digit = -b_borrow; | |
784 Chunk result_chunk = ((a_digit | b_digit) & kDigitMask) + result_carry; | |
785 result.SetChunkAt(i, result_chunk & kDigitMask); | |
786 a_borrow = a_digit >> (kChunkBitSize - 1); | |
787 b_borrow = 0; | |
788 result_carry = result_chunk >> kDigitBitSize; | |
789 } | |
790 Chunk a_digit = -a_borrow; | |
791 Chunk b_digit = -b_borrow; | |
792 Chunk result_chunk = ((a_digit | b_digit) & kDigitMask) + result_carry; | |
793 result.SetChunkAt(a_length, result_chunk & kDigitMask); | |
794 Clamp(result); | |
795 return result.raw(); | |
796 } | |
797 | |
798 | |
799 RawBigint* BigintOperations::BitOr(const Bigint& a, const Bigint& b) { | |
800 ASSERT(IsClamped(a)); | |
801 ASSERT(IsClamped(b)); | |
802 | |
803 if (a.IsNegative() && !b.IsNegative()) { | |
804 return BitOr(b, a); | |
805 } | |
806 if ((a.IsNegative() == b.IsNegative()) && (a.Length() < b.Length())) { | |
807 return BitOr(b, a); | |
808 } | |
809 | |
810 intptr_t a_length = a.Length(); | |
811 intptr_t b_length = b.Length(); | |
812 intptr_t min_length = Utils::Minimum(a_length, b_length); | |
813 intptr_t max_length = Utils::Maximum(a_length, b_length); | |
814 if (!b.IsNegative()) { | |
815 ASSERT(!a.IsNegative()); | |
816 intptr_t result_length = max_length; | |
817 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); | |
818 | |
819 ASSERT(a_length >= b_length); | |
820 for (intptr_t i = 0; i < b_length; i++) { | |
821 result.SetChunkAt(i, a.GetChunkAt(i) | b.GetChunkAt(i)); | |
822 } | |
823 for (intptr_t i = b_length; i < a_length; i++) { | |
824 result.SetChunkAt(i, a.GetChunkAt(i)); | |
825 } | |
826 return result.raw(); | |
827 } | |
828 | |
829 // Bigints encode negative values by storing the absolute value and the sign | |
830 // separately. To do bit operations we need to simulate numbers that are | |
831 // implemented as two's complement. | |
832 // The negation of a positive number x would be encoded as follows in | |
833 // two's complement: n = ~(x - 1). | |
834 // The inverse transformation is hence (~n) + 1. | |
835 | |
836 if (!a.IsNegative()) { | |
837 ASSERT(b.IsNegative()); | |
838 if (a.IsZero()) { | |
839 return Copy(b); | |
840 } | |
841 // The result will be negative. | |
842 // We need to convert b to two's complement. Do the bit-operation there, | |
843 // and transform the resulting bits from two's complement back to separated | |
844 // magnitude and sign. | |
845 // a | b is therefore computed as ~((a & (~(b - 1))) + 1 which is | |
846 // equal to ((~a) & (b-1)) + 1. | |
847 intptr_t result_length = b_length; | |
848 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); | |
849 result.ToggleSign(); | |
850 Chunk borrow = 1; | |
851 Chunk result_carry = 1; | |
852 for (intptr_t i = 0; i < min_length; i++) { | |
853 Chunk a_digit = a.GetChunkAt(i); | |
854 Chunk b_digit = b.GetChunkAt(i) - borrow; | |
855 Chunk result_digit = ((~a_digit) & b_digit & kDigitMask) + result_carry; | |
856 result.SetChunkAt(i, result_digit & kDigitMask); | |
857 borrow = b_digit >> (kChunkBitSize - 1); | |
858 result_carry = result_digit >> kDigitBitSize; | |
859 } | |
860 ASSERT(result_carry == 0); | |
861 for (intptr_t i = min_length; i < b_length; i++) { | |
862 Chunk b_digit = b.GetChunkAt(i) - borrow; | |
863 Chunk result_digit = (b_digit & kDigitMask) + result_carry; | |
864 result.SetChunkAt(i, result_digit & kDigitMask); | |
865 borrow = b_digit >> (kChunkBitSize - 1); | |
866 result_carry = result_digit >> kDigitBitSize; | |
867 } | |
868 ASSERT(result_carry == 0); | |
869 Clamp(result); | |
870 return result.raw(); | |
871 } | |
872 | |
873 ASSERT(a.IsNegative()); | |
874 ASSERT(b.IsNegative()); | |
875 // The result will be negative. | |
876 // We need to convert a and b to two's complement. Do the bit-operation there, | |
877 // and transform the resulting bits from two's complement back to separated | |
878 // magnitude and sign. | |
879 // a & b is therefore computed as ~((~(a - 1)) | (~(b - 1))) + 1 which is | |
880 // equal to ((a-1) & (b-1)) + 1. | |
881 intptr_t result_length = min_length + 1; | |
882 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); | |
883 result.ToggleSign(); | |
884 Chunk a_borrow = 1; | |
885 Chunk b_borrow = 1; | |
886 Chunk result_carry = 1; | |
887 ASSERT(a_length >= b_length); | |
888 for (intptr_t i = 0; i < b_length; i++) { | |
889 Chunk a_digit = a.GetChunkAt(i) - a_borrow; | |
890 Chunk b_digit = b.GetChunkAt(i) - b_borrow; | |
891 Chunk result_chunk = ((a_digit & b_digit) & kDigitMask) + result_carry; | |
892 result.SetChunkAt(i, result_chunk & kDigitMask); | |
893 a_borrow = a_digit >> (kChunkBitSize - 1); | |
894 b_borrow = b_digit >> (kChunkBitSize - 1); | |
895 result_carry = result_chunk >> kDigitBitSize; | |
896 } | |
897 result.SetChunkAt(a_length, result_carry); | |
898 Clamp(result); | |
899 return result.raw(); | |
900 } | |
901 | |
902 | |
903 RawBigint* BigintOperations::BitXor(const Bigint& a, const Bigint& b) { | |
904 ASSERT(IsClamped(a)); | |
905 ASSERT(IsClamped(b)); | |
906 | |
907 if (a.IsZero()) { | |
908 return Copy(b); | |
909 } | |
910 if (b.IsZero()) { | |
911 return Copy(a); | |
912 } | |
913 if (a.IsNegative() && !b.IsNegative()) { | |
914 return BitXor(b, a); | |
915 } | |
916 if ((a.IsNegative() == b.IsNegative()) && (a.Length() < b.Length())) { | |
917 return BitXor(b, a); | |
918 } | |
919 | |
920 intptr_t a_length = a.Length(); | |
921 intptr_t b_length = b.Length(); | |
922 intptr_t min_length = Utils::Minimum(a_length, b_length); | |
923 intptr_t max_length = Utils::Maximum(a_length, b_length); | |
924 if (!b.IsNegative()) { | |
925 ASSERT(!a.IsNegative()); | |
926 intptr_t result_length = max_length; | |
927 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); | |
928 | |
929 ASSERT(a_length >= b_length); | |
930 for (intptr_t i = 0; i < b_length; i++) { | |
931 result.SetChunkAt(i, a.GetChunkAt(i) ^ b.GetChunkAt(i)); | |
932 } | |
933 for (intptr_t i = b_length; i < a_length; i++) { | |
934 result.SetChunkAt(i, a.GetChunkAt(i)); | |
935 } | |
936 Clamp(result); | |
937 return result.raw(); | |
938 } | |
939 | |
940 // Bigints encode negative values by storing the absolute value and the sign | |
941 // separately. To do bit operations we need to simulate numbers that are | |
942 // implemented as two's complement. | |
943 // The negation of a positive number x would be encoded as follows in | |
944 // two's complement: n = ~(x - 1). | |
945 // The inverse transformation is hence (~n) + 1. | |
946 | |
947 if (!a.IsNegative()) { | |
948 ASSERT(b.IsNegative()); | |
949 // The result will be negative. | |
950 // We need to convert b to two's complement. Do the bit-operation there, | |
951 // and transform the resulting bits from two's complement back to separated | |
952 // magnitude and sign. | |
953 // a ^ b is therefore computed as ~((a ^ (~(b - 1))) + 1. | |
954 intptr_t result_length = max_length + 1; | |
955 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); | |
956 result.ToggleSign(); | |
957 Chunk borrow = 1; | |
958 Chunk result_carry = 1; | |
959 for (intptr_t i = 0; i < min_length; i++) { | |
960 Chunk a_digit = a.GetChunkAt(i); | |
961 Chunk b_digit = b.GetChunkAt(i) - borrow; | |
962 Chunk result_digit = | |
963 ((~(a_digit ^ ~b_digit)) & kDigitMask) + result_carry; | |
964 result.SetChunkAt(i, result_digit & kDigitMask); | |
965 borrow = b_digit >> (kChunkBitSize - 1); | |
966 result_carry = result_digit >> kDigitBitSize; | |
967 } | |
968 for (intptr_t i = min_length; i < a_length; i++) { | |
969 Chunk a_digit = a.GetChunkAt(i); | |
970 Chunk b_digit = -borrow; | |
971 Chunk result_digit = | |
972 ((~(a_digit ^ ~b_digit)) & kDigitMask) + result_carry; | |
973 result.SetChunkAt(i, result_digit & kDigitMask); | |
974 borrow = b_digit >> (kChunkBitSize - 1); | |
975 result_carry = result_digit >> kDigitBitSize; | |
976 } | |
977 for (intptr_t i = min_length; i < b_length; i++) { | |
978 // a_digit = 0. | |
979 Chunk b_digit = b.GetChunkAt(i) - borrow; | |
980 Chunk result_digit = (b_digit & kDigitMask) + result_carry; | |
981 result.SetChunkAt(i, result_digit & kDigitMask); | |
982 borrow = b_digit >> (kChunkBitSize - 1); | |
983 result_carry = result_digit >> kDigitBitSize; | |
984 } | |
985 result.SetChunkAt(max_length, result_carry); | |
986 Clamp(result); | |
987 return result.raw(); | |
988 } | |
989 | |
990 ASSERT(a.IsNegative()); | |
991 ASSERT(b.IsNegative()); | |
992 // The result will be positive. | |
993 // We need to convert a and b to two's complement, do the bit-operation there, | |
994 // and simply store the result. | |
995 // a ^ b is therefore computed as (~(a - 1)) ^ (~(b - 1)). | |
996 intptr_t result_length = max_length; | |
997 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); | |
998 Chunk a_borrow = 1; | |
999 Chunk b_borrow = 1; | |
1000 ASSERT(a_length >= b_length); | |
1001 for (intptr_t i = 0; i < b_length; i++) { | |
1002 Chunk a_digit = a.GetChunkAt(i) - a_borrow; | |
1003 Chunk b_digit = b.GetChunkAt(i) - b_borrow; | |
1004 Chunk result_chunk = (~a_digit) ^ (~b_digit); | |
1005 result.SetChunkAt(i, result_chunk & kDigitMask); | |
1006 a_borrow = a_digit >> (kChunkBitSize - 1); | |
1007 b_borrow = b_digit >> (kChunkBitSize - 1); | |
1008 } | |
1009 ASSERT(b_borrow == 0); | |
1010 for (intptr_t i = b_length; i < a_length; i++) { | |
1011 Chunk a_digit = a.GetChunkAt(i) - a_borrow; | |
1012 result.SetChunkAt(i, (~a_digit) & kDigitMask); | |
1013 a_borrow = a_digit >> (kChunkBitSize - 1); | |
1014 } | |
1015 ASSERT(a_borrow == 0); | |
1016 Clamp(result); | |
1017 return result.raw(); | |
1018 } | |
1019 | |
1020 | |
1021 RawBigint* BigintOperations::BitNot(const Bigint& bigint) { | |
1022 if (bigint.IsZero()) { | |
1023 return MinusOne(); | |
1024 } | |
1025 const Bigint& one_bigint = Bigint::Handle(One()); | |
1026 if (bigint.IsNegative()) { | |
1027 return UnsignedSubtract(bigint, one_bigint); | |
1028 } else { | |
1029 const Bigint& result = Bigint::Handle(UnsignedAdd(bigint, one_bigint)); | |
1030 result.ToggleSign(); | |
1031 return result.raw(); | |
1032 } | |
1033 } | |
1034 | |
1035 | |
1036 int BigintOperations::Compare(const Bigint& a, const Bigint& b) { | |
1037 bool a_is_negative = a.IsNegative(); | |
1038 bool b_is_negative = b.IsNegative(); | |
1039 if (a_is_negative != b_is_negative) { | |
1040 return a_is_negative ? -1 : 1; | |
1041 } | |
1042 | |
1043 if (a_is_negative) { | |
1044 return -UnsignedCompare(a, b); | |
1045 } | |
1046 return UnsignedCompare(a, b); | |
1047 } | |
1048 | |
1049 | |
1050 RawBigint* BigintOperations::AddSubtract(const Bigint& a, | |
1051 const Bigint& b, | |
1052 bool negate_b) { | |
1053 ASSERT(IsClamped(a)); | |
1054 ASSERT(IsClamped(b)); | |
1055 Bigint& result = Bigint::Handle(); | |
1056 // We perform the subtraction by simulating a negation of the b-argument. | |
1057 bool b_is_negative = negate_b ? !b.IsNegative() : b.IsNegative(); | |
1058 | |
1059 // If both are of the same sign, then we can compute the unsigned addition | |
1060 // and then simply adjust the sign (if necessary). | |
1061 // Ex: -3 + -5 -> -(3 + 5) | |
1062 if (a.IsNegative() == b_is_negative) { | |
1063 result = UnsignedAdd(a, b); | |
1064 result.SetSign(b_is_negative); | |
1065 ASSERT(IsClamped(result)); | |
1066 return result.raw(); | |
1067 } | |
1068 | |
1069 // The signs differ. | |
1070 // Take the number with small magnitude and subtract its absolute value from | |
1071 // the absolute value of the other number. Then adjust the sign, if necessary. | |
1072 // The sign is the same as for the number with the greater magnitude. | |
1073 // Ex: -8 + 3 -> -(8 - 3) | |
1074 // 8 + -3 -> (8 - 3) | |
1075 // -3 + 8 -> (8 - 3) | |
1076 // 3 + -8 -> -(8 - 3) | |
1077 int comp = UnsignedCompare(a, b); | |
1078 if (comp < 0) { | |
1079 result = UnsignedSubtract(b, a); | |
1080 result.SetSign(b_is_negative); | |
1081 } else if (comp > 0) { | |
1082 result = UnsignedSubtract(a, b); | |
1083 result.SetSign(a.IsNegative()); | |
1084 } else { | |
1085 return Zero(); | |
1086 } | |
1087 ASSERT(IsClamped(result)); | |
1088 return result.raw(); | |
1089 } | |
1090 | |
1091 | |
1092 int BigintOperations::UnsignedCompare(const Bigint& a, const Bigint& b) { | |
1093 ASSERT(IsClamped(a)); | |
1094 ASSERT(IsClamped(b)); | |
1095 intptr_t a_length = a.Length(); | |
1096 intptr_t b_length = b.Length(); | |
1097 if (a_length < b_length) return -1; | |
1098 if (a_length > b_length) return 1; | |
1099 for (intptr_t i = a_length - 1; i >= 0; i--) { | |
1100 Chunk digit_a = a.GetChunkAt(i); | |
1101 Chunk digit_b = b.GetChunkAt(i); | |
1102 if (digit_a < digit_b) return -1; | |
1103 if (digit_a > digit_b) return 1; | |
1104 // Else look at the next digit. | |
1105 } | |
1106 return 0; // They are equal. | |
1107 } | |
1108 | |
1109 | |
1110 int BigintOperations::UnsignedCompareNonClamped( | |
1111 const Bigint& a, const Bigint& b) { | |
1112 intptr_t a_length = a.Length(); | |
1113 intptr_t b_length = b.Length(); | |
1114 while (a_length > b_length) { | |
1115 if (a.GetChunkAt(a_length - 1) != 0) return 1; | |
1116 a_length--; | |
1117 } | |
1118 while (b_length > a_length) { | |
1119 if (b.GetChunkAt(b_length - 1) != 0) return -1; | |
1120 b_length--; | |
1121 } | |
1122 for (intptr_t i = a_length - 1; i >= 0; i--) { | |
1123 Chunk digit_a = a.GetChunkAt(i); | |
1124 Chunk digit_b = b.GetChunkAt(i); | |
1125 if (digit_a < digit_b) return -1; | |
1126 if (digit_a > digit_b) return 1; | |
1127 // Else look at the next digit. | |
1128 } | |
1129 return 0; // They are equal. | |
1130 } | |
1131 | |
1132 | |
1133 RawBigint* BigintOperations::UnsignedAdd(const Bigint& a, const Bigint& b) { | |
1134 ASSERT(IsClamped(a)); | |
1135 ASSERT(IsClamped(b)); | |
1136 | |
1137 intptr_t a_length = a.Length(); | |
1138 intptr_t b_length = b.Length(); | |
1139 if (a_length < b_length) { | |
1140 return UnsignedAdd(b, a); | |
1141 } | |
1142 | |
1143 // We might request too much space, in which case we will adjust the length | |
1144 // afterwards. | |
1145 intptr_t result_length = a_length + 1; | |
1146 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); | |
1147 | |
1148 Chunk carry = 0; | |
1149 // b has fewer digits than a. | |
1150 ASSERT(b_length <= a_length); | |
1151 for (intptr_t i = 0; i < b_length; i++) { | |
1152 Chunk sum = a.GetChunkAt(i) + b.GetChunkAt(i) + carry; | |
1153 result.SetChunkAt(i, sum & kDigitMask); | |
1154 carry = sum >> kDigitBitSize; | |
1155 } | |
1156 // Copy over the remaining digits of a, but don't forget the carry. | |
1157 for (intptr_t i = b_length; i < a_length; i++) { | |
1158 Chunk sum = a.GetChunkAt(i) + carry; | |
1159 result.SetChunkAt(i, sum & kDigitMask); | |
1160 carry = sum >> kDigitBitSize; | |
1161 } | |
1162 // Shrink the result if there was no overflow. Otherwise apply the carry. | |
1163 if (carry == 0) { | |
1164 // TODO(floitsch): We change the size of bigint-objects here. | |
1165 result.SetLength(a_length); | |
1166 } else { | |
1167 result.SetChunkAt(a_length, carry); | |
1168 } | |
1169 ASSERT(IsClamped(result)); | |
1170 return result.raw(); | |
1171 } | |
1172 | |
1173 | |
1174 RawBigint* BigintOperations::UnsignedSubtract(const Bigint& a, | |
1175 const Bigint& b) { | |
1176 ASSERT(IsClamped(a)); | |
1177 ASSERT(IsClamped(b)); | |
1178 ASSERT(UnsignedCompare(a, b) >= 0); | |
1179 | |
1180 const int kSignBitPos = Bigint::kChunkSize * kBitsPerByte - 1; | |
1181 | |
1182 intptr_t a_length = a.Length(); | |
1183 intptr_t b_length = b.Length(); | |
1184 | |
1185 // We might request too much space, in which case we will adjust the length | |
1186 // afterwards. | |
1187 intptr_t result_length = a_length; | |
1188 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length)); | |
1189 | |
1190 Chunk borrow = 0; | |
1191 ASSERT(b_length <= a_length); | |
1192 for (intptr_t i = 0; i < b_length; i++) { | |
1193 Chunk difference = a.GetChunkAt(i) - b.GetChunkAt(i) - borrow; | |
1194 result.SetChunkAt(i, difference & kDigitMask); | |
1195 borrow = difference >> kSignBitPos; | |
1196 ASSERT((borrow == 0) || (borrow == 1)); | |
1197 } | |
1198 // Copy over the remaining digits of a, but don't forget the borrow. | |
1199 for (intptr_t i = b_length; i < a_length; i++) { | |
1200 Chunk difference = a.GetChunkAt(i) - borrow; | |
1201 result.SetChunkAt(i, difference & kDigitMask); | |
1202 borrow = (difference >> kSignBitPos); | |
1203 ASSERT((borrow == 0) || (borrow == 1)); | |
1204 } | |
1205 ASSERT(borrow == 0); | |
1206 Clamp(result); | |
1207 return result.raw(); | |
1208 } | |
1209 | |
1210 | |
1211 RawBigint* BigintOperations::MultiplyWithDigit( | |
1212 const Bigint& bigint, Chunk digit) { | |
1213 // TODO(floitsch): implement MultiplyWithDigit. | |
1214 ASSERT(digit <= kDigitMaxValue); | |
1215 if (digit == 0) return Zero(); | |
1216 | |
1217 Bigint& tmp = Bigint::Handle(Bigint::Allocate(1)); | |
1218 tmp.SetChunkAt(0, digit); | |
1219 return Multiply(bigint, tmp); | |
1220 } | |
1221 | |
1222 | |
1223 void BigintOperations::DivideRemainder( | |
1224 const Bigint& a, const Bigint& b, Bigint* quotient, Bigint* remainder) { | |
1225 // TODO(floitsch): This function is very memory-intensive since all | |
1226 // intermediate bigint results are allocated in new memory. It would be | |
1227 // much more efficient to reuse the space of temporary intermediate variables. | |
1228 ASSERT(IsClamped(a)); | |
1229 ASSERT(IsClamped(b)); | |
1230 ASSERT(!b.IsZero()); | |
1231 | |
1232 int comp = UnsignedCompare(a, b); | |
1233 if (comp < 0) { | |
1234 (*quotient) ^= Zero(); | |
1235 (*remainder) ^= Copy(a); // TODO(floitsch): can we reuse the input? | |
1236 return; | |
1237 } else if (comp == 0) { | |
1238 (*quotient) ^= One(); | |
1239 quotient->SetSign(a.IsNegative() != b.IsNegative()); | |
1240 (*remainder) ^= Zero(); | |
1241 return; | |
1242 } | |
1243 | |
1244 // High level description: | |
1245 // The algorithm is basically the algorithm that is taught in school: | |
1246 // Let a the dividend and b the divisor. We are looking for | |
1247 // the quotient q = truncate(a / b), and | |
1248 // the remainder r = a - q * b. | |
1249 // School algorithm: | |
1250 // q = 0 | |
1251 // n = number_of_digits(a) - number_of_digits(b) | |
1252 // for (i = n; i >= 0; i--) { | |
1253 // Maximize k such that k*y*10^i is less than or equal to a and | |
1254 // (k + 1)*y*10^i is greater. | |
1255 // q = q + k * 10^i // Add new digit to result. | |
1256 // a = a - k * b * 10^i | |
1257 // } | |
1258 // r = a | |
1259 // | |
1260 // Instead of working in base 10 we work in base kDigitBitSize. | |
1261 | |
1262 intptr_t b_length = b.Length(); | |
1263 int normalization_shift = | |
1264 kDigitBitSize - CountBits(b.GetChunkAt(b_length - 1)); | |
1265 Bigint& dividend = Bigint::Handle(ShiftLeft(a, normalization_shift)); | |
1266 const Bigint& divisor = Bigint::Handle(ShiftLeft(b, normalization_shift)); | |
1267 dividend.SetSign(false); | |
1268 divisor.SetSign(false); | |
1269 | |
1270 intptr_t dividend_length = dividend.Length(); | |
1271 intptr_t divisor_length = b_length; | |
1272 ASSERT(divisor_length == divisor.Length()); | |
1273 | |
1274 intptr_t quotient_length = dividend_length - divisor_length + 1; | |
1275 *quotient ^= Bigint::Allocate(quotient_length); | |
1276 quotient->SetSign(a.IsNegative() != b.IsNegative()); | |
1277 | |
1278 intptr_t quotient_pos = dividend_length - divisor_length; | |
1279 // Find the first quotient-digit. | |
1280 // The first digit must be computed separately from the other digits because | |
1281 // the preconditions for the loop are not yet satisfied. | |
1282 // For simplicity use a shifted divisor, so that the comparison and | |
1283 // subtraction are easier. | |
1284 int divisor_shift_amount = dividend_length - divisor_length; | |
1285 Bigint& shifted_divisor = | |
1286 Bigint::Handle(DigitsShiftLeft(divisor, divisor_shift_amount)); | |
1287 Chunk first_quotient_digit = 0; | |
1288 while (UnsignedCompare(dividend, shifted_divisor) >= 0) { | |
1289 first_quotient_digit++; | |
1290 dividend ^= Subtract(dividend, shifted_divisor); | |
1291 } | |
1292 quotient->SetChunkAt(quotient_pos--, first_quotient_digit); | |
1293 | |
1294 // Find the remainder of the digits. | |
1295 | |
1296 Chunk first_divisor_digit = divisor.GetChunkAt(divisor_length - 1); | |
1297 // The short divisor only represents the first two digits of the divisor. | |
1298 // If the divisor has only one digit, then the second part is zeroed out. | |
1299 Bigint& short_divisor = Bigint::Handle(Bigint::Allocate(2)); | |
1300 if (divisor_length > 1) { | |
1301 short_divisor.SetChunkAt(0, divisor.GetChunkAt(divisor_length - 2)); | |
1302 } else { | |
1303 short_divisor.SetChunkAt(0, 0); | |
1304 } | |
1305 short_divisor.SetChunkAt(1, first_divisor_digit); | |
1306 // The following bigint will be used inside the loop. It is allocated outside | |
1307 // the loop to avoid repeated allocations. | |
1308 Bigint& target = Bigint::Handle(Bigint::Allocate(3)); | |
1309 // The dividend_length here must be from the initial dividend. | |
1310 for (intptr_t i = dividend_length - 1; i >= divisor_length; i--) { | |
1311 // Invariant: let t = i - divisor_length | |
1312 // then dividend / (divisor << (t * kDigitBitSize)) <= kDigitMaxValue. | |
1313 // Ex: dividend: 53451232, and divisor: 535 (with t == 5) is ok. | |
1314 // dividend: 56822123, and divisor: 563 (with t == 5) is bad. | |
1315 // dividend: 6822123, and divisor: 563 (with t == 5) is ok. | |
1316 | |
1317 // The dividend has changed. So recompute its length. | |
1318 dividend_length = dividend.Length(); | |
1319 Chunk dividend_digit; | |
1320 if (i > dividend_length) { | |
1321 quotient->SetChunkAt(quotient_pos--, 0); | |
1322 continue; | |
1323 } else if (i == dividend_length) { | |
1324 dividend_digit = 0; | |
494 } else { | 1325 } else { |
495 n = Utils::Minimum(a.NumberOfBits(), b.NumberOfBits()); | 1326 ASSERT(i + 1 == dividend_length); |
496 } | 1327 dividend_digit = dividend.GetChunkAt(i); |
497 } else if (a.IsNegative() || b.IsNegative()) { | 1328 } |
498 if (tt[2]) { | 1329 Chunk quotient_digit; |
499 rflip = rborrow = -1; | 1330 // Compute an estimate of the quotient_digit. The estimate will never |
500 } | 1331 // be too small. |
501 n = Utils::Maximum(a.NumberOfBits(), b.NumberOfBits()); | 1332 if (dividend_digit == first_divisor_digit) { |
502 } else { | 1333 // Small shortcut: the else-branch would compute a value > kDigitMaxValue. |
503 if (tt[2]) { | 1334 // However, by hypothesis, we know that the quotient_digit must fit into |
504 n = Utils::Maximum(a.NumberOfBits(), b.NumberOfBits()); | 1335 // a digit. Avoid going through repeated iterations of the adjustment |
1336 // loop by directly assigning kDigitMaxValue to the quotient_digit. | |
1337 // Ex: 51235 / 523. | |
1338 // 51 / 5 would yield 10 (if computed in the else branch). | |
1339 // However we know that 9 is the maximal value. | |
1340 quotient_digit = kDigitMaxValue; | |
505 } else { | 1341 } else { |
506 n = Utils::Minimum(a.NumberOfBits(), b.NumberOfBits()); | 1342 // Compute the estimate by using two digits of the dividend and one of |
507 } | 1343 // the divisor. |
508 } | 1344 // Ex: 32421 / 535 |
509 bool aflip = false; | 1345 // 32 / 5 -> 6 |
510 int acarry = 0; | 1346 // The estimate would hence be 6. |
511 if (a.IsNegative()) { | 1347 DoubleChunk two_dividend_digits = dividend_digit; |
512 aflip = true; | 1348 two_dividend_digits <<= kDigitBitSize; |
513 acarry = 1; | 1349 two_dividend_digits += dividend.GetChunkAt(i - 1); |
514 } | 1350 DoubleChunk q = two_dividend_digits / first_divisor_digit; |
515 bool bflip = false; | 1351 if (q > kDigitMaxValue) q = kDigitMaxValue; |
516 int bcarry = 0; | 1352 quotient_digit = static_cast<Chunk>(q); |
517 if (b.IsNegative()) { | 1353 } |
518 bflip = true; | 1354 |
519 bcarry = 1; | 1355 // Refine estimation. |
520 } | 1356 quotient_digit++; // The following loop will start by decrementing. |
521 for (int i = 0 ; i < n ; ++i) { | 1357 Bigint& estimation_product = Bigint::Handle(); |
522 int ab = (a.Bit(i) ^ (aflip ? 1 : 0)) + acarry; | 1358 target.SetChunkAt(0, ((i - 2) < 0) ? 0 : dividend.GetChunkAt(i - 2)); |
523 ASSERT(ab <= 2 && ab >= 0); | 1359 target.SetChunkAt(1, ((i - 1) < 0) ? 0 : dividend.GetChunkAt(i - 1)); |
524 int bb = (b.Bit(i) ^ (bflip ? 1 : 0)) + bcarry; | 1360 target.SetChunkAt(2, dividend_digit); |
525 ASSERT(bb <= 2 && bb >= 0); | 1361 do { |
526 int r = tt[(ab & 1) + ((bb & 1) << 1)]; | 1362 quotient_digit = (quotient_digit - 1) & kDigitMask; |
527 r = r + rborrow; | 1363 estimation_product ^= MultiplyWithDigit(short_divisor, quotient_digit); |
528 ASSERT(r >= -1 && r <= 1); | 1364 } while (UnsignedCompareNonClamped(estimation_product, target) > 0); |
529 if ((r ^ rflip) & 1) { | 1365 // At this point the quotient_digit is fairly accurate. |
530 int status = BN_set_bit(TmpBN(), i); | 1366 // At the worst it is off by one. |
531 ASSERT(status == 1); | 1367 // Remove a multiple of the divisor. If the estimate is incorrect we will |
532 } | 1368 // subtract the divisor another time. |
533 acarry = ab >> 1; | 1369 // Let t = i - divisor_length. |
534 bcarry = bb >> 1; | 1370 // dividend -= (quotient_digit * divisor) << (t * kDigitBitSize); |
535 rborrow = r >> 1; | 1371 shifted_divisor ^= MultiplyWithDigit(divisor, quotient_digit); |
536 } | 1372 shifted_divisor ^= DigitsShiftLeft(shifted_divisor, i - divisor_length); |
537 if (rborrow) { | 1373 dividend = Subtract(dividend, shifted_divisor); |
538 int status = BN_set_bit(TmpBN(), n); | 1374 if (dividend.IsNegative()) { |
539 ASSERT(status == 1); | 1375 // The estimation was still too big. |
540 } | 1376 quotient_digit--; |
541 if (rflip) { | 1377 // TODO(floitsch): allocate space for the shifted_divisor once and reuse |
542 // FIXME(benl): can be changed to use BN_set_negative() on more | 1378 // it at every iteration. |
543 // recent OpenSSL releases (> 1.0.0). | 1379 shifted_divisor ^= DigitsShiftLeft(divisor, i - divisor_length); |
544 ASSERT(!BN_is_zero(TmpBN())); | 1380 // TODO(floitsch): reuse the space of the previous dividend. |
545 TmpBN()->neg = 1; | 1381 dividend = Add(dividend, shifted_divisor); |
546 } | 1382 } |
547 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); | 1383 quotient->SetChunkAt(quotient_pos--, quotient_digit); |
548 return result.raw(); | 1384 } |
549 } | 1385 ASSERT(quotient_pos == -1); |
550 | 1386 Clamp(*quotient); |
551 | 1387 *remainder ^= ShiftRight(dividend, normalization_shift); |
552 RawSmi* BigintOperations::BitOpWithSmi(Token::Kind kind, | 1388 remainder->SetSign(a.IsNegative()); |
553 const Bigint& bigint, | 1389 } |
554 const Smi& smi) { | 1390 |
555 ASSERT((kind == Token::kBIT_OR) || (kind == Token::kBIT_AND)); | 1391 |
556 intptr_t smi_value = smi.Value(); | 1392 void BigintOperations::Clamp(const Bigint& bigint) { |
557 intptr_t big_value = 0; | 1393 intptr_t length = bigint.Length(); |
558 // We take Smi::kBits + 1 (one more bit), in case bigint is negative. | 1394 while (length > 0 && (bigint.GetChunkAt(length - 1) == 0)) { |
559 ASSERT((Smi::kBits + 1) <= (sizeof(big_value) * kBitsPerByte)); | 1395 length--; |
560 intptr_t num_bits = bigint.NumberOfBits(); | 1396 } |
561 int n = Utils::Minimum(num_bits, Smi::kBits + 1); | 1397 // TODO(floitsch): We change the size of bigint-objects here. |
562 for (int i = n - 1; i >= 0; i--) { | 1398 bigint.SetLength(length); |
563 big_value <<= 1; | 1399 } |
564 big_value += bigint.Bit(i); | 1400 |
565 } | 1401 |
566 if (bigint.IsNegative()) { | 1402 RawBigint* BigintOperations::Copy(const Bigint& bigint) { |
567 big_value = -big_value; | 1403 intptr_t bigint_length = bigint.Length(); |
568 } | 1404 Bigint& copy = Bigint::Handle(Bigint::Allocate(bigint_length)); |
569 intptr_t result; | 1405 for (intptr_t i = 0; i < bigint_length; i++) { |
570 if (kind == Token::kBIT_OR) { | 1406 copy.SetChunkAt(i, bigint.GetChunkAt(i)); |
571 result = smi_value | big_value; | 1407 } |
572 } else { | 1408 copy.SetSign(bigint.IsNegative()); |
573 result = smi_value & big_value; | 1409 return copy.raw(); |
574 } | 1410 } |
575 ASSERT(Smi::IsValid(result)); | 1411 |
576 return Smi::New(result); | 1412 |
577 } | 1413 int BigintOperations::CountBits(Chunk digit) { |
578 | 1414 int result = 0; |
579 | 1415 while (digit != 0) { |
580 RawBigint* BigintOperations::BitAnd(const Bigint& a, const Bigint& b) { | 1416 digit >>= 1; |
581 static bool tt_and[] = { false, false, false, true }; | 1417 result++; |
582 return BitTT(a, b, tt_and); | 1418 } |
583 } | 1419 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 } | 1420 } |
636 | 1421 |
637 } // namespace dart | 1422 } // namespace dart |
OLD | NEW |