Skip to content

Instantly share code, notes, and snippets.

@mmore500
Last active Nov 24, 2019
Embed
What would you like to do?
emp::Random::GetUInt64 profile
// This is the main function for the NATIVE version of this project.
#include <iostream>
#include <chrono>
#include "base/vector.h"
#include "config/command_line.h"
#include "tools/Random.h"
#include "data/DataFile.h"
int main(int argc, char* argv[])
{
emp::Random rand(1);
double sum = 0.0;
emp::DataFile dfile("timings.dat");
std::string type;
double timing;
dfile.AddVar<std::string>(type, "type");
dfile.AddVar<double>(timing, "timing");
dfile.PrintHeaderKeys();
for (size_t rep = 0; rep < 500; ++rep) {
std::cout << "." << std::endl;
{
type = "old";
const auto start = std::chrono::high_resolution_clock::now();
for (size_t i = 0; i < 1e5; ++i) {
sum += rand.GetUInt64Old();
}
const auto stop = std::chrono::high_resolution_clock::now();
timing = std::chrono::duration_cast<std::chrono::microseconds>(
stop - start
).count();
dfile.Update();
}
{
type = "new";
const auto start = std::chrono::high_resolution_clock::now();
for (size_t i = 0; i < 1e5; ++i) {
sum += rand.GetUInt64();
}
const auto stop = std::chrono::high_resolution_clock::now();
timing = std::chrono::duration_cast<std::chrono::microseconds>(
stop - start
).count();
dfile.Update();
}
std::cout << sum << std::endl;
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
df = pd.read_csv("timings.dat")
sns.barplot(data=df, y="timing", x="type")
plt.savefig("out.pdf")
/**
* @note This file is part of Empirical, https://github.com/devosoft/Empirical
* @copyright Copyright (C) Michigan State University, MIT Software license; see doc/LICENSE.md
* @date 2015-2019
*
* @file Random.h
* @brief A versatile and non-patterned pseudo-random-number generator.
* @note Status: RELEASE
*/
#ifndef EMP_RANDOM_H
#define EMP_RANDOM_H
#include <ctime>
#include <climits>
#include <cmath>
#include <cstring>
#include <iterator>
#include "../base/assert.h"
#include "Range.h"
namespace emp {
/// A versatile and non-patterned pseudo-random-number generator (Mersenne Twister).
class Random {
protected:
int seed = 0; ///< Current random number seed.
int original_seed = 0; ///< Orignal random number seed when object was first created.
int inext = 0; ///< First position in use in internal state.
int inextp = 0; ///< Second position in use in internal state.
int ma[56]; ///< Internal state of RNG
// Members & functions for stat functions
double expRV = 0.0; ///< Exponential Random Variable for the randNormal function
// Constants ////////////////////////////////////////////////////////////////
// Statistical Approximation
static const int32_t _BINOMIAL_TO_NORMAL = 50; // if < n*p*(1-p)
static const int32_t _BINOMIAL_TO_POISSON = 1000; // if < n && !Normal approx Engine
// Engine
static const int32_t _RAND_MBIG = 1000000000;
static const int32_t _RAND_MSEED = 161803398;
// Internal functions
// Setup, called on initialization and seed reset.
void init()
{
// Clear variables
for (int i = 0; i < 56; ++i) ma[i] = 0;
int32_t mj = (_RAND_MSEED - seed) % _RAND_MBIG;
ma[55] = mj;
int32_t mk = 1;
for (int32_t i = 1; i < 55; ++i) {
int32_t ii = (21 * i) % 55;
ma[ii] = mk;
mk = mj - mk;
if (mk < 0) mk += _RAND_MBIG;
mj = ma[ii];
}
for (int32_t k = 0; k < 4; ++k) {
for (int32_t j = 1; j < 55; ++j) {
ma[j] -= ma[1 + (j + 30) % 55];
if (ma[j] < 0) ma[j] += _RAND_MBIG;
}
}
inext = 0;
inextp = 31;
// Setup variables used by Statistical Distribution functions
expRV = -log(Random::Get() / (double) _RAND_MBIG);
}
// Basic Random number
// Returns a random number [0,_RAND_MBIG)
int32_t Get() {
if (++inext == 56) inext = 0;
if (++inextp == 56) inextp = 0;
int mj = ma[inext] - ma[inextp];
if (mj < 0) mj += _RAND_MBIG;
ma[inext] = mj;
return mj;
}
public:
/**
* Set up the random generator object.
* @param _seed The seed of the random number generator. A negative seed means that the
* random number generator gets its seed from a combination of the actual system time and
* the memory position of the random number generator.
**/
Random(const int _seed = -1) {
for (int i = 0; i < 56; ++i) ma[i] = 0;
ResetSeed(_seed); // Calls init()
}
~Random() { ; }
/**
* @return The seed that was actually used to start the random sequence.
**/
inline int GetSeed() const { return seed; }
/**
* @return The seed that was originally provided by the user.
**/
inline int GetOriginalSeed() const { return original_seed; }
/**
* Starts a new sequence of pseudo random numbers.
*
* @param new_seed The seed for the new sequence.
* A negative seed means that the random number generator gets its
* seed from the actual system time and the process ID.
**/
inline void ResetSeed(const int _seed) {
original_seed = _seed;
if (_seed <= 0) {
int seed_time = (int) time(NULL);
int seed_mem = (int) ((uint64_t) this);
seed = seed_time ^ seed_mem;
} else {
seed = _seed;
}
if (seed < 0) seed *= -1;
seed %= _RAND_MSEED;
init();
}
// Random Number Generation /////////////////////////////////////////////////
/**
* Generate a double between 0.0 and 1.0
*
* @return The pseudo random number.
**/
inline double GetDouble() { return Get() / (double) _RAND_MBIG; }
/**
* Generate a double between 0 and a given number.
*
* @return The pseudo random number.
* @param max The upper bound for the random numbers (will never be returned).
**/
inline double GetDouble(const double max) {
// emp_assert(max <= (double) _RAND_MBIG, max, (double) _RAND_MBIG); // Precision will be too low past this point...
return GetDouble() * max;
}
/**
* Generate a double out of a given interval.
*
* @return The pseudo random number.
* @param min The lower bound for the random numbers.
* @param max The upper bound for the random numbers (will never be returned).
**/
inline double GetDouble(const double min, const double max) {
emp_assert((max-min) <= (double) _RAND_MBIG, min, max); // Precision will be too low past this point...
return GetDouble() * (max - min) + min;
}
/**
* Generate a double out of a given interval.
*
* @return The pseudo random number.
* @param range The upper and lower bounds for the random numbers [lower, upper)
**/
inline double GetDouble(const Range<double> range) {
return GetDouble(range.GetLower(), range.GetUpper());
}
/**
* Generate an uint32_t.
*
* @return The pseudo random number.
* @param max The upper bound for the random numbers (will never be returned).
**/
template <typename T>
inline uint32_t GetUInt(const T max) {
emp_assert(max <= (T) _RAND_MBIG, max); // Precision will be too low past this point...
return static_cast<uint32_t>(GetDouble() * static_cast<double>(max));
}
/**
* Generate a random 32-bit block of bits.
*
* @return The pseudo random number.
**/
inline uint32_t GetUInt() {
return ( static_cast<uint32_t>(GetDouble() * 65536.0) << 16 )
+ static_cast<uint32_t>(GetDouble() * 65536.0);
}
/**
* Generate a random 64-bit block of bits.
*
* @return The pseudo random number.
**/
inline uint64_t GetUInt64Old() {
// @MAM profiled,
// this is faster than using RandFill
return ( static_cast<uint64_t>(GetUInt()) << 32 )
+ static_cast<uint64_t>(GetUInt());
}
/**
* Generate a random 64-bit block of bits.
*
* @return The pseudo random number.
**/
inline uint64_t GetUInt64() {
uint64_t res;
RandFill(reinterpret_cast<unsigned char*>(&res), sizeof(res));
return res;
}
/**
* Randomize a contiguous segment of memory.
**/
inline void RandFillOld(unsigned char* dest, const size_t num_bytes) {
// go three bytes at a time because we only get
// _RAND_MBIG (not quite four bytes) of entropy
// from the generator
// @MAM profiled,
// sampling raw bytes and rejecting the region of integer space
// that would introduce bias is faster than rescaling using double
// multiplication
const uint32_t accept_thresh = (
_RAND_MBIG - _RAND_MBIG % 16777216 /* 2^(3*8) */
);
for (size_t byte = 0; byte + 3 < num_bytes; byte += 3) {
uint32_t rnd;
while (true) {
rnd = Get();
if (rnd < accept_thresh) break;
}
std::memcpy(dest+byte, &rnd, 3);
}
if (num_bytes%3) {
uint32_t rnd;
while (true) {
rnd = Get();
if (rnd < accept_thresh) break;
}
std::memcpy(dest+num_bytes-num_bytes%3, &rnd, num_bytes%3);
}
}
/**
* Randomize a contiguous segment of memory.
**/
inline void RandFill(unsigned char* dest, const size_t num_bytes) {
// go three bytes at a time because we only get
// _RAND_MBIG (slightly more than 3 bytes) of entropy
// from the generator
for (size_t byte = 0; byte + 3 < num_bytes; byte += 3) {
uint32_t rnd;
rnd = GetDouble() * 16777216.0; /* 2^(3*8) */
std::memcpy(dest+byte, &rnd, 3);
}
if (num_bytes%3) {
uint32_t rnd;
rnd = GetDouble() * 16777216.0; /* 2^(3*8) */
std::memcpy(dest+num_bytes-num_bytes%3, &rnd, num_bytes%3);
}
}
/**
* Generate an uint64_t.
*
* @return The pseudo random number.
* @param max The upper bound for the random numbers (will never be returned).
* @todo this function needs to be tested and refined.
**/
template <typename T>
inline uint64_t GetUInt64(const T max) {
if (max <= (T) _RAND_MBIG) return (uint64_t) GetUInt(max); // Don't need extra precision.
const double max2 = ((double) max) / (double) _RAND_MBIG;
emp_assert(max2 <= (T) _RAND_MBIG, max); // Precision will be too low past this point...
return static_cast<uint64_t>(GetDouble() * static_cast<double>(max))
+ static_cast<uint64_t>(GetDouble() * static_cast<double>(max2) * _RAND_MBIG);
}
/**
* Generate an uint32_t out of an interval.
*
* @return The pseudo random number.
* @param min The lower bound for the random numbers.
* @param max The upper bound for the random numbers (will never be returned).
**/
template <typename T1, typename T2>
inline uint32_t GetUInt(const T1 min, const T2 max) {
return GetUInt<uint32_t>((uint32_t) max - (uint32_t) min) + (uint32_t) min;
}
/**
* Generate a uint32_t out of a given interval.
*
* @return The pseudo random number.
* @param range The upper and lower bounds for the random numbers [lower, upper)
**/
template <typename T>
inline uint32_t GetUInt(const Range<T> range) {
return GetUInt(range.GetLower(), range.GetUpper());
}
/**
* Generate an int out of an interval.
*
* @return The pseudo random number.
* @param min The lower bound for the random numbers.
* @param max The upper bound for the random numbers (will never be returned).
**/
inline int GetInt(const int max) { return static_cast<int>(GetUInt((uint32_t) max)); }
inline int GetInt(const int min, const int max) { return GetInt(max - min) + min; }
inline int GetInt(const Range<int> range) { return GetInt(range.GetLower(), range.GetUpper()); }
// Random Event Generation //////////////////////////////////////////////////
/// Tests a random value [0,1) against a given probability p, and returns true of false.
/// @param p The probability of the result being "true".
inline bool P(const double p) {
emp_assert(p >= 0.0 && p <= 1.0, p);
return (Get() < (p * _RAND_MBIG));
}
// Statistical functions ////////////////////////////////////////////////////
// Distributions //
/**
* Generate a random variable drawn from a unit normal distribution.
**/
inline double GetRandNormal() {
// Draw from a Unit Normal Dist
// Using Rejection Method and saving of initial exponential random variable
double expRV2;
while (1) {
expRV2 = -log(GetDouble());
expRV -= (expRV2-1)*(expRV2-1)/2;
if (expRV > 0) break;
expRV = -log(GetDouble());
}
if (P(.5)) return expRV2;
return -expRV2;
}
/**
* Generate a random variable drawn from a distribution with given
* mean and standard deviation.
**/
inline double GetRandNormal(const double mean, const double std) { return mean + GetRandNormal() * std; }
/**
* Generate a random variable drawn from a Poisson distribution.
**/
inline uint32_t GetRandPoisson(const double n, double p) {
emp_assert(p >= 0.0 && p <= 1.0, p);
// Optimizes for speed and calculability using symetry of the distribution
if (p > .5) return (uint32_t)n - GetRandPoisson(n * (1 - p));
else return GetRandPoisson(n * p);
}
/**
* Generate a random variable drawn from a Poisson distribution.
*
* @param mean The mean of the distribution.
**/
inline uint32_t GetRandPoisson(const double mean) {
// Draw from a Poisson Dist with mean; if cannot calculate, return UINT_MAX.
// Uses Rejection Method
const double a = exp(-mean);
if (a <= 0) return UINT_MAX; // cannot calculate, so return UINT_MAX
uint32_t k = 0;
double u = GetDouble();
while (u >= a) {
u *= GetDouble();
++k;
}
return k;
}
/**
* Generate a random variable drawn from a Binomial distribution.
*
* This function is exact, but slow.
* @see Random::GetApproxRandBinomial
* @see emp::Binomial in source/tools/Binomial.h
**/
inline uint32_t GetFullRandBinomial(const double n, const double p) { // Exact
emp_assert(p >= 0.0 && p <= 1.0, p);
emp_assert(n >= 0.0, n);
// Actually try n Bernoulli events, each with probability p
uint32_t k = 0;
for (uint32_t i = 0; i < n; ++i) if (P(p)) k++;
return k;
}
/**
* Generate a random variable drawn from a Binomial distribution.
*
* This function is faster than @ref Random::GetFullRandBinomial(), but
* uses some approximations. Note that for repeated calculations with
* the same n and p, the Binomial class provides a much faster and more
* exact interface.
*
* @see Random::GetFullRandBinomial
* @see emp::Binomial in source/tools/Binomial.h
**/
inline uint32_t GetApproxRandBinomial(const double n, const double p) { // Approx
emp_assert(p >= 0.0 && p <= 1.0, p);
emp_assert(n >= 0.0, n);
// Approximate Binomial if appropriate
// if np(1-p) is large, we might be tempted to use a Normal approx, but it is giving poor results.
// if (n * p * (1 - p) >= _BINOMIAL_TO_NORMAL) {
// return static_cast<uint32_t>(GetRandNormal(n * p, n * p * (1 - p)) + 0.5);
// }
// If n is large, use a Poisson approx
if (n >= _BINOMIAL_TO_POISSON) {
uint32_t k = GetRandPoisson(n, p);
if (k < UINT_MAX) return k; // if approx worked
}
// otherwise, actually generate the randBinomial
return GetFullRandBinomial(n, p);
}
/**
* By default GetRandBinomial calls the full (non-approximation) version.
*
* Note that if approximations are okay, they can create a big speedup
* for n > 1000.
*
* @see Random::GetFullRandBinomial
* @see Random::GetApproxRandBinomial
* @see emp::Binomial in source/tools/Binomial.h
**/
inline uint32_t GetRandBinomial(const double n, const double p) {
return GetFullRandBinomial(n,p);
}
};
/// This is an adaptor to make Random behave like a proper STL random number generator.
struct RandomStdAdaptor {
typedef int argument_type;
typedef int result_type;
RandomStdAdaptor(Random& rng) : _rng(rng) { }
int operator()(int n) { return _rng.GetInt(n); }
Random& _rng;
};
/// Draw a sample (with replacement) from an input range, copying to the output range.
template <typename ForwardIterator, typename OutputIterator, typename RNG>
void sample_with_replacement(ForwardIterator first, ForwardIterator last, OutputIterator ofirst, OutputIterator olast, RNG rng) {
std::size_t range = std::distance(first, last);
while(ofirst != olast) {
*ofirst = *(first+rng(range));
++ofirst;
}
}
} // END emp namespace
#endif
type,timing
old,3332
new,3310
old,3064
new,3324
old,3267
new,3185
old,2694
new,2830
old,2574
new,2661
old,2542
new,2787
old,2475
new,2698
old,2558
new,3006
old,2640
new,2693
old,2531
new,2719
old,2543
new,2722
old,2505
new,2741
old,2522
new,2734
old,2426
new,2835
old,2796
new,2869
old,2544
new,2705
old,2474
new,2743
old,2528
new,2752
old,2477
new,2721
old,2505
new,2498
old,1789
new,2595
old,1890
new,2709
old,1853
new,2228
old,1862
new,2285
old,2020
new,2446
old,1848
new,2249
old,1830
new,2756
old,2064
new,2804
old,2230
new,2309
old,1771
new,2268
old,1844
new,2268
old,2182
new,2416
old,2614
new,3117
old,1893
new,2231
old,1801
new,2237
old,2014
new,2537
old,1876
new,2857
old,2832
new,2524
old,1933
new,2306
old,2032
new,2261
old,1802
new,2246
old,2459
new,3090
old,2455
new,2236
old,1953
new,2255
old,1902
new,2292
old,2172
new,2942
old,2499
new,2501
old,1930
new,2294
old,1921
new,2474
old,2132
new,2829
old,2678
new,2919
old,1828
new,2384
old,2034
new,2389
old,2179
new,2654
old,1992
new,2647
old,1969
new,2480
old,1996
new,2609
old,2025
new,2668
old,2867
new,3075
old,1958
new,2591
old,2023
new,2454
old,2085
new,3001
old,2981
new,2689
old,2080
new,2409
old,1993
new,2554
old,2065
new,2859
old,2870
new,2969
old,2008
new,2528
old,2061
new,2592
old,2448
new,2768
old,2065
new,2546
old,1995
new,2563
old,2215
new,2636
old,2491
new,2704
old,2191
new,2815
old,1970
new,2616
old,2324
new,2648
old,2126
new,2859
old,2980
new,2895
old,2056
new,2791
old,2001
new,2563
old,2117
new,2817
old,2689
new,2914
old,2124
new,2511
old,2109
new,2620
old,2224
new,3043
old,2161
new,2682
old,2020
new,2610
old,2192
new,2657
old,2747
new,3061
old,3001
new,2788
old,2060
new,2645
old,2174
new,2612
old,2739
new,3823
old,2534
new,2739
old,2067
new,2670
old,2075
new,2891
old,2244
new,2724
old,2055
new,2708
old,2023
new,2580
old,2187
new,2611
old,2235
new,2661
old,2165
new,2692
old,2216
new,3014
old,2236
new,2755
old,2067
new,2584
old,2077
new,2648
old,2215
new,2722
old,2411
new,2610
old,2227
new,2968
old,2179
new,2920
old,2067
new,2563
old,2258
new,2536
old,2148
new,2619
old,2147
new,2787
old,2698
new,2716
old,2329
new,2526
old,17965
new,3255
old,3012
new,3293
old,3095
new,3429
old,3159
new,3482
old,3191
new,3460
old,3210
new,3387
old,3230
new,3440
old,3116
new,3384
old,3249
new,3389
old,2948
new,3287
old,2932
new,3402
old,3044
new,3234
old,3139
new,3396
old,2487
new,3275
old,2274
new,3117
old,2193
new,2640
old,2504
new,2815
old,2550
new,2788
old,2016
new,2519
old,2089
new,3012
old,2522
new,3150
old,2146
new,2437
old,2095
new,2922
old,2713
new,3157
old,2524
new,2458
old,2091
new,2749
old,2502
new,2679
old,2611
new,2567
old,2066
new,2587
old,2142
new,2692
old,2191
new,3056
old,3055
new,2834
old,2130
new,2675
old,2114
new,2662
old,2080
new,3078
old,3086
new,2796
old,2129
new,2707
old,2089
new,2636
old,2823
new,3502
old,2360
new,2609
old,2065
new,2598
old,2122
new,2717
old,2817
new,3404
old,2409
new,2556
old,2143
new,2841
old,3057
new,3288
old,2265
new,2533
old,2126
new,2757
old,3037
new,3469
old,2166
new,2548
old,2064
new,2629
old,2725
new,3250
old,2595
new,2511
old,2143
new,2582
old,2125
new,2736
old,2697
new,2881
old,2414
new,2559
old,2127
new,2736
old,2096
new,2849
old,2100
new,2609
old,2235
new,2634
old,2309
new,3119
old,3182
new,2679
old,2148
new,2719
old,2142
new,2736
old,2425
new,2633
old,2238
new,3261
old,2838
new,2778
old,2238
new,2572
old,2182
new,2695
old,2218
new,3058
old,2277
new,2861
old,2119
new,2703
old,2254
new,2646
old,2257
new,2764
old,2435
new,2702
old,2236
new,2605
old,2235
new,2685
old,2251
new,2662
old,2526
new,2753
old,2413
new,2533
old,2326
new,2567
old,2100
new,2787
old,2721
new,2981
old,2364
new,2563
old,2098
new,2723
old,2276
new,3092
old,2188
new,2715
old,2288
new,2547
old,2187
new,2689
old,2351
new,2797
old,2764
new,3311
old,2373
new,2591
old,2410
new,2943
old,2232
new,2918
old,2408
new,2837
old,2353
new,2662
old,2245
new,2528
old,2123
new,2955
old,2277
new,2965
old,2213
new,2647
old,2140
new,2725
old,2233
new,3110
old,2619
new,2890
old,2073
new,2703
old,2148
new,2719
old,2362
new,2910
old,2820
new,3343
old,2002
new,2616
old,2256
new,2828
old,2101
new,2965
old,2260
new,2966
old,2212
new,2710
old,2254
new,2575
old,2158
new,2928
old,2415
new,2935
old,2227
new,3372
old,2389
new,2706
old,2205
new,3227
old,2795
new,3172
old,1993
new,2625
old,2127
new,2762
old,2444
new,2780
old,2236
new,3250
old,2099
new,2803
old,2127
new,2811
old,2035
new,2941
old,2355
new,2916
old,2119
new,2844
old,2121
new,2642
old,2170
new,3031
old,2597
new,2804
old,2129
new,2691
old,2184
new,2726
old,2374
new,2912
old,2621
new,2914
old,2022
new,2644
old,2169
new,2747
old,2360
new,2905
old,2394
new,2866
old,2085
new,2613
old,2225
new,2720
old,2092
new,2713
old,3097
new,3453
old,1996
new,2772
old,2017
new,2601
old,2137
new,3209
old,3078
new,2857
old,2108
new,2696
old,2127
new,2711
old,2601
new,3397
old,2594
new,2607
old,2130
new,2641
old,2253
new,2788
old,2641
new,3022
old,2343
new,2604
old,2146
new,2726
old,2206
new,2634
old,2212
new,3005
old,2218
new,2927
old,2032
new,2754
old,1987
new,2650
old,2211
new,3030
old,2458
new,2800
old,2030
new,2692
old,2226
new,2719
old,2325
new,3297
old,3089
new,2612
old,2110
new,2601
old,2162
new,2746
old,2109
new,2800
old,3056
new,3167
old,1994
new,2617
old,2239
new,2657
old,2053
new,3052
old,3216
new,2956
old,2075
new,2658
old,2119
new,2703
old,2130
new,3183
old,3176
new,2798
old,2087
new,2723
old,2133
new,2780
old,2964
new,3299
old,3053
new,2761
old,2098
new,2759
old,2592
new,3227
old,2527
new,2948
old,2039
new,2671
old,2282
new,2828
old,2121
new,2784
old,2416
new,2948
old,2452
new,2782
old,2045
new,2562
old,2196
new,3090
old,2384
new,2989
old,2464
new,2627
old,2088
new,2727
old,2163
new,3130
old,2366
new,2730
old,2048
new,2709
old,2130
new,2735
old,2227
new,3068
old,2416
new,2872
old,2054
new,2717
old,2295
new,2679
old,2281
new,2826
old,2458
new,2916
old,2186
new,2593
old,2142
new,2700
old,2103
new,2927
old,2556
new,2980
old,2307
new,2697
old,2136
new,2727
old,2189
new,3040
old,2674
new,3125
old,2050
new,2645
old,2101
new,2755
old,2336
new,3022
old,2207
new,2672
old,2273
new,2548
old,2298
new,2807
old,2228
new,2759
old,2637
new,2750
old,2433
new,2572
old,2522
new,2673
old,2165
new,2799
old,2984
new,3308
old,2093
new,2644
old,2188
new,2699
old,2204
new,3110
old,2745
new,2854
old,2104
new,2688
old,2201
new,2830
old,2156
new,3137
old,2638
new,2887
old,2201
new,2694
old,2285
new,2850
old,2131
new,2895
old,2337
new,2960
old,2306
new,2848
old,2379
new,2742
old,2243
new,3007
old,3150
new,3029
old,2097
new,2644
old,2171
new,2773
old,2306
new,3144
old,2580
new,2661
old,2054
new,2731
old,2279
new,2827
old,2652
new,2935
old,2208
new,2895
old,2199
new,2729
old,2512
new,2659
old,2200
new,3037
old,2209
new,3153
old,2440
new,2622
old,2204
new,2719
old,2373
new,3114
old,2314
new,2801
old,2201
new,2738
old,2176
new,2888
old,2625
new,2973
old,2586
new,2579
old,2185
new,2724
old,2727
new,3170
old,2999
new,2844
old,2165
new,2708
old,2409
new,2839
old,2796
new,3453
old,2221
new,2667
old,2312
new,2830
old,2723
new,2750
old,2675
new,2564
old,2454
new,2855
old,2420
new,3330
old,2699
new,2554
old,2457
new,2875
old,2276
new,2579
old,2201
new,2677
old,2249
new,2637
old,2142
new,3353
old,2922
new,2611
old,2179
new,2702
old,2636
new,2721
old,2311
new,2694
old,2186
new,3327
old,3034
new,2586
old,2131
new,2699
old,2416
new,2719
old,2454
new,3227
old,3137
new,2838
old,2139
new,2801
old,2288
new,2847
old,2349
new,3525
old,2562
new,2713
old,2190
new,2890
old,2126
new,2666
old,2712
new,2857
old,2518
new,2690
old,2142
new,2732
old,2154
new,2826
old,2965
new,3499
old,2209
new,2649
old,2207
new,2918
old,2562
new,2840
old,2566
new,2586
old,2189
new,2770
old,2696
new,3267
old,2620
new,2617
old,2128
new,2672
old,2242
new,2910
old,2938
new,3058
old,2083
new,2580
old,2257
new,2729
old,2204
new,2806
old,2140
new,2735
old,2381
new,2686
old,2153
new,2724
old,2139
new,2708
old,2741
new,2787
old,2572
new,2546
old,2181
new,2716
old,2169
new,2836
old,3091
new,3560
old,2092
new,2617
old,2202
new,2722
old,2424
new,3234
old,3000
new,3124
old,2141
new,2649
old,2241
new,2624
old,2281
new,2630
old,3075
new,3206
old,2257
new,2632
old,2266
new,2644
old,2181
new,3039
old,3166
new,2923
old,2225
new,2597
old,2208
new,2713
old,2210
new,3099
old,2189
new,2906
old,2194
new,2684
old,2241
new,2825
old,2474
new,3226
old,2152
new,2892
old,2054
new,2759
old,2359
new,2737
old,2180
new,2968
old,2357
new,2845
old,2273
new,2734
old,2317
new,2678
old,2237
new,3072
old,2430
new,2915
old,2252
new,2645
old,2254
new,2768
old,2780
new,2957
old,2956
new,2753
old,2116
new,2685
old,2195
new,2909
old,2785
new,3009
old,2579
new,2546
old,2210
new,2867
old,2468
new,2671
old,2693
new,3417
old,2266
new,2817
old,2598
new,2644
old,2241
new,2700
old,3054
new,3475
old,2153
new,2610
old,2155
new,2715
old,3022
new,3308
old,2766
new,2659
old,2205
new,3014
old,2298
new,2941
old,2331
new,3053
old,2222
new,2768
old,3030
new,3522
old,2314
new,2637
old,2200
new,2759
old,3110
new,3462
old,2161
new,2629
old,2195
new,2770
old,3093
new,3518
old,2274
new,2586
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment