Changeset 192855 in webkit


Ignore:
Timestamp:
Nov 30, 2015 7:39:59 PM (8 years ago)
Author:
ggaren@apple.com
Message:

Use a better RNG for Math.random()
https://bugs.webkit.org/show_bug.cgi?id=151641

Reviewed by Anders Carlsson.

Source/JavaScriptCore:

Updated for interface change.

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::setInputCursor):

Source/WTF:

Use 64 bits in the random number generator instead of 32 bit. (In
the end, JavaScript, which uses doubles, will only see 52 bits.) This
prevents programs that mulitply a random number by a large constant from
seeing non-random "banding" caused by zeroes in the low 20 bits.

I also took the opportunity to upgrade from GameRandom to Xorshift+,
since Xorshift+ passes more benchmarks for randomness, and is not any
slower or more complicated.

Now let us all remember the fateful words of Steve Weibe, who would be
King of Kong: "The randomness went the opposite way that it usually goes."

  • wtf/WeakRandom.h:

(WTF::WeakRandom::WeakRandom):
(WTF::WeakRandom::setSeed): Use standard naming.

(WTF::WeakRandom::seed): This function is safe now. "Unsafe" in function
names makes me itch.

(WTF::WeakRandom::get):
(WTF::WeakRandom::getUint32): Update to 64bit.

(WTF::WeakRandom::advance): The Xorshift+ algorithm.

(WTF::WeakRandom::initializeSeed): Deleted.
(WTF::WeakRandom::seedUnsafe): Deleted.

