Skip to content

Instantly share code, notes, and snippets.

@mmore500
Last active Nov 24, 2019
Embed
What would you like to do?
emp::Random::RandFill 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();
unsigned char data[1000000];
rand.RandFillOld(data, sizeof(data));
const auto stop = std::chrono::high_resolution_clock::now();
timing = std::chrono::duration_cast<std::chrono::microseconds>(
stop - start
).count();
for (size_t i = 0; i < 1e6; ++i) {
sum += data[i];
}
dfile.Update();
}
{
type = "new";
const auto start = std::chrono::high_resolution_clock::now();
unsigned char data[1000000];
rand.RandFill(data, sizeof(data));
const auto stop = std::chrono::high_resolution_clock::now();
timing = std::chrono::duration_cast<std::chrono::microseconds>(
stop - start
).count();
for (size_t i = 0; i < 1e6; ++i) {
sum += data[i];
}
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,972
new,1027
old,1020
new,1996
old,778
new,849
old,613
new,883
old,607
new,858
old,653
new,1244
old,848
new,848
old,623
new,972
old,952
new,1773
old,613
new,908
old,600
new,1768
old,867
new,825
old,599
new,942
old,947
new,1208
old,608
new,1700
old,867
new,851
old,888
new,1274
old,888
new,911
old,643
new,950
old,1130
new,849
old,917
new,1091
old,1082
new,919
old,618
new,1168
old,906
new,1746
old,1001
new,1666
old,1007
new,1618
old,1004
new,1703
old,954
new,1594
old,881
new,1774
old,916
new,1625
old,821
new,1938
old,923
new,1611
old,748
new,1736
old,835
new,1558
old,733
new,1825
old,932
new,1655
old,919
new,1649
old,739
new,1568
old,893
new,1717
old,887
new,1686
old,913
new,1608
old,799
new,1580
old,839
new,1814
old,830
new,1756
old,754
new,1658
old,643
new,896
old,871
new,1993
old,690
new,846
old,897
new,1589
old,639
new,912
old,850
new,1107
old,686
new,895
old,827
new,1669
old,678
new,979
old,720
new,1688
old,666
new,958
old,812
new,1800
old,658
new,980
old,846
new,1740
old,947
new,1646
old,985
new,1637
old,671
new,871
old,695
new,1903
old,973
new,1002
old,750
new,1883
old,658
new,1042
old,966
new,1962
old,731
new,981
old,1000
new,1892
old,726
new,1140
old,958
new,1808
old,682
new,1496
old,923
new,1078
old,761
new,1276
old,867
new,1131
old,747
new,1504
old,965
new,932
old,716
new,1525
old,942
new,1468
old,748
new,1833
old,895
new,1308
old,732
new,1939
old,728
new,1391
old,838
new,1968
old,677
new,989
old,824
new,1882
old,685
new,959
old,871
new,1598
old,668
new,1116
old,685
new,1535
old,702
new,1169
old,767
new,2007
old,691
new,1038
old,735
new,1847
old,771
new,1008
old,747
new,1806
old,723
new,989
old,737
new,1339
old,766
new,1029
old,942
new,1397
old,718
new,989
old,1041
new,1347
old,745
new,1023
old,1166
new,1026
old,732
new,1170
old,1106
new,975
old,688
new,1186
old,1120
new,984
old,740
new,1127
old,1083
new,1016
old,688
new,1012
old,1057
new,1384
old,705
new,1276
old,937
new,1287
old,678
new,1888
old,814
new,935
old,725
new,1158
old,817
new,1022
old,738
new,1192
old,883
new,1015
old,720
new,1949
old,1121
new,991
old,920
new,1950
old,1130
new,1026
old,967
new,1822
old,694
new,1084
old,1140
new,1912
old,726
new,1098
old,1011
new,931
old,713
new,1054
old,1184
new,1998
old,1217
new,2010
old,1217
new,1923
old,1129
new,1993
old,1313
new,1874
old,1148
new,2016
old,1210
new,2025
old,951
new,1244
old,1102
new,997
old,879
new,1092
old,710
new,1034
old,922
new,1404
old,1069
new,992
old,736
new,1127
old,788
new,1818
old,1233
new,974
old,736
new,1481
old,801
new,990
old,903
new,1041
old,837
new,1890
old,779
new,961
old,739
new,1128
old,1031
new,1060
old,732
new,1015
old,944
new,930
old,730
new,1257
old,1100
new,1873
old,812
new,1986
old,737
new,1186
old,802
new,1816
old,685
new,1129
old,705
new,1793
old,699
new,941
old,953
new,1876
old,770
new,1000
old,979
new,1856
old,775
new,1114
old,940
new,1466
old,714
new,1081
old,940
new,1587
old,757
new,1633
old,1203
new,1000
old,660
new,1803
old,866
new,986
old,716
new,1289
old,1103
new,1015
old,757
new,1106
old,663
new,994
old,677
new,1190
old,1077
new,951
old,764
new,1602
old,913
new,1079
old,700
new,1506
old,957
new,959
old,738
new,1175
old,1007
new,1379
old,709
new,1518
old,786
new,1005
old,722
new,1364
old,877
new,1004
old,738
new,1448
old,866
new,971
old,754
new,1672
old,673
new,997
old,871
new,1835
old,679
new,991
old,794
new,1446
old,1069
new,1017
old,659
new,1083
old,695
new,958
old,878
new,1734
old,656
new,986
old,837
new,1706
old,727
new,1259
old,825
new,1976
old,685
new,1058
old,951
new,1945
old,722
new,1165
old,1098
new,1714
old,688
new,1385
old,1150
new,1092
old,722
new,1311
old,1286
new,973
old,675
new,1642
old,893
new,1339
old,661
new,1968
old,637
new,994
old,799
new,2002
old,698
new,1156
old,792
new,1645
old,708
new,1095
old,820
new,1879
old,684
new,1053
old,840
new,1933
old,724
new,990
old,943
new,1898
old,726
new,1168
old,1057
new,1656
old,745
new,1199
old,1216
new,991
old,800
new,1262
old,933
new,1000
old,741
new,1081
old,943
new,1001
old,770
new,1112
old,1030
new,1010
old,778
new,1077
old,899
new,1787
old,779
new,1945
old,710
new,1020
old,796
new,1860
old,711
new,1074
old,755
new,1930
old,761
new,1018
old,918
new,1929
old,740
new,1153
old,954
new,1520
old,783
new,1069
old,1054
new,1490
old,685
new,1693
old,893
new,981
old,719
new,1867
old,804
new,999
old,706
new,2083
old,684
new,1256
old,790
new,1987
old,672
new,1143
old,735
new,1606
old,687
new,1033
old,715
new,1228
old,1008
new,1357
old,829
new,1204
old,1060
new,1345
old,1072
new,1858
old,1034
new,1320
old,1188
new,1880
old,706
new,1015
old,932
new,1363
old,691
new,1473
old,975
new,1475
old,832
new,1779
old,938
new,1380
old,746
new,1341
old,873
new,1097
old,688
new,1099
old,877
new,1217
old,633
new,1582
old,725
new,1030
old,825
new,1609
old,883
new,1268
old,1002
new,1340
old,710
new,1194
old,1106
new,1143
old,694
new,1281
old,1063
new,1161
old,786
new,1074
old,987
new,1381
old,749
new,995
old,982
new,2117
old,814
new,1090
old,864
new,1135
old,771
new,1189
old,1103
new,1167
old,822
new,1267
old,1067
new,1713
old,757
new,1976
old,682
new,1037
old,1022
new,1150
old,658
new,1024
old,961
new,2075
old,682
new,1154
old,1019
new,1848
old,878
new,1604
old,830
new,1603
old,596
new,935
old,725
new,1331
old,638
new,1176
old,1164
new,1494
old,752
new,1092
old,971
new,1391
old,791
new,1335
old,974
new,1881
old,801
new,1690
old,895
new,1234
old,774
new,1145
old,1126
new,1437
old,965
new,1032
old,822
new,1103
old,1028
new,989
old,889
new,1106
old,1194
new,1174
old,724
new,1144
old,797
new,1089
old,839
new,993
old,737
new,995
old,789
new,1002
old,722
new,1038
old,706
new,1026
old,794
new,2123
old,828
new,1743
old,730
new,2057
old,767
new,1360
old,1196
new,988
old,1013
new,2034
old,721
new,1146
old,1071
new,1002
old,1036
new,1236
old,1076
new,1943
old,709
new,1026
old,879
new,1187
old,779
new,1140
old,994
new,1268
old,796
new,1437
old,985
new,1305
old,865
new,1166
old,1009
new,1886
old,665
new,1055
old,1064
new,1666
old,714
new,1812
old,813
new,1085
old,912
new,2062
old,805
new,1097
old,1050
new,1952
old,784
new,1603
old,833
new,1830
old,844
new,1706
old,665
new,1865
old,919
new,1782
old,732
new,1818
old,875
new,1635
old,795
new,1652
old,889
new,1722
old,967
new,1583
old,851
new,1665
old,936
new,1670
old,825
new,1855
old,787
new,1612
old,644
new,1930
old,884
new,1677
old,642
new,1874
old,679
new,861
old,697
new,978
old,645
new,1057
old,796
new,1070
old,685
new,1228
old,1101
new,1288
old,801
new,1143
old,953
new,1403
old,751
new,1085
old,1055
new,1849
old,863
new,1166
old,804
new,2011
old,740
new,1474
old,702
new,1049
old,985
new,1223
old,1014
new,1030
old,1120
new,2016
old,688
new,1057
old,1140
new,1910
old,787
new,1673
old,609
new,1773
old,871
new,1633
old,947
new,1396
old,780
new,1154
old,992
new,2026
old,770
new,1110
old,789
new,2014
old,686
new,1999
old,705
new,1029
old,1079
new,1911
old,716
new,1217
old,1226
new,1874
old,635
new,1585
old,853
new,1916
old,826
new,851
old,621
new,1764
old,653
new,1016
old,653
new,1446
old,743
new,1126
old,985
new,1479
old,713
new,1137
old,796
new,1143
old,807
new,1205
old,1046
new,1494
old,848
new,1193
old,1034
new,1383
old,852
new,1944
old,764
new,1233
old,1102
new,1916
old,1056
new,1669
old,850
new,1558
old,900
new,1743
old,936
new,1643
old,942
new,1671
old,948
new,1664
old,946
new,1420
old,896
new,1539
old,927
new,1523
old,888
new,1579
old,887
new,1505
old,887
new,1695
old,986
new,1622
old,937
new,1711
old,843
new,1646
old,667
new,992
old,641
new,1775
old,824
new,1465
old,682
new,1035
old,722
new,1113
old,726
new,2148
old,722
new,1018
old,722
new,2264
old,875
new,1209
old,934
new,2026
old,804
new,1137
old,992
new,1119
old,751
new,967
old,1057
new,1122
old,744
new,982
old,955
new,1753
old,985
new,1840
old,876
new,1790
old,835
new,1788
old,750
new,1611
old,792
new,1957
old,788
new,1551
old,822
new,1876
old,787
new,1605
old,786
new,1826
old,796
new,1657
old,858
new,1873
old,849
new,1562
old,686
new,894
old,819
new,1047
old,660
new,1032
old,870
new,1183
old,725
new,1288
old,957
new,1125
old,920
new,1143
old,952
new,1035
old,927
new,1205
old,781
new,1031
old,983
new,2173
old,1314
new,1995
old,729
new,1141
old,868
new,1929
old,769
new,956
old,720
new,1985
old,790
new,1147
old,765
new,2074
old,976
new,1182
old,1109
new,1428
old,722
new,2003
old,740
new,1040
old,1026
new,1156
old,720
new,1123
old,967
new,1958
old,808
new,1986
old,813
new,1803
old,813
new,1750
old,820
new,1783
old,786
new,1077
old,694
new,1765
old,705
new,1038
old,710
new,1892
old,775
new,992
old,721
new,1930
old,743
new,1004
old,733
new,1528
old,781
new,1251
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment