将向量<bool>转换为十进制(作为字符串)

convert vector<bool> to decimal (as string)

本文关键字:十进制 字符串 gt 向量 lt bool 转换      更新时间:2023-10-16

使用这个函数可以很容易地将vector转换为十进制(整数):

vector<bool> A = {0, 1, 1, 1,0,1}; # A size will change during run time
long int integer = 0, n = 0;
    for (auto i : A)
    {
        if (i)
        {
            integer += pow(2, n);
        }
        n = n + 1;
    }

但是如果vector的元素数超过64个,则结果将不可预测。

我们如何写类似的函数,但返回字符串代替?

正如其他人所建议的,对于表示任何固定长度的二进制数(对于动态长度,如您的情况,请参阅boost::dynamic_bitset),使用std::bitset是更好的选择。这个链接解释了为什么不使用std::vector<bool>的一些原因。

你的问题基本上可以归结为实现一个BigNum类。就像您在方法中所做的一样,首先需要将值从二进制转换为十进制(但现在需要64位以上的精度)。一旦构造了BigNum,将其转换为字符串就很简单了。我通过简单地修改前一段时间制作的BigNum类来实现您要求的算法。

要打印二进制数,以下几行应该足够了。

/*Creates a 90-digit binary number with all bits set.*/
std::vector<bool> A(90, 1);
/*Prints its decimal reprsentation*/
cout << longBinaryToDecimalAsString(A);

至于实现:

#ifndef BIG_NUM_H
#define BIG_NUM_H
#include <string>
#include <vector>
#include <sstream>
#include <cstdint>
class BigNum {
public:
    BigNum(){values.push_back(0);}
    BigNum(std::uint64_t val){
        if (val == 0)
            values.assign(1, 0);
        else{
            while (val > 0){
                values.push_back(val % 10);
                val /= 10;
            }
        }
    }
    BigNum &operator+=(BigNum &rhs)
    {
        std::vector<std::uint8_t> *lowAddend, *bigAddend;
        /*If right value is larger, ‘values’ vector will always grow*/
        if (rhs.values.size() > values.size()){
            values.resize(rhs.values.size(), 0);
            lowAddend = &values;
            bigAddend = &rhs.values;
        }
        else{
            values.push_back(0);
            bigAddend = &values;
            lowAddend = &rhs.values;
        }
        std::uint8_t carry = 0;
        size_t i = 0;
        /*First we sum lower part*/
        for (; i < lowAddend->size(); ++i){
            std::uint8_t sum = values[i] + rhs.values[i] + carry;
            values[i] = sum % 10;
            carry = sum / 10;
        }
        /*Now we copy the remaining part*/
        for (; i < bigAddend->size(); ++i){
            /*For 10 10, sum will be 18, at most*/
            std::uint8_t sum = (*bigAddend)[i] + carry;
            values[i] = sum % 10;
            carry = sum / 10;
        }
        this->trimFrontalZeros();
        return *this;
    }
    BigNum &operator*=(BigNum &rhs)
    {
        /*Case when one of the operands is Zero*/
        if (this->isZero())
            return *this;
        else if (rhs.isZero()){
            values.assign(1, 0);    
            return *this;
        }
        size_t maxLen = values.size() + rhs.values.size();
        std::vector<std::uint8_t> product(maxLen);
        size_t lowSize, bigSize;
        std::vector<std::uint8_t> *multiplier, *multiplicand;
        /*The iteration process for the multiplicaiton is developed as the multiplier (A in A*B)
        as the one with more digits.*/
        if (values.size() > rhs.values.size()){
            multiplier = &values;
            multiplicand = &rhs.values;
            bigSize = values.size();
            lowSize = rhs.values.size();
        }
        else{
            multiplier = &rhs.values;
            multiplicand = &values;
            bigSize = rhs.values.size();
            lowSize = values.size();
        }
        /*Implemented as 'values x rhs.values' */
        std::uint8_t carry = 0;
        for (size_t n = 0; n < maxLen; ++n){
            size_t numIters;
            if (maxLen - n - 1< lowSize) numIters = maxLen - n - 1;
            else                         numIters = std::min(n + 1, lowSize);
            std::uint64_t sum = 0;
            for (size_t i = 0; i < numIters; ++i){
                size_t indBelow = i + n + 1 - std::min(n + 1, lowSize);
                size_t indAbove = std::min(n + 1, lowSize) - 1 - i;
                std::uint8_t be = (*multiplier)[indBelow];
                std::uint8_t ab = (*multiplicand)[indAbove];
                sum += be*ab;
            }
            sum += carry;
            product[n] = sum % 10;
            carry = sum / 10;
        }
        values.assign(product.begin(), product.end());
        this->trimFrontalZeros();
        return *this;
    }
    std::string toString(){
        std::stringstream ss;
        std::copy(values.rbegin(), values.rend(), std::ostream_iterator<int>(ss, ""));
        return ss.str();
    }
private:
    bool isAbsOne() {return values.size() == 1 && values[0] == 1;}
    bool isZero()   {return values.size() == 1 && values[0] == 0;}
    void trimFrontalZeros(){
        size_t newSize = values.size();
        auto it = values.rbegin();
        while (it != values.rend() && *it == 0){
            ++it;
            --newSize;
        }
        values.resize(newSize);
    }
    std::vector<std::uint8_t> values;
};
std::string longBinaryToDecimalAsString(std::vector<bool> &longBinary){
    BigNum big;
    std::uint64_t n = 0;
    for (bool bit : longBinary){
        if (bit){
            if (n > 63){
                BigNum aux(1);          
                for (std::uint64_t i = 0; i < n / 32; ++i){
                    aux *= BigNum(1ULL << 32);
                }
                aux *= BigNum(1ULL << (n % 32));
                big += aux;
            }
            else{
                big += BigNum(1ULL << n);
            }
        }
        ++n;
    }
    return big.toString();
}
#endif

请注意这是BigNum类的一个非常简化的版本。将其用于本问题之外的其他目的可能会输出不希望的结果。例如,它不考虑+*操作的负数