📄 random.cpp
字号:
template<> Double Random12<true,true,Double>(RandomState& state) {
// Get uniform number between 1 and 2 at max precision
// Generate bits
SizedUnsignedInteger<64>::Type r12 = Accessor<64>::getRandomInt(state);
// Keep 2^52 + 1 possibilities
// See comment in Simple version
// allow %= only for 64-bit register machines
#if STREFLOP_RANDOM_GEN_SIZE == 64
r12 %= 0x0010000000000001ULL;
#else
// Choose to avoid % operator by having about 1/2 chance of rejection. Is this faster?
while ((r12 &= 0x001FFFFFFFFFFFFFULL) > 0x0010000000000000ULL) r12 = Accessor<64>::getRandomInt(state);
#endif
// bitwise add exponent so it's in the [1.0-2.0] range
r12 += 0x3FF0000000000000ULL;
return *reinterpret_cast<Double*>(&r12);
}
// Random in a 1..2 - need to exclude both bounds
template<> Double Random12<false,false,Double>(RandomState& state) {
// Get uniform number between 1 and 2 at max precision
// Generate bits
SizedUnsignedInteger<64>::Type r12 = Accessor<64>::getRandomInt(state);
// Keep 2^52 - 1 possibilities
// See comment in Simple version
// r12 %= 0x000FFFFFFFFFFFFFULL;
// Choose to avoid % operator by having very small chance of rejection
while ((r12 &= 0x000FFFFFFFFFFFFFULL) == 0x000FFFFFFFFFFFFFULL) r12 = Accessor<64>::getRandomInt(state);
// bitwise add exponent so it's in the (1.0-2.0) range
r12 += 0x3FF0000000000001ULL;
return *reinterpret_cast<Double*>(&r12);
}
#ifdef Extended
// little endian
#if __FLOAT_WORD_ORDER == 1234
/// Little endian is fine, always the same offsets whatever the memory model
template<int Nbytes> struct ExtendedConverter {
// Sign and exponent
static inline SizedUnsignedInteger<16>::Type* sexpPtr(Extended* e) {
return reinterpret_cast<SizedUnsignedInteger<16>::Type*>(reinterpret_cast<char*>(e)+8);
}
// Mantissa
static inline SizedUnsignedInteger<64>::Type* mPtr(Extended* e) {
return reinterpret_cast<SizedUnsignedInteger<64>::Type*>(e);
}
};
// Big endian
#elif __FLOAT_WORD_ORDER == 4321
template<int Nbytes> struct ExtendedConverter {
}
/// Extended is softfloat
template<> struct ExtendedConverter<10> {
// Sign and exponent
static inline SizedUnsignedInteger<16>::Type* sexpPtr(Extended* e) {
return reinterpret_cast<SizedUnsignedInteger<16>::Type*>(e);
}
// Mantissa
static inline SizedUnsignedInteger<64>::Type* mPtr(Extended* e) {
return reinterpret_cast<SizedUnsignedInteger<64>::Type*>(reinterpret_cast<char*>(e)+2);
}
};
/// Default gcc model for x87 - 32 bits (or with -m96bit-long-double)
template<> struct ExtendedConverter<12> {
// Sign and exponent
static inline SizedUnsignedInteger<16>::Type* sexpPtr(Extended* e) {
return reinterpret_cast<SizedUnsignedInteger<16>::Type*>(reinterpret_cast<char*>(e)+2);
}
// Mantissa
static inline SizedUnsignedInteger<64>::Type* mPtr(Extended* e) {
return reinterpret_cast<SizedUnsignedInteger<64>::Type*>(reinterpret_cast<char*>(e)+4);
}
};
/// Default gcc model for x87 - 64 bits (or with -m128bit-long-double)
template<> struct ExtendedConverter<16> {
// Sign and exponent
static inline SizedUnsignedInteger<16>::Type* sexpPtr(Extended* e) {
return reinterpret_cast<SizedUnsignedInteger<16>::Type*>(reinterpret_cast<char*>(e)+6);
}
// Mantissa
static inline SizedUnsignedInteger<64>::Type* mPtr(Extended* e) {
return reinterpret_cast<SizedUnsignedInteger<64>::Type*>(reinterpret_cast<char*>(e)+8);
}
};
#else
#error unknown byte order
#endif
// Return a random float
template<> Extended Random<Extended>(RandomState& state) {
// Work directly on Extended bits
Extended ret;
// Generate 63 bits for the mantissa
*ExtendedConverter<sizeof(Extended)>::mPtr(&ret) = Accessor<64>::getRandomInt(state);
// Generate 16 bits for the exponent
*ExtendedConverter<sizeof(Extended)>::sexpPtr(&ret) = Accessor<16>::getRandomInt(state);
// Discard NaNs and Inf, ignore sign
while ((*ExtendedConverter<sizeof(Extended)>::sexpPtr(&ret) & 0x7fff) == 0x7fff)
*ExtendedConverter<sizeof(Extended)>::sexpPtr(&ret) = Accessor<16>::getRandomInt(state);
// x87 extended format oddity: the first mantissa bit (always 1 for normal numbers) is visible, not hidden!
if ((*ExtendedConverter<sizeof(Extended)>::sexpPtr(&ret) & 0x7fff) != 0)
*ExtendedConverter<sizeof(Extended)>::mPtr(&ret) |= 0x8000000000000000ULL;
return ret;
}
// Random in 1..2 - ideal IE case
template<> Extended Random12<true,false,Extended>(RandomState& state) {
// Get uniform number between 1 and 2 at max precision
// Work directly on Extended bits
Extended r12;
// Generate 63 bits for the mantissa
*ExtendedConverter<sizeof(Extended)>::mPtr(&r12) = Accessor<64>::getRandomInt(state);
// x87 extended format oddity: the first mantissa bit (always 1 for normal numbers) is visible, not hidden!
// Since in this case this is a number between 1 and 2, this bit has to be set explicitly
*ExtendedConverter<sizeof(Extended)>::mPtr(&r12) |= 0x8000000000000000ULL;
// Set exponent so it's in the [1.0-2.0) range
*ExtendedConverter<sizeof(Extended)>::sexpPtr(&r12) = 0x3FFF;
// scale from 1-2 interval to the desired interval
return r12;
}
// Random in 1..2 - near ideal EI case
template<> Extended Random12<false,true,Extended>(RandomState& state) {
// Get uniform number between 1 and 2 at max precision
// Work directly on Extended bits
Extended r12;
// Generate 63 bits for the mantissa
*ExtendedConverter<sizeof(Extended)>::mPtr(&r12) = Accessor<64>::getRandomInt(state);
// x87 extended format oddity: the first mantissa bit (always 1 for normal numbers) is visible, not hidden!
// Since in this case this is a number between 1 and 2, this bit has to be set explicitly
*ExtendedConverter<sizeof(Extended)>::mPtr(&r12) |= 0x8000000000000000LL;
// Set exponent so it's in the (1.0-2.0] range
// Replace 1.0 by 2.0
if (*ExtendedConverter<sizeof(Extended)>::mPtr(&r12) == 0x8000000000000000LL)
*ExtendedConverter<sizeof(Extended)>::sexpPtr(&r12) = 0x4000;
else
*ExtendedConverter<sizeof(Extended)>::sexpPtr(&r12) = 0x3FFF;
return r12;
}
// Random in 1..2 - need to include both bounds
template<> Extended Random12<true,true,Extended>(RandomState& state) {
// Get uniform number between 1 and 2 at max precision
// Work directly on Extended bits
Extended r12;
// Generate 64 bits for the mantissa
do {
*ExtendedConverter<sizeof(Extended)>::mPtr(&r12) = Accessor<64>::getRandomInt(state);
}
// Include both bounds : repeat the random get till it's in the desired range
// Keep the possibility for 2.0 in addition to all [1.0-2.0)
while (*ExtendedConverter<sizeof(Extended)>::mPtr(&r12) > 0x8000000000000000LL);
// Set exponent so it's in the [1.0-2.0] range
// Check if 2.0 was selected
if (*ExtendedConverter<sizeof(Extended)>::mPtr(&r12) == 0x8000000000000000LL)
*ExtendedConverter<sizeof(Extended)>::sexpPtr(&r12) = 0x4000;
// otherwise, set the correct mantissa bit and the correct exponent
else {
// x87 extended format oddity: the first mantissa bit (always 1 for normal numbers) is visible, not hidden!
// Since in this case this is a number between 1 and 2, this bit has to be set explicitly
*ExtendedConverter<sizeof(Extended)>::mPtr(&r12) |= 0x8000000000000000LL;
*ExtendedConverter<sizeof(Extended)>::sexpPtr(&r12) = 0x3FFF;
}
return r12;
}
// Random in 1..2 - need to exclude both bounds
template<> Extended Random12<false,false,Extended>(RandomState& state) {
// Get uniform number between 1 and 2 at max precision
// Work directly on Extended bits
Extended r12;
// Generate 63 bits for the mantissa
do {
*ExtendedConverter<sizeof(Extended)>::mPtr(&r12) = Accessor<64>::getRandomInt(state);
// x87 extended format oddity: the first mantissa bit (always 1 for normal numbers) is visible, not hidden!
// Since in this case this is a number between 1 and 2, this bit has to be set explicitly
*ExtendedConverter<sizeof(Extended)>::mPtr(&r12) |= 0x8000000000000000LL;
}
// Exclude both bounds : repeat the random get till it's in the desired range
// Remove the possibility for 1.0 compared to all [1.0-2.0)
while (*ExtendedConverter<sizeof(Extended)>::mPtr(&r12) == 0x8000000000000000LL);
// Set exponent so it's in the (1.0-2.0) range
*ExtendedConverter<sizeof(Extended)>::sexpPtr(&r12) = 0x3FFF;
// scale from 1-2 interval to the desired interval
return r12;
}
#endif
// This is a way to hide the implementation from the header
// And also to ensure there is only one template instanciation, instead of duplicating
// the code in all object files
template<typename FloatType> static inline FloatType NRandom_Generic(FloatType *secondary, RandomState& state) {
FloatType x, y, d;
// Generate a point strictly inside the unit circle
do {
// Use IE as this is the most convenient for the generation,
// any will do since the bounds are rejected anyway by unit circle strict comparison
x = RandomIE(FloatType(-1.0), FloatType(1.0), state);
y = RandomIE(FloatType(-1.0), FloatType(1.0), state);
d = x*x + y*y;
} while (d>=FloatType(1.0));
// Convert from x/y to uniform
FloatType conv = sqrt( FloatType(-2.0) * log(d) / d );
// Use one result as secondary independent variable, if user wishes
if (secondary) *secondary = x * conv;
// return the other
return y * conv;
}
// Specialize for the Float types declared in the header
template<> Simple NRandom(Simple *secondary, RandomState& state) {
return NRandom_Generic<Simple>(secondary,state);
}
/*
template<> Double NRandom(Double *secondary, RandomState& state) {
return NRandom_Generic<Double>(secondary,state);
}
#if defined(Extended)
template<> Extended NRandom(Extended *secondary, RandomState& state) {
return NRandom_Generic<Extended>(secondary,state);
}
#endif
*/
// May save one mul
template<typename FloatType> static inline FloatType NRandom_Generic(FloatType mean, FloatType std_dev, FloatType *secondary, RandomState& state) {
FloatType x, y, d;
// Generate a point strictly inside the unit circle
do {
// Use IE as this is the most convenient for the generation,
// any will do since the bounds are rejected anyway by unit circle strict comparison
x = RandomIE(FloatType(-1.0), FloatType(1.0), state);
y = RandomIE(FloatType(-1.0), FloatType(1.0), state);
d = x*x + y*y;
} while (d>=FloatType(1.0));
// Convert from x/y to uniform
FloatType conv = sqrt( FloatType(-2.0) * log(d) / d ) * std_dev;
// Use one result as secondary independent variable, if user wishes
if (secondary) *secondary = x * conv + mean;
// return the other
return y * conv + mean;
}
// Specialize for the Float types declared in the header
template<> Simple NRandom(Simple mean, Simple std_dev, Simple *secondary, RandomState& state) {
return NRandom_Generic<Simple>(mean, std_dev, secondary,state);
}
/*
template<> Double NRandom(Double mean, Double std_dev, Double *secondary, RandomState& state) {
return NRandom_Generic<Double>(mean, std_dev, secondary,state);
}
#if defined(Extended)
template<> Extended NRandom(Extended mean, Extended std_dev, Extended *secondary, RandomState& state) {
return NRandom_Generic<Extended>(mean, std_dev, secondary,state);
}
#endif
*/
SizedUnsignedInteger<32>::Type RandomInit(RandomState& state) {
return RandomInit(SizedUnsignedInteger<32>::Type(time(0)));
}
SizedUnsignedInteger<32>::Type RandomInit(SizedUnsignedInteger<32>::Type seed, RandomState& state) {
init_genrand(seed,state);
return state.seed;
}
SizedUnsignedInteger<32>::Type RandomSeed(RandomState& state) {
return state.seed;
}
// Default state holder, so single threaded applications don't bother setting up an object
RandomState DefaultRandomState;
} // end streflop namespace
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -