c++ 可变位浮点数的乘除法

wfsdck30  于 2023-05-02  发布在  其他
关注(0)|答案(1)|浏览(123)

bounty还有3天到期。此问题的答案有资格获得+200声望奖励。ZeunO8正在寻找一个答案从一个有信誉的来源

我正在开发一个BigNumber库,它允许创建大数字(整数和浮点数)。您可以找到公共存储库here
我已经实现了BigFloatingBigInteger的加法和减法,但是乘法和除法只用于BigInteger
浮点数的位存储在std::vector中,格式为:
sign (1 bit)|binary integer(variable bits)|binary fraction(variable bits)
使得数字5.5将具有位0 101 1
这种格式的数字乘除有哪些算法?

(5.5)   101 1
* (5.5) 101 1
-------------
= (30.25) 11110 01

(5.5)   101 1
/ (5.5) 101 1
-------------
= (1)     1

要实现的功能可以在BigCommon.cpp中找到,它们是:
std::tuple<std::vector<bool>, size_t, size_t> BigCommon::multiplyBits(const std::vector<bool> &lhsBits, const std::vector<bool> &rhsBits, const size_t &integerBitsSize, const size_t &mantissaBitsSize)

std::tuple<std::vector<bool>, size_t, size_t> BigCommon::divideBits(const std::vector<bool> &lhsBits, const std::vector<bool> &rhsBits, const size_t &integerBitsSize, const size_t &mantissaBitsSize)

更新

我已经实现了multiplyBits算法如下:

std::tuple<std::vector<bool>, size_t, size_t> BigCommon::multiplyBits(const std::vector<bool> &lhsBits, const std::vector<bool> &rhsBits, const size_t &integerBitsSize, const size_t &mantissaBitsSize)
{
 std::vector<bool> result;
 result.insert(result.begin(), lhsBits[0] ^ rhsBits[0]);
 size_t newIntegerBitsSize = 0;
 size_t newMantissaBitsSize = mantissaBitsSize + mantissaBitsSize;
 std::vector<bool> lhsBinary(lhsBits.begin() + 1, lhsBits.end());
 std::vector<bool> rhsBinary(rhsBits.begin() + 1, rhsBits.end());
 std::vector<bool> multResult = multiplyBinaryVectors(lhsBinary, rhsBinary);
 newIntegerBitsSize = multResult.size() - newMantissaBitsSize;
 result.insert(result.begin() + 1, multResult.begin(), multResult.end());
 return {result, newIntegerBitsSize, newMantissaBitsSize};
};

现在只是为了分裂!

更新2

我已经使用以下算法成功地实现了除法:

std::tuple<std::vector<bool>, size_t, size_t> BigCommon::divideBits(const std::vector<bool> &lhsBits, const std::vector<bool> &rhsBits, const size_t &integerBitsSize, const size_t &mantissaBitsSize)
{
 if (lhsBits.size() != integerBitsSize + mantissaBitsSize + 1 || rhsBits.size() != integerBitsSize + mantissaBitsSize + 1)
 {
  throw std::invalid_argument("Invalid input sizes");
 }
 bool lhs_sign = lhsBits[0];
 bool rhs_sign = rhsBits[0];
 std::vector<bool> lhs_combined(lhsBits.begin() + 1, lhsBits.end());
 std::vector<bool> rhs_combined(rhsBits.begin() + 1, rhsBits.end());
 // Shift the dividend left by mantissa size
 std::vector<bool> lhs_shifted(lhs_combined);
 lhs_shifted.insert(lhs_shifted.end(), mantissaBitsSize, false);
 // Perform binary long division
 std::vector<bool> quotient = divideBinaryVectors(lhs_shifted, rhs_combined);
 // Determine the binary point position in the quotient
 int binary_point_pos = integerBitsSize + mantissaBitsSize;
 // Include the sign bit in the result
 const bool sign = lhs_sign ^ rhs_sign;
 std::vector<bool> result_bits = {sign};
 result_bits.insert(result_bits.end(), quotient.begin(), quotient.end());
 return std::make_tuple(result_bits, binary_point_pos, mantissaBitsSize);
};

更新3

经过一些测试,我发现除法算法不适用于某些类型的数字,这里有一些测试用例:5 / 0.2710 / 100。我还需要一些组织的指导

k10s72fa

k10s72fa1#

你所描述的是一个二进制 * 固定 * 点表示,在固定二进制点(整数和小数位之间的分割)的上方和下方都具有可变(无界)大小。
对于这种表示,乘法非常简单--只需将每个数字的整数位和小数位连接起来,相乘,然后再次拆分为整数/小数。如果输入的数字分别有 jk 小数位,则结果将有 j+k 小数位。
除法比较难,因为当结果不能用二进制精确表示时,你需要决定继续除法多远(多少额外的小数位)来计算。从根本上说,它只是长除法--连接整数/分数位,除法(一个可能不会终止的过程),然后分割结果。例如,10/5。5给你

1.11010 00101 11010 ....
       /----------------------
101.1 / 1010.00000 00000 00000
         101 1
         100 10000 00000 00000
          10 11
           1 11000 00000 00000
           1 011
              1100 00000 00000
              1011
                 1 00000 00000
                   1011
                    1010 00000
                     101 1
                     100 10000
                      10 11
                       1 11000
                       1 011
                          1100
                          1011
                             1

在结果中具有重复的10位值。你需要决定什么时候要截断它并对分数进行四舍五入。

相关问题