OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 // TODO(srdjan): fix limitations. | 5 // TODO(srdjan): fix limitations. |
6 // - shift amount must be a Smi. | 6 // - shift amount must be a Smi. |
7 class _IntegerImplementation extends _Num { | 7 class _IntegerImplementation extends _Num { |
8 // The Dart class _Bigint extending _IntegerImplementation requires a | 8 // The Dart class _Bigint extending _IntegerImplementation requires a |
9 // default constructor. | 9 // default constructor. |
10 | 10 |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 int floor() { return this; } | 168 int floor() { return this; } |
169 int ceil() { return this; } | 169 int ceil() { return this; } |
170 int truncate() { return this; } | 170 int truncate() { return this; } |
171 | 171 |
172 double roundToDouble() { return this.toDouble(); } | 172 double roundToDouble() { return this.toDouble(); } |
173 double floorToDouble() { return this.toDouble(); } | 173 double floorToDouble() { return this.toDouble(); } |
174 double ceilToDouble() { return this.toDouble(); } | 174 double ceilToDouble() { return this.toDouble(); } |
175 double truncateToDouble() { return this.toDouble(); } | 175 double truncateToDouble() { return this.toDouble(); } |
176 | 176 |
177 num clamp(num lowerLimit, num upperLimit) { | 177 num clamp(num lowerLimit, num upperLimit) { |
178 if (lowerLimit is! num) throw new ArgumentError(lowerLimit); | 178 if (lowerLimit is! num) { |
179 if (upperLimit is! num) throw new ArgumentError(upperLimit); | 179 throw new ArgumentError.value(lowerLimit, "lowerLimit"); |
| 180 } |
| 181 if (upperLimit is! num) { |
| 182 throw new ArgumentError.value(upperLimit, "upperLimit"); |
| 183 } |
180 | 184 |
181 // Special case for integers. | 185 // Special case for integers. |
182 if (lowerLimit is int && upperLimit is int) { | 186 if (lowerLimit is int && upperLimit is int && |
183 if (lowerLimit > upperLimit) { | 187 lowerLimit <= upperLimit) { |
184 throw new ArgumentError(lowerLimit); | |
185 } | |
186 if (this < lowerLimit) return lowerLimit; | 188 if (this < lowerLimit) return lowerLimit; |
187 if (this > upperLimit) return upperLimit; | 189 if (this > upperLimit) return upperLimit; |
188 return this; | 190 return this; |
189 } | 191 } |
190 // Generic case involving doubles. | 192 // Generic case involving doubles, and invalid integer ranges. |
191 if (lowerLimit.compareTo(upperLimit) > 0) { | 193 if (lowerLimit.compareTo(upperLimit) > 0) { |
192 throw new ArgumentError(lowerLimit); | 194 throw new RangeError.range(upperLimit, lowerLimit, null, "upperLimit"); |
193 } | 195 } |
194 if (lowerLimit.isNaN) return lowerLimit; | 196 if (lowerLimit.isNaN) return lowerLimit; |
195 // Note that we don't need to care for -0.0 for the lower limit. | 197 // Note that we don't need to care for -0.0 for the lower limit. |
196 if (this < lowerLimit) return lowerLimit; | 198 if (this < lowerLimit) return lowerLimit; |
197 if (this.compareTo(upperLimit) > 0) return upperLimit; | 199 if (this.compareTo(upperLimit) > 0) return upperLimit; |
198 return this; | 200 return this; |
199 } | 201 } |
200 | 202 |
201 int toInt() { return this; } | 203 int toInt() { return this; } |
202 double toDouble() { return new _Double.fromInteger(this); } | 204 double toDouble() { return new _Double.fromInteger(this); } |
203 _Bigint _toBigint() { return new _Bigint._fromInt(this); } | 205 _Bigint _toBigint() { return new _Bigint._fromInt(this); } |
204 num _toBigintOrDouble() { return _toBigint(); } | 206 num _toBigintOrDouble() { return _toBigint(); } |
205 | 207 |
206 String toStringAsFixed(int fractionDigits) { | 208 String toStringAsFixed(int fractionDigits) { |
207 return this.toDouble().toStringAsFixed(fractionDigits); | 209 return this.toDouble().toStringAsFixed(fractionDigits); |
208 } | 210 } |
209 String toStringAsExponential([int fractionDigits]) { | 211 String toStringAsExponential([int fractionDigits]) { |
210 return this.toDouble().toStringAsExponential(fractionDigits); | 212 return this.toDouble().toStringAsExponential(fractionDigits); |
211 } | 213 } |
212 String toStringAsPrecision(int precision) { | 214 String toStringAsPrecision(int precision) { |
213 return this.toDouble().toStringAsPrecision(precision); | 215 return this.toDouble().toStringAsPrecision(precision); |
214 } | 216 } |
215 | 217 |
216 static const _digits = "0123456789abcdefghijklmnopqrstuvwxyz"; | 218 static const _digits = "0123456789abcdefghijklmnopqrstuvwxyz"; |
217 | 219 |
218 String toRadixString(int radix) { | 220 String toRadixString(int radix) { |
219 if (radix is! int || radix < 2 || radix > 36) { | 221 if (radix < 2 || 36 < radix) { |
220 throw new ArgumentError(radix); | 222 throw new RangeError.range(radix, 2, 36, "radix"); |
221 } | 223 } |
222 if (radix & (radix - 1) == 0) { | 224 if (radix & (radix - 1) == 0) { |
223 return _toPow2String(radix); | 225 return _toPow2String(radix); |
224 } | 226 } |
225 if (radix == 10) return this.toString(); | 227 if (radix == 10) return this.toString(); |
226 final bool isNegative = this < 0; | 228 final bool isNegative = this < 0; |
227 int value = isNegative ? -this : this; | 229 int value = isNegative ? -this : this; |
228 List temp = new List(); | 230 List temp = new List(); |
229 do { | 231 do { |
230 int digit = value % radix; | 232 int digit = value % radix; |
(...skipping 29 matching lines...) Expand all Loading... |
260 string._setAt(--length, _digits.codeUnitAt(value & mask)); | 262 string._setAt(--length, _digits.codeUnitAt(value & mask)); |
261 value >>= bitsPerDigit; | 263 value >>= bitsPerDigit; |
262 } while (value > 0); | 264 } while (value > 0); |
263 return string; | 265 return string; |
264 } | 266 } |
265 | 267 |
266 _leftShiftWithMask32(count, mask) native "Integer_leftShiftWithMask32"; | 268 _leftShiftWithMask32(count, mask) native "Integer_leftShiftWithMask32"; |
267 | 269 |
268 // Returns pow(this, e) % m. | 270 // Returns pow(this, e) % m. |
269 int modPow(int e, int m) { | 271 int modPow(int e, int m) { |
270 if (e is! int) throw new ArgumentError(e); | 272 if (e is! int) { |
271 if (m is! int) throw new ArgumentError(m); | 273 throw new ArgumentError.value(e, "exponent", "not an integer"); |
272 if (e < 0) throw new RangeError(e); | 274 } |
273 if (m <= 0) throw new RangeError(m); | 275 if (m is! int) { |
| 276 throw new ArgumentError.value(m, "modulus", "not an integer"); |
| 277 } |
| 278 if (e < 0) throw new RangeError.range(e, 0, null, "exponent"); |
| 279 if (m <= 0) throw new RangeError.range(m, 1, null, "modulus"); |
274 if (e == 0) return 1; | 280 if (e == 0) return 1; |
275 if (e is _Bigint || m is _Bigint) { | 281 if (e is _Bigint || m is _Bigint) { |
276 return _toBigint().modPow(e, m); | 282 return _toBigint().modPow(e, m); |
277 } | 283 } |
278 int b = this; | 284 int b = this; |
279 if (b < 0 || b > m) { | 285 if (b < 0 || b > m) { |
280 b %= m; | 286 b %= m; |
281 } | 287 } |
282 int r = 1; | 288 int r = 1; |
283 while (e > 0) { | 289 while (e > 0) { |
284 if (e.isOdd) { | 290 if (e.isOdd) { |
285 r = (r * b) % m; | 291 r = (r * b) % m; |
286 } | 292 } |
287 e >>= 1; | 293 e >>= 1; |
288 b = (b * b) % m; | 294 b = (b * b) % m; |
289 } | 295 } |
290 return r; | 296 return r; |
291 } | 297 } |
292 | 298 |
293 // If inv is false, returns gcd(x, y). | 299 // If inv is false, returns gcd(x, y). |
294 // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1. | 300 // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1. |
295 // If inv is true and gcd(x, y) != 1, throws RangeError("Not coprime"). | 301 // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime"). |
296 static int _binaryGcd(int x, int y, bool inv) { | 302 static int _binaryGcd(int x, int y, bool inv) { |
297 int s = 0; | 303 int s = 0; |
298 if (!inv) { | 304 if (!inv) { |
299 while (x.isEven && y.isEven) { | 305 while (x.isEven && y.isEven) { |
300 x >>= 1; | 306 x >>= 1; |
301 y >>= 1; | 307 y >>= 1; |
302 s++; | 308 s++; |
303 } | 309 } |
304 if (y.isOdd) { | 310 if (y.isOdd) { |
305 var t = x; | 311 var t = x; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 u -= v; | 351 u -= v; |
346 if (ac) a -= c; | 352 if (ac) a -= c; |
347 b -= d; | 353 b -= d; |
348 } else { | 354 } else { |
349 v -= u; | 355 v -= u; |
350 if (ac) c -= a; | 356 if (ac) c -= a; |
351 d -= b; | 357 d -= b; |
352 } | 358 } |
353 } while (u != 0); | 359 } while (u != 0); |
354 if (!inv) return v << s; | 360 if (!inv) return v << s; |
355 if (v != 1) throw new RangeError("Not coprime"); | 361 if (v != 1) { |
| 362 throw new Exception("Not coprime"); |
| 363 } |
356 if (d < 0) { | 364 if (d < 0) { |
357 d += x; | 365 d += x; |
358 if (d < 0) d += x; | 366 if (d < 0) d += x; |
359 } else if (d > x) { | 367 } else if (d > x) { |
360 d -= x; | 368 d -= x; |
361 if (d > x) d -= x; | 369 if (d > x) d -= x; |
362 } | 370 } |
363 return d; | 371 return d; |
364 } | 372 } |
365 | 373 |
366 // Returns 1/this % m, with m > 0. | 374 // Returns 1/this % m, with m > 0. |
367 int modInverse(int m) { | 375 int modInverse(int m) { |
368 if (m is! int) throw new ArgumentError(m); | 376 if (m is! int) { |
369 if (m <= 0) throw new RangeError(m); | 377 throw new ArgumentError.value(m, "modulus", "not an integer"); |
| 378 } |
| 379 if (m <= 0) throw new RangeError.range(m, 1, null, "modulus"); |
370 if (m == 1) return 0; | 380 if (m == 1) return 0; |
371 if (m is _Bigint) { | 381 if (m is _Bigint) { |
372 return _toBigint().modInverse(m); | 382 return _toBigint().modInverse(m); |
373 } | 383 } |
374 int t = this; | 384 int t = this; |
375 if ((t < 0) || (t >= m)) t %= m; | 385 if ((t < 0) || (t >= m)) t %= m; |
376 if (t == 1) return 1; | 386 if (t == 1) return 1; |
377 if ((t == 0) || (t.isEven && m.isEven)) throw new RangeError("Not coprime"); | 387 if ((t == 0) || (t.isEven && m.isEven)) { |
| 388 throw new Exception("Not coprime"); |
| 389 } |
378 return _binaryGcd(m, t, true); | 390 return _binaryGcd(m, t, true); |
379 } | 391 } |
380 | 392 |
381 // Returns gcd of abs(this) and abs(other), with this != 0 and other !=0. | 393 // Returns gcd of abs(this) and abs(other), with this != 0 and other !=0. |
382 int gcd(int other) { | 394 int gcd(int other) { |
383 if (other is! int) throw new ArgumentError(other); | 395 if (other is! int) { |
384 if ((this == 0) || (other == 0)) throw new RangeError(0); | 396 throw new ArgumentError.value(other, "other", "not an integer"); |
| 397 } |
| 398 if (this == 0) { |
| 399 throw new ArgumentError.value(this, "this", "must not be zero"); |
| 400 } |
| 401 if (other == 0) { |
| 402 throw new ArgumentError.value(this, "other", "must not be zero"); |
| 403 } |
385 int x = this.abs(); | 404 int x = this.abs(); |
386 int y = other.abs(); | 405 int y = other.abs(); |
387 if ((x == 1) || (y == 1)) return 1; | 406 if ((x == 1) || (y == 1)) return 1; |
388 if (other is _Bigint) { | 407 if (other is _Bigint) { |
389 return _toBigint().gcd(other); | 408 return _toBigint().gcd(other); |
390 } | 409 } |
391 return _binaryGcd(x, y, false); | 410 return _binaryGcd(x, y, false); |
392 } | 411 } |
393 } | 412 } |
394 | 413 |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
604 // Shift by mint exceeds range that can be handled by the VM. | 623 // Shift by mint exceeds range that can be handled by the VM. |
605 int _shrFromInt(int other) { | 624 int _shrFromInt(int other) { |
606 if (other < 0) { | 625 if (other < 0) { |
607 return -1; | 626 return -1; |
608 } else { | 627 } else { |
609 return 0; | 628 return 0; |
610 } | 629 } |
611 } | 630 } |
612 int _shlFromInt(int other) native "Mint_shlFromInt"; | 631 int _shlFromInt(int other) native "Mint_shlFromInt"; |
613 } | 632 } |
OLD | NEW |