| 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 |