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 part of dart._interceptors; | 5 part of dart._interceptors; |
6 | 6 |
7 /** | 7 /** |
8 * The implementation of Dart's int & double methods. | 8 * The implementation of Dart's int & double methods. |
9 * These are made available as extension methods on `Number` in JS. | 9 * These are made available as extension methods on `Number` in JS. |
10 */ | 10 */ |
(...skipping 22 matching lines...) Expand all Loading... |
33 } else { | 33 } else { |
34 return -1; | 34 return -1; |
35 } | 35 } |
36 } | 36 } |
37 | 37 |
38 bool get isNegative => (this == 0) ? (1 / this) < 0 : this < 0; | 38 bool get isNegative => (this == 0) ? (1 / this) < 0 : this < 0; |
39 | 39 |
40 bool get isNaN => JS('bool', r'isNaN(#)', this); | 40 bool get isNaN => JS('bool', r'isNaN(#)', this); |
41 | 41 |
42 bool get isInfinite { | 42 bool get isInfinite { |
43 return JS('bool', r'# == Infinity', this) | 43 return JS('bool', r'# == (1/0)', this) |
44 || JS('bool', r'# == -Infinity', this); | 44 || JS('bool', r'# == (-1/0)', this); |
45 } | 45 } |
46 | 46 |
47 bool get isFinite => JS('bool', r'isFinite(#)', this); | 47 bool get isFinite => JS('bool', r'isFinite(#)', this); |
48 | 48 |
49 JSNumber remainder(num b) { | 49 JSNumber remainder(num b) { |
50 checkNull(b); // TODO(ngeoffray): This is not specified but co19 tests it. | 50 if (b is! num) throw argumentErrorValue(b); |
51 return JS('num', r'# % #', this, b); | 51 return JS('num', r'# % #', this, b); |
52 } | 52 } |
53 | 53 |
54 JSNumber abs() => JS('num', r'Math.abs(#)', this); | 54 JSNumber abs() => JS('num', r'Math.abs(#)', this); |
55 | 55 |
56 JSNumber get sign => this > 0 ? 1 : this < 0 ? -1 : this; | 56 JSNumber get sign => this > 0 ? 1 : this < 0 ? -1 : this; |
57 | 57 |
58 static const int _MIN_INT32 = -0x80000000; | 58 static const int _MIN_INT32 = -0x80000000; |
59 static const int _MAX_INT32 = 0x7FFFFFFF; | 59 static const int _MAX_INT32 = 0x7FFFFFFF; |
60 | 60 |
61 int toInt() { | 61 int toInt() { |
62 if (this >= _MIN_INT32 && this <= _MAX_INT32) { | 62 if (this >= _MIN_INT32 && this <= _MAX_INT32) { |
63 return JS('int', '# | 0', this); | 63 return JS('int', '# | 0', this); |
64 } | 64 } |
65 if (JS('bool', r'isFinite(#)', this)) { | 65 if (JS('bool', r'isFinite(#)', this)) { |
66 return JS('int', r'# + 0', truncateToDouble()); // Converts -0.0 to +0.0. | 66 return JS('int', r'# + 0', truncateToDouble()); // Converts -0.0 to +0.0. |
67 } | 67 } |
68 // This is either NaN, Infinity or -Infinity. | 68 // This is either NaN, Infinity or -Infinity. |
69 throw new UnsupportedError(JS("String", "''+#", this)); | 69 throw new UnsupportedError(JS("String", '"" + #', this)); |
70 } | 70 } |
71 | 71 |
72 int truncate() => toInt(); | 72 int truncate() => toInt(); |
| 73 |
73 int ceil() => ceilToDouble().toInt(); | 74 int ceil() => ceilToDouble().toInt(); |
| 75 |
74 int floor() => floorToDouble().toInt(); | 76 int floor() => floorToDouble().toInt(); |
75 int round() => roundToDouble().toInt(); | 77 |
| 78 int round() { |
| 79 if (this > 0) { |
| 80 // This path excludes the special cases -0.0, NaN and -Infinity, leaving |
| 81 // only +Infinity, for which a direct test is faster than [isFinite]. |
| 82 if (JS('bool', r'# !== (1/0)', this)) { |
| 83 return JS('int', r'Math.round(#)', this); |
| 84 } |
| 85 } else if (JS('bool', '# > (-1/0)', this)) { |
| 86 // This test excludes NaN and -Infinity, leaving only -0.0. |
| 87 // |
| 88 // Subtraction from zero rather than negation forces -0.0 to 0.0 so code |
| 89 // inside Math.round and code to handle result never sees -0.0, which on |
| 90 // some JavaScript VMs can be a slow path. |
| 91 return JS('int', r'0 - Math.round(0 - #)', this); |
| 92 } |
| 93 // This is either NaN, Infinity or -Infinity. |
| 94 throw new UnsupportedError(JS("String", '"" + #', this)); |
| 95 } |
76 | 96 |
77 double ceilToDouble() => JS('num', r'Math.ceil(#)', this); | 97 double ceilToDouble() => JS('num', r'Math.ceil(#)', this); |
78 | 98 |
79 double floorToDouble() => JS('num', r'Math.floor(#)', this); | 99 double floorToDouble() => JS('num', r'Math.floor(#)', this); |
80 | 100 |
81 double roundToDouble() { | 101 double roundToDouble() { |
82 if (this < 0) { | 102 if (this < 0) { |
83 return JS('num', r'-Math.round(-#)', this); | 103 return JS('num', r'-Math.round(-#)', this); |
84 } else { | 104 } else { |
85 return JS('num', r'Math.round(#)', this); | 105 return JS('num', r'Math.round(#)', this); |
86 } | 106 } |
87 } | 107 } |
88 | 108 |
89 double truncateToDouble() => this < 0 ? ceilToDouble() : floorToDouble(); | 109 double truncateToDouble() => this < 0 ? ceilToDouble() : floorToDouble(); |
90 | 110 |
91 num clamp(num lowerLimit, num upperLimit) { | 111 num clamp(num lowerLimit, num upperLimit) { |
92 if (lowerLimit.compareTo(upperLimit) > 0) { | 112 if (lowerLimit.compareTo(upperLimit) > 0) { |
93 throw new ArgumentError(lowerLimit); | 113 throw argumentErrorValue(lowerLimit); |
94 } | 114 } |
95 if (this.compareTo(lowerLimit) < 0) return lowerLimit; | 115 if (this.compareTo(lowerLimit) < 0) return lowerLimit; |
96 if (this.compareTo(upperLimit) > 0) return upperLimit; | 116 if (this.compareTo(upperLimit) > 0) return upperLimit; |
97 return this; | 117 return this; |
98 } | 118 } |
99 | 119 |
100 double toDouble() => this; | 120 double toDouble() => this; |
101 | 121 |
102 String toStringAsFixed(int fractionDigits) { | 122 String toStringAsFixed(int fractionDigits) { |
103 checkInt(fractionDigits); | 123 checkInt(fractionDigits); |
104 if (fractionDigits < 0 || fractionDigits > 20) { | 124 if (fractionDigits < 0 || fractionDigits > 20) { |
105 throw new RangeError(fractionDigits); | 125 throw new RangeError.range(fractionDigits, 0, 20, "fractionDigits"); |
106 } | 126 } |
107 String result = JS('String', r'#.toFixed(#)', this, fractionDigits); | 127 String result = JS('String', r'#.toFixed(#)', this, fractionDigits); |
108 if (this == 0 && isNegative) return "-$result"; | 128 if (this == 0 && isNegative) return "-$result"; |
109 return result; | 129 return result; |
110 } | 130 } |
111 | 131 |
112 String toStringAsExponential([int fractionDigits]) { | 132 String toStringAsExponential([int fractionDigits]) { |
113 String result; | 133 String result; |
114 if (fractionDigits != null) { | 134 if (fractionDigits != null) { |
115 checkInt(fractionDigits); | 135 checkInt(fractionDigits); |
116 if (fractionDigits < 0 || fractionDigits > 20) { | 136 if (fractionDigits < 0 || fractionDigits > 20) { |
117 throw new RangeError(fractionDigits); | 137 throw new RangeError.range(fractionDigits, 0, 20, "fractionDigits"); |
118 } | 138 } |
119 result = JS('String', r'#.toExponential(#)', this, fractionDigits); | 139 result = JS('String', r'#.toExponential(#)', this, fractionDigits); |
120 } else { | 140 } else { |
121 result = JS('String', r'#.toExponential()', this); | 141 result = JS('String', r'#.toExponential()', this); |
122 } | 142 } |
123 if (this == 0 && isNegative) return "-$result"; | 143 if (this == 0 && isNegative) return "-$result"; |
124 return result; | 144 return result; |
125 } | 145 } |
126 | 146 |
127 String toStringAsPrecision(int precision) { | 147 String toStringAsPrecision(int precision) { |
128 checkInt(precision); | 148 checkInt(precision); |
129 if (precision < 1 || precision > 21) { | 149 if (precision < 1 || precision > 21) { |
130 throw new RangeError(precision); | 150 throw new RangeError.range(precision, 1, 21, "precision"); |
131 } | 151 } |
132 String result = JS('String', r'#.toPrecision(#)', | 152 String result = JS('String', r'#.toPrecision(#)', |
133 this, precision); | 153 this, precision); |
134 if (this == 0 && isNegative) return "-$result"; | 154 if (this == 0 && isNegative) return "-$result"; |
135 return result; | 155 return result; |
136 } | 156 } |
137 | 157 |
138 String toRadixString(int radix) { | 158 String toRadixString(int radix) { |
139 checkInt(radix); | 159 checkInt(radix); |
140 if (radix < 2 || radix > 36) throw new RangeError(radix); | 160 if (radix < 2 || radix > 36) { |
| 161 throw new RangeError.range(radix, 2, 36, "radix"); |
| 162 } |
141 String result = JS('String', r'#.toString(#)', this, radix); | 163 String result = JS('String', r'#.toString(#)', this, radix); |
142 const int rightParenCode = 0x29; | 164 const int rightParenCode = 0x29; |
143 if (result.codeUnitAt(result.length - 1) != rightParenCode) { | 165 if (result.codeUnitAt(result.length - 1) != rightParenCode) { |
144 return result; | 166 return result; |
145 } | 167 } |
146 return _handleIEtoString(result); | 168 return _handleIEtoString(result); |
147 } | 169 } |
148 | 170 |
149 static String _handleIEtoString(String result) { | 171 static String _handleIEtoString(String result) { |
150 // Result is probably IE's untraditional format for large numbers, | 172 // Result is probably IE's untraditional format for large numbers, |
(...skipping 21 matching lines...) Expand all Loading... |
172 } else { | 194 } else { |
173 return JS('String', r'"" + (#)', this); | 195 return JS('String', r'"" + (#)', this); |
174 } | 196 } |
175 } | 197 } |
176 | 198 |
177 int get hashCode => JS('int', '# & 0x1FFFFFFF', this); | 199 int get hashCode => JS('int', '# & 0x1FFFFFFF', this); |
178 | 200 |
179 JSNumber operator -() => JS('num', r'-#', this); | 201 JSNumber operator -() => JS('num', r'-#', this); |
180 | 202 |
181 JSNumber operator +(num other) { | 203 JSNumber operator +(num other) { |
182 checkNull(other); | 204 if (other is !num) throw argumentErrorValue(other); |
183 return JS('num', '# + #', this, other); | 205 return JS('num', '# + #', this, other); |
184 } | 206 } |
185 | 207 |
186 JSNumber operator -(num other) { | 208 JSNumber operator -(num other) { |
187 checkNull(other); | 209 if (other is !num) throw argumentErrorValue(other); |
188 return JS('num', '# - #', this, other); | 210 return JS('num', '# - #', this, other); |
189 } | 211 } |
190 | 212 |
191 double operator /(num other) { | 213 double operator /(num other) { |
192 checkNull(other); | 214 if (other is !num) throw argumentErrorValue(other); |
193 return JS('double', '# / #', this, other); | 215 return JS('num', '# / #', this, other); |
194 } | 216 } |
195 | 217 |
196 JSNumber operator *(num other) { | 218 JSNumber operator *(num other) { |
197 checkNull(other); | 219 if (other is !num) throw argumentErrorValue(other); |
198 return JS('num', '# * #', this, other); | 220 return JS('num', '# * #', this, other); |
199 } | 221 } |
200 | 222 |
201 JSNumber operator %(num other) { | 223 JSNumber operator %(num other) { |
202 checkNull(other); | 224 if (other is !num) throw argumentErrorValue(other); |
203 // Euclidean Modulo. | 225 // Euclidean Modulo. |
204 num result = JS('num', r'# % #', this, other); | 226 num result = JS('num', r'# % #', this, other); |
205 if (result == 0) return (0 as JSNumber); // Make sure we don't return -0.0. | 227 if (result == 0) return (0 as JSNumber); // Make sure we don't return -0.0. |
206 if (result > 0) return result; | 228 if (result > 0) return result; |
207 if (JS('num', '#', other) < 0) { | 229 if (JS('num', '#', other) < 0) { |
208 return result - JS('num', '#', other); | 230 return result - JS('num', '#', other); |
209 } else { | 231 } else { |
210 return result + JS('num', '#', other); | 232 return result + JS('num', '#', other); |
211 } | 233 } |
212 } | 234 } |
213 | 235 |
214 bool _isInt32(value) => JS('bool', '(# | 0) === #', value, value); | 236 bool _isInt32(value) => JS('bool', '(# | 0) === #', value, value); |
215 | 237 |
216 int operator ~/(num other) { | 238 int operator ~/(num other) { |
217 if (_isInt32(this) && _isInt32(other) && 0 != other && -1 != other) { | 239 if (_isInt32(this) && _isInt32(other) && 0 != other && -1 != other) { |
218 return JS('int', r'(# / #) | 0', this, other); | 240 return JS('int', r'(# / #) | 0', this, other); |
219 } else { | 241 } else { |
220 return _tdivSlow(other); | 242 return _tdivSlow(other); |
221 } | 243 } |
222 } | 244 } |
223 | 245 |
224 int _tdivSlow(num other) { | 246 int _tdivSlow(num other) { |
225 checkNull(other); | 247 if (other is !num) throw argumentErrorValue(other); |
226 return (JS('num', r'# / #', this, other)).toInt(); | 248 return (JS('num', r'# / #', this, other)).toInt(); |
227 } | 249 } |
228 | 250 |
229 // TODO(ngeoffray): Move the bit operations below to [JSInt] and | 251 // TODO(ngeoffray): Move the bit operations below to [JSInt] and |
230 // make them take an int. Because this will make operations slower, | 252 // make them take an int. Because this will make operations slower, |
231 // we define these methods on number for now but we need to decide | 253 // we define these methods on number for now but we need to decide |
232 // the grain at which we do the type checks. | 254 // the grain at which we do the type checks. |
233 | 255 |
234 int operator <<(num other) { | 256 int operator <<(num other) { |
235 if (other < 0) throw new ArgumentError(other); | 257 if (other is !num) throw argumentErrorValue(other); |
| 258 if (JS('num', '#', other) < 0) throw argumentErrorValue(other); |
236 return _shlPositive(other); | 259 return _shlPositive(other); |
237 } | 260 } |
238 | 261 |
239 int _shlPositive(num other) { | 262 int _shlPositive(num other) { |
240 // JavaScript only looks at the last 5 bits of the shift-amount. Shifting | 263 // JavaScript only looks at the last 5 bits of the shift-amount. Shifting |
241 // by 33 is hence equivalent to a shift by 1. | 264 // by 33 is hence equivalent to a shift by 1. |
242 return JS('bool', r'# > 31', other) | 265 return JS('bool', r'# > 31', other) |
243 ? 0 | 266 ? 0 |
244 : JS('int', r'(# << #) >>> 0', this, other); | 267 : JS('int', r'(# << #) >>> 0', this, other); |
245 } | 268 } |
246 | 269 |
247 int operator >>(num other) { | 270 int operator >>(num other) { |
248 if (other < 0) throw new ArgumentError(other); | 271 if (other is !num) throw argumentErrorValue(other); |
| 272 if (JS('num', '#', other) < 0) throw argumentErrorValue(other); |
249 return _shrOtherPositive(other); | 273 return _shrOtherPositive(other); |
250 } | 274 } |
251 | 275 |
252 int _shrOtherPositive(num other) { | 276 int _shrOtherPositive(num other) { |
253 return JS('num', '#', this) > 0 | 277 return JS('num', '#', this) > 0 |
254 ? _shrBothPositive(other) | 278 ? _shrBothPositive(other) |
255 // For negative numbers we just clamp the shift-by amount. | 279 // For negative numbers we just clamp the shift-by amount. |
256 // `this` could be negative but not have its 31st bit set. | 280 // `this` could be negative but not have its 31st bit set. |
257 // The ">>" would then shift in 0s instead of 1s. Therefore | 281 // The ">>" would then shift in 0s instead of 1s. Therefore |
258 // we cannot simply return 0xFFFFFFFF. | 282 // we cannot simply return 0xFFFFFFFF. |
259 : JS('int', r'(# >> #) >>> 0', this, other > 31 ? 31 : other); | 283 : JS('int', r'(# >> #) >>> 0', this, other > 31 ? 31 : other); |
260 } | 284 } |
261 | 285 |
262 int _shrBothPositive(num other) { | 286 int _shrBothPositive(num other) { |
263 return JS('bool', r'# > 31', other) | 287 return JS('bool', r'# > 31', other) |
264 // JavaScript only looks at the last 5 bits of the shift-amount. In JS | 288 // JavaScript only looks at the last 5 bits of the shift-amount. In JS |
265 // shifting by 33 is hence equivalent to a shift by 1. Shortcut the | 289 // shifting by 33 is hence equivalent to a shift by 1. Shortcut the |
266 // computation when that happens. | 290 // computation when that happens. |
267 ? 0 | 291 ? 0 |
268 // Given that `this` is positive we must not use '>>'. Otherwise a | 292 // Given that `this` is positive we must not use '>>'. Otherwise a |
269 // number that has the 31st bit set would be treated as negative and | 293 // number that has the 31st bit set would be treated as negative and |
270 // shift in ones. | 294 // shift in ones. |
271 : JS('int', r'# >>> #', this, other); | 295 : JS('int', r'# >>> #', this, other); |
272 } | 296 } |
273 | 297 |
274 int operator &(num other) { | 298 int operator &(num other) { |
275 checkNull(other); | 299 if (other is !num) throw argumentErrorValue(other); |
276 return JS('int', r'(# & #) >>> 0', this, other); | 300 return JS('int', r'(# & #) >>> 0', this, other); |
277 } | 301 } |
278 | 302 |
279 int operator |(num other) { | 303 int operator |(num other) { |
280 checkNull(other); | 304 if (other is !num) throw argumentErrorValue(other); |
281 return JS('int', r'(# | #) >>> 0', this, other); | 305 return JS('int', r'(# | #) >>> 0', this, other); |
282 } | 306 } |
283 | 307 |
284 int operator ^(num other) { | 308 int operator ^(num other) { |
285 checkNull(other); | 309 if (other is !num) throw argumentErrorValue(other); |
286 return JS('int', r'(# ^ #) >>> 0', this, other); | 310 return JS('int', r'(# ^ #) >>> 0', this, other); |
287 } | 311 } |
288 | 312 |
289 bool operator <(num other) { | 313 bool operator <(num other) { |
290 checkNull(other); | 314 if (other is !num) throw argumentErrorValue(other); |
291 return JS('bool', '# < #', this, other); | 315 return JS('bool', '# < #', this, other); |
292 } | 316 } |
293 | 317 |
294 bool operator >(num other) { | 318 bool operator >(num other) { |
295 checkNull(other); | 319 if (other is !num) throw argumentErrorValue(other); |
296 return JS('bool', '# > #', this, other); | 320 return JS('bool', '# > #', this, other); |
297 } | 321 } |
298 | 322 |
299 bool operator <=(num other) { | 323 bool operator <=(num other) { |
300 checkNull(other); | 324 if (other is !num) throw argumentErrorValue(other); |
301 return JS('bool', '# <= #', this, other); | 325 return JS('bool', '# <= #', this, other); |
302 } | 326 } |
303 | 327 |
304 bool operator >=(num other) { | 328 bool operator >=(num other) { |
305 checkNull(other); | 329 if (other is !num) throw argumentErrorValue(other); |
306 return JS('bool', '# >= #', this, other); | 330 return JS('bool', '# >= #', this, other); |
307 } | 331 } |
308 | 332 |
309 // int members. | 333 // int members. |
310 // TODO(jmesserly): all numbers will have these in dynamic dispatch. | 334 // TODO(jmesserly): all numbers will have these in dynamic dispatch. |
311 // We can fix by checking it at dispatch time but we'd need to structure them | 335 // We can fix by checking it at dispatch time but we'd need to structure them |
312 // differently. | 336 // differently. |
313 | 337 |
314 bool get isEven => (this & 1) == 0; | 338 bool get isEven => (this & 1) == 0; |
315 | 339 |
(...skipping 10 matching lines...) Expand all Loading... |
326 | 350 |
327 int get bitLength { | 351 int get bitLength { |
328 int nonneg = this < 0 ? -this - 1 : this; | 352 int nonneg = this < 0 ? -this - 1 : this; |
329 if (nonneg >= 0x100000000) { | 353 if (nonneg >= 0x100000000) { |
330 nonneg = nonneg ~/ 0x100000000; | 354 nonneg = nonneg ~/ 0x100000000; |
331 return _bitCount(_spread(nonneg)) + 32; | 355 return _bitCount(_spread(nonneg)) + 32; |
332 } | 356 } |
333 return _bitCount(_spread(nonneg)); | 357 return _bitCount(_spread(nonneg)); |
334 } | 358 } |
335 | 359 |
| 360 // Returns pow(this, e) % m. |
| 361 int modPow(int e, int m) { |
| 362 if (e is! int) { |
| 363 throw new ArgumentError.value(e, "exponent", "not an integer"); |
| 364 } |
| 365 if (m is! int) { |
| 366 throw new ArgumentError.value(m, "modulus", "not an integer"); |
| 367 } |
| 368 if (e < 0) throw new RangeError.range(e, 0, null, "exponent"); |
| 369 if (m <= 0) throw new RangeError.range(m, 1, null, "modulus"); |
| 370 if (e == 0) return 1; |
| 371 int b = this; |
| 372 if (b < 0 || b > m) { |
| 373 b %= m; |
| 374 } |
| 375 int r = 1; |
| 376 while (e > 0) { |
| 377 if (e.isOdd) { |
| 378 r = (r * b) % m; |
| 379 } |
| 380 e ~/= 2; |
| 381 b = (b * b) % m; |
| 382 } |
| 383 return r; |
| 384 } |
| 385 |
| 386 // If inv is false, returns gcd(x, y). |
| 387 // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1. |
| 388 // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime"). |
| 389 static int _binaryGcd(int x, int y, bool inv) { |
| 390 int s = 1; |
| 391 if (!inv) { |
| 392 while (x.isEven && y.isEven) { |
| 393 x ~/= 2; |
| 394 y ~/= 2; |
| 395 s *= 2; |
| 396 } |
| 397 if (y.isOdd) { |
| 398 var t = x; |
| 399 x = y; |
| 400 y = t; |
| 401 } |
| 402 } |
| 403 final bool ac = x.isEven; |
| 404 int u = x; |
| 405 int v = y; |
| 406 int a = 1, |
| 407 b = 0, |
| 408 c = 0, |
| 409 d = 1; |
| 410 do { |
| 411 while (u.isEven) { |
| 412 u ~/= 2; |
| 413 if (ac) { |
| 414 if (!a.isEven || !b.isEven) { |
| 415 a += y; |
| 416 b -= x; |
| 417 } |
| 418 a ~/= 2; |
| 419 } else if (!b.isEven) { |
| 420 b -= x; |
| 421 } |
| 422 b ~/= 2; |
| 423 } |
| 424 while (v.isEven) { |
| 425 v ~/= 2; |
| 426 if (ac) { |
| 427 if (!c.isEven || !d.isEven) { |
| 428 c += y; |
| 429 d -= x; |
| 430 } |
| 431 c ~/= 2; |
| 432 } else if (!d.isEven) { |
| 433 d -= x; |
| 434 } |
| 435 d ~/= 2; |
| 436 } |
| 437 if (u >= v) { |
| 438 u -= v; |
| 439 if (ac) a -= c; |
| 440 b -= d; |
| 441 } else { |
| 442 v -= u; |
| 443 if (ac) c -= a; |
| 444 d -= b; |
| 445 } |
| 446 } while (u != 0); |
| 447 if (!inv) return s*v; |
| 448 if (v != 1) throw new Exception("Not coprime"); |
| 449 if (d < 0) { |
| 450 d += x; |
| 451 if (d < 0) d += x; |
| 452 } else if (d > x) { |
| 453 d -= x; |
| 454 if (d > x) d -= x; |
| 455 } |
| 456 return d; |
| 457 } |
| 458 |
| 459 // Returns 1/this % m, with m > 0. |
| 460 int modInverse(int m) { |
| 461 if (m is! int) { |
| 462 throw new ArgumentError.value(m, "modulus", "not an integer"); |
| 463 } |
| 464 if (m <= 0) throw new RangeError.range(m, 1, null, "modulus"); |
| 465 if (m == 1) return 0; |
| 466 int t = this; |
| 467 if ((t < 0) || (t >= m)) t %= m; |
| 468 if (t == 1) return 1; |
| 469 if ((t == 0) || (t.isEven && m.isEven)) { |
| 470 throw new Exception("Not coprime"); |
| 471 } |
| 472 return _binaryGcd(m, t, true); |
| 473 } |
| 474 |
| 475 // Returns gcd of abs(this) and abs(other). |
| 476 int gcd(int other) { |
| 477 if (other is! int) { |
| 478 throw new ArgumentError.value(other, "other", "not an integer"); |
| 479 } |
| 480 int x = this.abs(); |
| 481 int y = other.abs(); |
| 482 if (x == 0) return y; |
| 483 if (y == 0) return x; |
| 484 if ((x == 1) || (y == 1)) return 1; |
| 485 return _binaryGcd(x, y, false); |
| 486 } |
| 487 |
336 // Assumes i is <= 32-bit and unsigned. | 488 // Assumes i is <= 32-bit and unsigned. |
337 static int _bitCount(int i) { | 489 static int _bitCount(int i) { |
338 // See "Hacker's Delight", section 5-1, "Counting 1-Bits". | 490 // See "Hacker's Delight", section 5-1, "Counting 1-Bits". |
339 | 491 |
340 // The basic strategy is to use "divide and conquer" to | 492 // The basic strategy is to use "divide and conquer" to |
341 // add pairs (then quads, etc.) of bits together to obtain | 493 // add pairs (then quads, etc.) of bits together to obtain |
342 // sub-counts. | 494 // sub-counts. |
343 // | 495 // |
344 // A straightforward approach would look like: | 496 // A straightforward approach would look like: |
345 // | 497 // |
(...skipping 23 matching lines...) Expand all Loading... |
369 i = _ors(i, _shrs(i, 1)); | 521 i = _ors(i, _shrs(i, 1)); |
370 i = _ors(i, _shrs(i, 2)); | 522 i = _ors(i, _shrs(i, 2)); |
371 i = _ors(i, _shrs(i, 4)); | 523 i = _ors(i, _shrs(i, 4)); |
372 i = _ors(i, _shrs(i, 8)); | 524 i = _ors(i, _shrs(i, 8)); |
373 i = _shru(_ors(i, _shrs(i, 16)), 0); | 525 i = _shru(_ors(i, _shrs(i, 16)), 0); |
374 return i; | 526 return i; |
375 } | 527 } |
376 | 528 |
377 int operator ~() => JS('int', r'(~#) >>> 0', this); | 529 int operator ~() => JS('int', r'(~#) >>> 0', this); |
378 } | 530 } |
OLD | NEW |