| 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 import "dart:typed_data"; | 5 import "dart:typed_data"; |
| 6 | 6 |
| 7 // A VM patch of the dart:math library. | 7 // A VM patch of the dart:math library. |
| 8 | 8 |
| 9 // If [x] is an [int] and [exponent] is a non-negative [int], the result is | 9 // If [x] is an [int] and [exponent] is a non-negative [int], the result is |
| 10 // an [int], otherwise the result is a [double]. | 10 // an [int], otherwise the result is a [double]. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 double _log(double x) native "Math_log"; | 39 double _log(double x) native "Math_log"; |
| 40 | 40 |
| 41 | 41 |
| 42 // TODO(iposva): Handle patch methods within a patch class correctly. | 42 // TODO(iposva): Handle patch methods within a patch class correctly. |
| 43 patch class Random { | 43 patch class Random { |
| 44 | 44 |
| 45 /*patch*/ factory Random([int seed]) { | 45 /*patch*/ factory Random([int seed]) { |
| 46 if (seed == null) { | 46 if (seed == null) { |
| 47 seed = _Random._nextSeed(); | 47 seed = _Random._nextSeed(); |
| 48 } | 48 } |
| 49 do { | |
| 50 seed = (seed + 0x5A17) & _Random._MASK_64; | |
| 51 } while (seed == 0); | |
| 52 // Crank a couple of times to distribute the seed bits a bit further. | 49 // Crank a couple of times to distribute the seed bits a bit further. |
| 53 return new _Random._internal(seed).._nextState() | 50 return new _Random().._setupSeed(seed) |
| 54 .._nextState() | 51 .._nextState() |
| 55 .._nextState() | 52 .._nextState() |
| 56 .._nextState(); | 53 .._nextState() |
| 54 .._nextState(); |
| 57 } | 55 } |
| 58 } | 56 } |
| 59 | 57 |
| 60 | 58 |
| 61 class _Random implements Random { | 59 class _Random implements Random { |
| 62 // Internal state of the random number generator. | 60 // Internal state of the random number generator. |
| 63 final _state = new Uint32List(2); | 61 final _state = new Uint32List(2); |
| 64 static const kSTATE_LO = 0; | 62 static const kSTATE_LO = 0; |
| 65 static const kSTATE_HI = 1; | 63 static const kSTATE_HI = 1; |
| 66 | 64 |
| 67 _Random._internal(state) { | 65 // Implements: |
| 68 _state[kSTATE_LO] = state & _MASK_32; | 66 // do { |
| 69 _state[kSTATE_HI] = state >> 32; | 67 // seed = (seed + 0x5A17) & _Random._MASK_64; |
| 70 } | 68 // } while (seed == 0); |
| 69 // _state[kSTATE_LO] = seed & _MASK_32; |
| 70 // _state[kSTATE_HI] = seed >> 32; |
| 71 // This is a native to prevent 64-bit operations in Dart, which |
| 72 // fail with --throw_on_javascript_int_overflow. |
| 73 void _setupSeed(int seed) native "Random_setupSeed"; |
| 71 | 74 |
| 72 // The algorithm used here is Multiply with Carry (MWC) with a Base b = 2^32. | 75 // The algorithm used here is Multiply with Carry (MWC) with a Base b = 2^32. |
| 73 // http://en.wikipedia.org/wiki/Multiply-with-carry | 76 // http://en.wikipedia.org/wiki/Multiply-with-carry |
| 74 // The constant A is selected from "Numerical Recipes 3rd Edition" p.348 B1. | 77 // The constant A is selected from "Numerical Recipes 3rd Edition" p.348 B1. |
| 75 void _nextState() { | 78 |
| 76 var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; | 79 // Implements: |
| 77 _state[kSTATE_LO] = state & _MASK_32; | 80 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; |
| 78 _state[kSTATE_HI] = state >> 32; | 81 // _state[kSTATE_LO] = state & _MASK_32; |
| 79 } | 82 // _state[kSTATE_HI] = state >> 32; |
| 83 // This is a native to prevent 64-bit operations in Dart, which |
| 84 // fail with --throw_on_javascript_int_overflow. |
| 85 void _nextState() native "Random_nextState"; |
| 80 | 86 |
| 81 int nextInt(int max) { | 87 int nextInt(int max) { |
| 82 // TODO(srdjan): Remove the 'limit' check once optimizing comparison of | 88 // TODO(srdjan): Remove the 'limit' check once optimizing comparison of |
| 83 // Smi-s with Mint constants. | 89 // Smi-s with Mint constants. |
| 84 final limit = 0x3FFFFFFF; | 90 final limit = 0x3FFFFFFF; |
| 85 if (max <= 0 || ((max > limit) && (max > _POW2_32))) { | 91 if (max <= 0 || ((max > limit) && (max > _POW2_32))) { |
| 86 throw new ArgumentError("max must be positive and < 2^32:" | 92 throw new ArgumentError("max must be positive and < 2^32:" |
| 87 " $max"); | 93 " $max"); |
| 88 } | 94 } |
| 89 if ((max & -max) == max) { | 95 if ((max & -max) == max) { |
| 90 // Fast case for powers of two. | 96 // Fast case for powers of two. |
| 91 _nextState(); | 97 _nextState(); |
| 92 return _state[kSTATE_LO] & (max - 1); | 98 return _state[kSTATE_LO] & (max - 1); |
| 93 } | 99 } |
| 94 | 100 |
| 95 var rnd32; | 101 var rnd32; |
| 96 var result; | 102 var result; |
| 97 do { | 103 do { |
| 98 _nextState(); | 104 _nextState(); |
| 99 rnd32 = _state[kSTATE_LO]; | 105 rnd32 = _state[kSTATE_LO]; |
| 100 result = rnd32 % max; | 106 result = rnd32 % max; |
| 101 } while ((rnd32 - result + max) >= _POW2_32); | 107 } while ((rnd32 - result + max) >= _POW2_32); |
| 102 return result; | 108 return result; |
| 103 } | 109 } |
| 104 | 110 |
| 105 double nextDouble() { | 111 double nextDouble() { |
| 106 return ((nextInt(1 << 26) << 27) + nextInt(1 << 27)) / _POW2_53_D; | 112 return ((nextInt(1 << 26) * _POW2_27_D) + nextInt(1 << 27)) / _POW2_53_D; |
| 107 } | 113 } |
| 108 | 114 |
| 109 bool nextBool() { | 115 bool nextBool() { |
| 110 return nextInt(2) == 0; | 116 return nextInt(2) == 0; |
| 111 } | 117 } |
| 112 | 118 |
| 113 // Constants used by the algorithm or masking. | 119 // Constants used by the algorithm or masking. |
| 114 static const _MASK_32 = (1 << 32) - 1; | 120 static const _MASK_32 = (1 << 32) - 1; |
| 115 static const _MASK_64 = (1 << 64) - 1; | 121 static const _MASK_64 = (1 << 64) - 1; |
| 116 static const _POW2_32 = 1 << 32; | 122 static const _POW2_32 = 1 << 32; |
| 117 static const _POW2_53_D = 1.0 * (1 << 53); | 123 static const _POW2_53_D = 1.0 * (1 << 53); |
| 124 static const _POW2_27_D = 1.0 * (1 << 27); |
| 118 | 125 |
| 119 static const _A = 0xffffda61; | 126 static const _A = 0xffffda61; |
| 120 | 127 |
| 121 // Use a singleton Random object to get a new seed if no seed was passed. | 128 // Use a singleton Random object to get a new seed if no seed was passed. |
| 122 static var _prng = null; | 129 static var _prng = null; |
| 123 | 130 |
| 124 static int _nextSeed() { | 131 static int _nextSeed() { |
| 125 if (_prng == null) { | 132 if (_prng == null) { |
| 126 // TODO(iposva): Use system to get a random seed. | 133 // TODO(iposva): Use system to get a random seed. |
| 127 _prng = new Random(new DateTime.now().millisecondsSinceEpoch); | 134 _prng = new Random(new DateTime.now().millisecondsSinceEpoch); |
| 128 } | 135 } |
| 129 // Trigger the PRNG once to change the internal state. | 136 // Trigger the PRNG once to change the internal state. |
| 130 _prng._nextState(); | 137 _prng._nextState(); |
| 131 return _prng._state[kSTATE_LO]; | 138 return _prng._state[kSTATE_LO]; |
| 132 } | 139 } |
| 133 } | 140 } |
| OLD | NEW |