如何将标准::位集<64>转换为双精度?

How can you convert a std::bitset<64> to a double?

本文关键字:gt 双精度 转换 lt 标准 位集      更新时间:2023-10-16

有没有办法在不使用任何外部库(Boost等)的情况下将std::bitset<64>转换为双精度?我正在使用位集来表示遗传算法中的基因组,我需要一种方法将一组位转换为双精度。

C++11路:

union Converter { uint64_t i; double d; };
double convert(std::bitset<64> const& bs) {
    Converter c;
    c.i = bs.to_ullong();
    return c.d;
}

编辑:如注释中所述,我们可以使用char*别名,因为它未指定而不是未定义。

double convert(std::bitset<64> const& bs) {
    static_assert(sizeof(uint64_t) == sizeof(double), "Cannot use this!");
    uint64_t const u = bs.to_ullong();
    double d;
    // Aliases to `char*` are explicitly allowed in the Standard (and only them)
    char const* cu = reinterpret_cast<char const*>(&u);
    char* cd = reinterpret_cast<char*>(&d);
    // Copy the bitwise representation from u to d
    memcpy(cd, cu, sizeof(u));
    return d;
}

to_ullong 仍然需要 C++11 .

大多数人都试图提供答案,让你把位向量当作直接包含编码的整数或双精度

我建议你完全避免这种做法。虽然它确实"工作"了,但它到处都是汉明悬崖。您通常希望编码排列内容,以便如果两个解码值彼此靠近,则它们的编码值也彼此靠近。它还强制您使用 64 位精度。

我会手动管理转换。假设您有三个变量要编码,x、y 和 z。例如,您的领域专业知识可用于表示 -5 <= x <5、0 <= y <100 和 0 <= z <1,其中 x 需要 8 位精度,y 需要 12 位精度,z 需要 10 位精度。这为您提供的总搜索空间仅为 30 位。您可以使用一个 30 位字符串,将前 8 个视为编码 x,将下一个 12 视为 y,将后 10 个视为 z。您还可以自由地对每个进行灰色编码以消除汉明悬崖。

我个人过去做过以下工作:

inline void binary_encoding::encode(const vector<double>& params)
{
    unsigned int start=0;
    for(unsigned int param=0; param<params.size(); ++param) {
        // m_bpp[i] = number of bits in encoding of parameter i
        unsigned int num_bits = m_bpp[param];
        // map the double onto the appropriate integer range
        // m_range[i] is a pair of (min, max) values for ith parameter
        pair<double,double> prange=m_range[param];
        double range=prange.second-prange.first;
        double max_bit_val=pow(2.0,static_cast<double>(num_bits))-1;
        int int_val=static_cast<int>((params[param]-prange.first)*max_bit_val/range+0.5);
        // convert the integer to binary
        vector<int> result(m_bpp[param]);
        for(unsigned int b=0; b<num_bits; ++b) {
            result[b]=int_val%2;
            int_val/=2;
        }
        if(m_gray) {
            for(unsigned int b=0; b<num_bits-1; ++b) {
                result[b]=!(result[b]==result[b+1]);
            }
        }
        // insert the bits into the correct spot in the encoding
        copy(result.begin(),result.end(),m_genotype.begin()+start);
        start+=num_bits;
    }
}
inline void binary_encoding::decode()
{
    unsigned int start = 0;
    // for each parameter
    for(unsigned int param=0; param<m_bpp.size(); param++) {
        unsigned int num_bits = m_bpp[param];
        unsigned int intval = 0;
        if(m_gray) {
            // convert from gray to binary
            vector<int> binary(num_bits);
            binary[num_bits-1] = m_genotype[start+num_bits-1];
            intval = binary[num_bits-1];
            for(int i=num_bits-2; i>=0; i--) {
                binary[i] = !(binary[i+1] == m_genotype[start+i]);
                intval += intval + binary[i];
            }
        }
        else {
            // convert from binary encoding to integer
            for(int i=num_bits-1; i>=0; i--) {
                intval += intval + m_genotype[start+i];
            }
        }
        // convert from integer to double in the appropriate range
        pair<double,double> prange = m_range[param];
        double range = prange.second - prange.first;
        double m = range / (pow(2.0,double(num_bits)) - 1.0);
        // m_phenotype is a vector<double> containing all the decoded parameters
        m_phenotype[param] = m * double(intval) + prange.first;
        start += num_bits;
    }
}

请注意,出于对你来说可能无关紧要的原因,我没有使用位向量 - 只是普通的编码vector<int>。当然,有一堆东西绑定到这个代码中,这里没有显示,但你可能得到基本的想法。

另外一点需要注意的是,如果您正在进行GPU计算,或者如果您遇到特定问题,例如64位无论如何都是合适的大小,那么将所有内容填充到本机单词中可能值得额外的开销。否则,我猜你给搜索过程增加的开销可能会压倒你通过更快的编码和解码获得的任何好处。

编辑:: 我已经决定我对此有点愚蠢。虽然你最终得到一个双精度,但它假设位集包含一个整数......这是一个很大的假设。你最终会得到每个位集一个可预测和可重复的值,但我仍然不认为这是作者的意图。

好吧,如果您遍历位值并执行

output_double += pow( 2, 64-(bit_position+1) ) * bit_value;

那会起作用。只要是大端序