任意精度无符号整数,仅支持后增量运算符

时间:2013-12-21 13:12:02

标签: c++ arbitrary-precision

我正在寻找一个非常简单的C ++类,它实现了一个具有任意精度的无符号整数,只有后增量运算符。

我知道有任意精度整数运算的库,但我的需求非常简单,我更喜欢避免完整库的重量。

在我看来,我目前的实现仍然不够简单,也不够优雅。你有什么建议?

#include <vector>
#include <string>
#include <algorithm>

class UNat
{
public:
    static const char base = 10;
    UNat( const char* n )
    {
        std::string s(n);
        std::reverse(s.begin(),s.end());
        for ( size_t i = 0; i < s.length(); i++ ) {
            n_.push_back(s[i]-'0');
        }
    }

    UNat& operator++(int) 
    {
        bool carry = false;
        bool finished = false;

        for ( size_t i = 0; i < n_.size() && !finished; i++ ) {
            n_[i] = add(n_[i],1,carry);
            if ( carry ) {
                finished = false;
            } else {
                finished = true;
            }
        }
        if ( carry ) {
            n_.push_back(1);
        }
        return *this;
    }

    std::string to_string() const
    {
        std::string r(n_.begin(), n_.end());
        std::reverse(r.begin(),r.end());
        std::for_each(r.begin(), r.end(), [](char& d) { d+='0';});
        return r;
    }

private:
    char add( const char& a, const char& b, bool& carry )
    {
        char cc = a + b;
        if ( cc >= base ) {
            carry = true;
            cc -= base;
        } else {
            carry = false;
        }
        return cc;
    }
    std::vector< char > n_;    
};

std::ostream& operator<<(std::ostream& oss, const UNat& n)
{
    oss << n.to_string();
    return oss;
}

#include <iostream>

int main()
{
    UNat n("0");
    std::cout << n++ << "\n";
    std::cout << UNat("9")++ << "\n";
    std::cout << UNat("99")++ << "\n";
    std::cout << UNat("19")++ << "\n";
    std::cout << UNat("29")++ << "\n";
    std::cout << UNat("39")++ << "\n";
    return 0;
}

2 个答案:

答案 0 :(得分:1)

为了避免返回变异值,请保存本地副本并将其返回:

UNat operator++(int) 
{
    UNat copy = *this;
    // ....
    return copy;
} // don't return by reference

相比之下,前缀运算符 通过引用返回。

UNat& operator++ ()
{
  // ....
  return *this;
}

来自Arbitrary-precision arithmetic Explanation的一些提示和技巧:

  

1 /添加或乘以数字时,预先分配最大空间   如果你发现它太多,那么需要在之后减少。例如,   添加两个100-“数字”(其中数字是int)数字永远不会给   你超过101位数。将12位数字乘以3位数   数字永远不会超过15位数(添加数字计数)。

添加功能的替代实现可能如下所示:

c->lastdigit = std::max(a->lastdigit, b->lastdigit)+1;
carry = 0;

for (i=0; i<=(c->lastdigit); i++) {
    c->digits[i] = (char) (carry+a->digits[i]+b->digits[i]) % 10;
    carry = (carry + a->digits[i] + b->digits[i]) / 10;
}

答案 1 :(得分:1)

代码实现了通常所说的二进制编码十进制(BCD)。非常简单,而且,正如您所说,如果您只想增加并且不需要一般添加,则实现可以更简单。为了进一步简化,请使用数字'0''9'的内部字符表示,而不是值09。另外,为了简化,请将字符存储在std::string

for (int index = 0; index < digits.size(); ++index) {
    if (digits[index] != '9') {
        ++digits[index];
        break;
    }
    digits[index] = '0';
}
if (index == digits.size())
    digits.push_back('1');

这使得流插入器几乎无足轻重。