big_int ackermann(unsigned m, unsigned n) {
  static big_int (*ack)(unsigned, big_int) =
      [](unsigned m, big_int n)->big_int {
    switch (m) {
    case 0:
      return n + 1;
    case 1:
      return n + 2;
    case 2:
      return 3 + 2 * n;
    case 3:
      return 5 + 8 * (ipow(big_int(2), n) - 1);
    default:
      return n == 0 ? ack(m - 1, big_int(1)) : ack(m - 1, ack(m, n - 1));
    }
  };
  return ack(m, big_int(n));
}
Ejemplo n.º 2
0
//TODO move extra operations, eg: add leading zeros, extra copy constructors
big_int big_int::operator*(const big_int&rhs){
    if(*this == 0|| rhs == 0){
        return big_int(0);
    }
    auto max_len = std::max(val_.size(), rhs.val_.size());
    if(max_len == 1){
        return big_int(static_cast<unsigned>(val_[0]) * static_cast<unsigned>(rhs.val_[0]));
    }

    auto val = val_, rhs_val = rhs.val_;
    val.insert(val.end(), max_len - val.size(), 0);
    rhs_val.insert(rhs_val.end(), max_len - rhs_val.size(), 0);
    auto mid = max_len >> 1;
    big_int x[2], y[2];
    x[0].val_.insert(x[0].val_.end(), val.begin(), val.begin()+mid);
    x[1].val_.insert(x[1].val_.end(), val.begin()+mid, val.end());
    y[0].val_.insert(y[0].val_.end(), rhs_val.begin(), rhs_val.begin()+mid);
    y[1].val_.insert(y[1].val_.end(), rhs_val.begin()+mid, rhs_val.end());
    x[0].positive_ = x[1].positive_ = y[0].positive_ = y[1].positive_ = 1;
    big_int z2 = x[1]*y[1];
    big_int z1 = x[1]*y[0] + x[0]*y[1];
    big_int ans = big_int(x[0]*y[0]);

    if(ans.val_.size() < mid){
        ans.val_.insert(ans.val_.end(), mid-ans.val_.size(), 0);
    }

    std::vector<int>::size_type pos_ans, pos_z;
    int carry = 0;
    for(pos_ans = mid, pos_z = 0; pos_ans < ans.val_.size() && pos_z < z1.val_.size(); ++pos_ans,++pos_z){
        auto tmp = ans.val_[pos_ans] + z1.val_[pos_z] + carry;
        ans.val_[pos_ans] = tmp & lowbits_;
        if(tmp > lowbits_){
            carry = 1;
        }else{
            carry = 0;
        }
    }
    if(pos_ans < ans.val_.size()){
        for(;pos_ans < ans.val_.size(); ++pos_ans){
            auto tmp = ans.val_[pos_ans] + carry;
            ans.val_[pos_ans] = tmp & lowbits_;
            if(tmp > lowbits_){
                carry = 1;
            }else{
                carry = 0;
            }
        }
    }else if(pos_z < z1.val_.size()){
        for(;pos_z < z1.val_.size(); ++pos_z){
            auto tmp = z1.val_[pos_z] + carry;
            ans.val_.push_back(tmp & lowbits_);
            if(tmp > lowbits_){
                carry = 1;
            }else{
                carry = 0;
            }
        }
    }
    if(carry){
        ans.val_.push_back(carry);
    }


    //ans.val_.insert(ans.val_.end(), z1.val_.begin(), z1.val_.end());

    if(ans.val_.size() < (mid<<1) ){
        ans.val_.insert(ans.val_.end(), (mid<<1)-ans.val_.size(), 0);
    }


    carry = 0;
    for(pos_ans = mid<<1, pos_z = 0; pos_ans < ans.val_.size() && pos_z < z2.val_.size(); ++pos_ans,++pos_z){
        auto tmp = ans.val_[pos_ans] + z2.val_[pos_z] + carry;
        ans.val_[pos_ans] = tmp & lowbits_;
        if(tmp > lowbits_){
            carry = 1;
        }else{
            carry = 0;
        }
    }
    if(pos_ans < ans.val_.size()){
        for(;pos_ans < ans.val_.size(); ++pos_ans){
            auto tmp = ans.val_[pos_ans] + carry;
            ans.val_[pos_ans] = tmp & lowbits_;
            if(tmp > lowbits_){
                carry = 1;
            }else{
                carry = 0;
            }
        }
    }else if(pos_z < z2.val_.size()){
        for(;pos_z < z2.val_.size(); ++pos_z){
            auto tmp = z2.val_[pos_z] + carry;
            ans.val_.push_back(tmp & lowbits_);
            if(tmp > lowbits_){
                carry = 1;
            }else{
                carry = 0;
            }
        }
    }
    if(carry){
        ans.val_.push_back(carry);
    }



    //ans.val_.insert(ans.val_.end(), z2.val_.begin(), z2.val_.end());
    ans.positive_ = positive_ * rhs.positive_;
    ans.fix_pre_zeros_();
    return ans;
}