[英]How do I generate random subnormal numbers?
I'd like to verify a piece of code works on subnormal numbers, so I'd like to generate a bunch of random subnormal single-precision numbers (including zero).我想验证一段代码是否适用于次正规数,所以我想生成一堆随机的次正规单精度数(包括零)。 How can I do this?
我怎样才能做到这一点?
Solutions such as dividing by a large number to get a subnormal may just round to zero or, in the best case, probably won't give an even distribution.除以大数以获得次正规的解决方案可能会四舍五入为零,或者在最好的情况下,可能不会给出均匀分布。
nextafter
iteration could work, but it'd be slow! nextafter
迭代可以工作,但它会很慢!
First, recall that a首先,回想一下
With this in hand we have the following strategy:有了这个,我们有以下策略:
A caveat is that the endianness of the exponent bit mask must match the endianness of the floating-point values .需要注意的是,指数位掩码的字节序必须与浮点值的字节序相匹配。 This is the case for most hardware, but you should test it if you want to be exceptionally rigorous or are working on something exotic.
大多数硬件都是这种情况,但如果您想格外严格或正在研究一些奇特的东西,则应该对其进行测试。
All that said, we get this code:话虽如此,我们得到了这段代码:
// Compile with: clang++.par -O3 -march=native test2.cpp --std=c++20 -Wall -Wextra -pedantic -Werror
#include <concepts>
#include <iostream>
#include <random>
#include <type_traits>
template<std::floating_point T>
class uniform_subnormal_distribution {
private:
// float is SignBit + 8 Exponent Bits + 23 Mantissa Bits
static constexpr uint32_t subnormal_mask32 = 0x807FFFFF;
// double is SignBit + 11 Exponent Bits + 52 Mantissa Bits
static constexpr uint64_t subnormal_mask64 = 0x800FFFFFFFFFFFFF;
public:
template<class Engine>
T operator()(Engine& eng) const {
if constexpr (std::is_same_v<T, float>){
std::uniform_int_distribution<uint32_t> dist;
// Get uniformaly distributed bits
const uint32_t bits = dist(eng);
// Make the exponent all zeros
const uint32_t subnormal_bits = bits & subnormal_mask32;
// Retrieve a floating-point value from the bits
return std::bit_cast<float, uint32_t>(subnormal_bits);
} else if constexpr (std::is_same_v<T, double>){
std::uniform_int_distribution<uint64_t> dist;
const uint64_t bits = dist(eng);
const uint64_t subnormal_bits = bits & subnormal_mask32;
return std::bit_cast<double, uint64_t>(subnormal_bits);
} else {
// can't use 'false' -- expression has to depend on a template parameter
static_assert(!sizeof(T*), "Unsupported floating-point type");
}
}
};
int main(){
std::random_device rd;
std::mt19937 mt(rd());
uniform_subnormal_distribution<float> dist;
std::vector<float> res;
for (unsigned i = 0; i < 20; i++) {
const auto float_val = dist(mt);
std::cout<<float_val<<std::endl;
res.push_back(float_val);
}
return 0;
}
How do I generate random subnormal numbers?
如何生成随机次正规数? (single-precision)
(单精度)
As the binary precision of single-precision is commonly 23 bits, generate 24 random bits: 1 for the sign and 23 for the significand.由于单精度的二进制精度一般为23位,生成24位随机位:1位符号位,23位尾数位。 Otherwise adjust the size.
否则调整大小。
Scale the 23-bit unsigned integer value by r23 * std::numeric_limits<float>::min() / 0x800000u /* 2^23 */
.按
r23 * std::numeric_limits<float>::min() / 0x800000u /* 2^23 */
缩放 23 位无符号 integer 值。
Apply the random sign bit.应用随机符号位。
Not that this may also generate +/- 0.0.并不是说这也可能产生 +/- 0.0。 By spec, zeroes are not sub-normals, yet I suspect for OP's purposes generating a zero is OK.
根据规范,零不是次常态,但我怀疑出于 OP 的目的生成零是可以的。 If not, add a test for zero.
如果不是,请添加零测试。
No endian issues.没有字节序问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.