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)); }
//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; }