Location:
trunk/Source
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r192851 r192855  
     12015-11-30  Geoffrey Garen  <ggaren@apple.com>
     2
     3        Use a better RNG for Math.random()
     4        https://bugs.webkit.org/show_bug.cgi?id=151641
     5
     6        Reviewed by Anders Carlsson.
     7
     8        Updated for interface change.
     9
     10        * runtime/JSGlobalObject.cpp:
     11        (JSC::JSGlobalObject::setInputCursor):
     12
    1132015-11-30  Benjamin Poulain  <bpoulain@apple.com>
    214
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r192751 r192855  
    10151015    // to avoid threading the input cursor through all the abstraction layers.
    10161016    if (cursor.isCapturing())
    1017         cursor.appendInput<SetRandomSeed>(m_weakRandom.seedUnsafe());
     1017        cursor.appendInput<SetRandomSeed>(m_weakRandom.seed());
    10181018    else if (cursor.isReplaying()) {
    10191019        if (SetRandomSeed* input = cursor.fetchInput<SetRandomSeed>())
    1020             m_weakRandom.initializeSeed(static_cast<unsigned>(input->randomSeed()));
     1020            m_weakRandom.setSeed(static_cast<unsigned>(input->randomSeed()));
    10211021    }
    10221022}
  • trunk/Source/WTF/ChangeLog

    r192851 r192855  
     12015-11-30  Geoffrey Garen  <ggaren@apple.com>
     2
     3        Use a better RNG for Math.random()
     4        https://bugs.webkit.org/show_bug.cgi?id=151641
     5
     6        Reviewed by Anders Carlsson.
     7
     8        Use 64 bits in the random number generator instead of 32 bit. (In
     9        the end, JavaScript, which uses doubles, will only see 52 bits.) This
     10        prevents programs that mulitply a random number by a large constant from
     11        seeing non-random "banding" caused by zeroes in the low 20 bits.
     12
     13        I also took the opportunity to upgrade from GameRandom to Xorshift+,
     14        since Xorshift+ passes more benchmarks for randomness, and is not any
     15        slower or more complicated.
     16
     17        Now let us all remember the fateful words of Steve Weibe, who would be
     18        King of Kong: "The randomness went the opposite way that it usually goes."
     19
     20        * wtf/WeakRandom.h:
     21        (WTF::WeakRandom::WeakRandom):
     22        (WTF::WeakRandom::setSeed): Use standard naming.
     23
     24        (WTF::WeakRandom::seed): This function is safe now. "Unsafe" in function
     25        names makes me itch.
     26
     27        (WTF::WeakRandom::get):
     28        (WTF::WeakRandom::getUint32): Update to 64bit.
     29
     30        (WTF::WeakRandom::advance): The Xorshift+ algorithm.
     31
     32        (WTF::WeakRandom::initializeSeed): Deleted.
     33        (WTF::WeakRandom::seedUnsafe): Deleted.
     34
    1352015-11-30  Benjamin Poulain  <bpoulain@apple.com>
    236
  • trunk/Source/WTF/wtf/WeakRandom.h

    r190267 r192855  
    2323 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2424 *
     25 * Vigna, Sebastiano (2014). "Further scramblings of Marsaglia's xorshift
     26 * generators". arXiv:1404.0390 (http://arxiv.org/abs/1404.0390)
    2527 *
    26  * Copyright (c) 2009 Ian C. Bullard
    27  *
    28  * Permission is hereby granted, free of charge, to any person
    29  * obtaining a copy of this software and associated documentation
    30  * files (the "Software"), to deal in the Software without
    31  * restriction, including without limitation the rights to use,
    32  * copy, modify, merge, publish, distribute, sublicense, and/or sell
    33  * copies of the Software, and to permit persons to whom the
    34  * Software is furnished to do so, subject to the following
    35  * conditions:
    36  *
    37  * The above copyright notice and this permission notice shall be
    38  * included in all copies or substantial portions of the Software.
    39  *
    40  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    41  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    42  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    43  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    44  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    45  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    46  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    47  * OTHER DEALINGS IN THE SOFTWARE.
     28 * See also https://en.wikipedia.org/wiki/Xorshift.
    4829 */
    4930
     
    5233
    5334#include <limits.h>
    54 #include <wtf/RandomNumber.h>
     35#include <wtf/CryptographicallyRandomNumber.h>
    5536#include <wtf/StdLibExtras.h>
    5637
     
    5940class WeakRandom {
    6041public:
    61     WeakRandom()
     42    WeakRandom(unsigned seed = cryptographicallyRandomNumber())
    6243    {
    63         initializeSeed(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0));
     44        setSeed(seed);
    6445    }
    65    
    66     WeakRandom(unsigned seed)
     46
     47    void setSeed(unsigned seed)
    6748    {
    68         initializeSeed(seed);
    69     }
    70    
    71     void initializeSeed(unsigned seed)
    72     {
    73         m_low = seed ^ 0x49616E42;
     49        m_seed = seed;
     50
     51        // A zero seed would cause an infinite series of zeroes.
     52        if (!seed)
     53            seed = 1;
     54
     55        m_low = seed;
    7456        m_high = seed;
    7557    }
    7658
    77     // Returns the seed provided that you've never called get() or getUint32().
    78     unsigned seedUnsafe() const { return m_high; }
     59    unsigned seed() const { return m_seed; }
    7960
    8061    double get()
    8162    {
    82         return advance() / (UINT_MAX + 1.0);
     63        return advance() / (std::numeric_limits<uint64_t>::max() + 1.0);
    8364    }
    8465
    8566    unsigned getUint32()
    8667    {
    87         return advance();
     68        return static_cast<unsigned>(advance());
    8869    }
    8970
     
    9273        if (limit <= 1)
    9374            return 0;
    94         uint64_t cutoff = (static_cast<uint64_t>(UINT_MAX) + 1) / limit * limit;
     75        uint64_t cutoff = (static_cast<uint64_t>(std::numeric_limits<unsigned>::max()) + 1) / limit * limit;
    9576        for (;;) {
    9677            uint64_t value = getUint32();
     
    10283
    10384private:
    104     unsigned advance()
     85    uint64_t advance()
    10586    {
    106         m_high = (m_high << 16) + (m_high >> 16);
    107         m_high += m_low;
    108         m_low += m_high;
    109         return m_high;
     87        uint64_t x = m_low;
     88        uint64_t y = m_high;
     89        m_low = y;
     90        x ^= x << 23;
     91        x ^= x >> 17;
     92        x ^= y ^ (y >> 26);
     93        m_high = x;
     94        return x + y;
    11095    }
    11196
    112     unsigned m_low;
    113     unsigned m_high;
     97    unsigned m_seed;
     98    uint64_t m_low;
     99    uint64_t m_high;
    114100};
    115101
Note: See TracChangeset for help on using the changeset viewer.