简体   繁体   English

如何生成随机次正规数?

[英]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:有了这个,我们有以下策略:

  1. Draw 32/64 bits uniformly.统一绘制32/64位。 We won't need all of these bits, but it'll be more convenient and faster to draw them this way.我们不需要所有这些位,但以这种方式绘制它们会更方便、更快捷。 We'll just randomize as many bits as a floating-point number requires and then...我们将随机化浮点数所需的位数,然后......
  2. Mask out the exponent bits so they are zero屏蔽掉指数位,使它们为零
  3. Convert the bit pattern into a floating-point number将位模式转换为浮点数

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) (单精度)

  1. 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.否则调整大小。

  2. 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 值。

  3. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM