codevs 3119 高精度练习之大整数开根
2015-01-04 11:17
381 查看
利用牛顿迭代法,来算。但是需要大数运算支持。此外牛顿迭代法中初值选取时,精确求出前5位。求前5位通过手算平方根的办法来求。用int类型即可。
手算平方根 参考 http://wenku.baidu.com/link?url=5fD_xTiIXbtRXatkSV2xAj2Y4lOCbg7Mkx0EArO8Nq3jKyR8vly-y6FPGhaxnMBgFX-1BxHynACp0bcfls7xiLW2hwFnDDJumFz_KHqyMjG
手算平方根 参考 http://wenku.baidu.com/link?url=5fD_xTiIXbtRXatkSV2xAj2Y4lOCbg7Mkx0EArO8Nq3jKyR8vly-y6FPGhaxnMBgFX-1BxHynACp0bcfls7xiLW2hwFnDDJumFz_KHqyMjG
#include <iostream> #include <vector> #include <algorithm> #include <cstdio> #include <string> #include <cmath> using namespace std; class BigInt{ friend istream& operator>>(istream &is,BigInt &bi); friend ostream& operator<<(ostream &is,const BigInt &bi); private: vector<int> num; // 存放数字 char sig; public: BigInt(){ sig = '+'; } BigInt operator-(BigInt& other); BigInt operator/(BigInt& other); // 大数除法,仅求出算整数部分 BigInt operator+(BigInt& other); // 大数加,为大数乘法提供帮助 BigInt operator*(BigInt& other); // 大数乘,为大数乘法提供帮助 BigInt biSqrt(); // 大整数开平方仅求出整数部分 // 二分法求开方 void divide(BigInt& other,BigInt& result); unsigned locate(unsigned); bool less(const BigInt& other); // A 是否小于 B bool gt(const BigInt& other); void delTailZero(); void delHeadZero(); BigInt newtonSqrt(); // 牛顿迭代求开方 void setSig(char s){ sig = s; } char getSig() const{ return sig; } }; bool BigInt::less(const BigInt& other){ if(num.size() != other.num.size()){ return num.size() < other.num.size(); } else{ for(unsigned i = 0; i < num.size(); i++){ if(num[i] < other.num[i]) return true; else if(num[i] > other.num[i]) return false; } return false; } } bool BigInt::gt(const BigInt& other){ // 传去比较函数,然后在传入比较器。 if(num.size() != other.num.size()){ return num.size() > other.num.size(); } else{ for(unsigned i = 0; i < num.size(); i++){ if(num[i] > other.num[i]) return true; else if(num[i] < other.num[i]) return false; } return false; } } unsigned BigInt::locate(unsigned pos){ // 下标转换 o(1) return pos >= num.size() ? 0 : num[num.size() - pos - 1]; } void BigInt::delTailZero(){ while (0 == num.back() && num.size() > 1) { num.pop_back(); } } void BigInt::delHeadZero(){ // 删除头0 reverse(num.begin(),num.end());// n/2 while (num.size() > 1 && 0 == num.back()) { num.pop_back(); } reverse(num.begin(),num.end()); // n/2 } BigInt BigInt::operator+(BigInt& other){ unsigned carry = 0, larger_size, partial_sum; BigInt sum; if (num.size() > other.num.size()) larger_size = num.size(); else larger_size = other.num.size(); for (unsigned i = 0; i < larger_size; i++) { partial_sum = locate (i) + other.locate(i) + carry; carry = partial_sum / 10; sum.num.push_back (partial_sum % 10); } if (carry == 1) sum.num.push_back (carry); reverse (sum.num.begin(), sum.num.end()); return sum; } BigInt BigInt::operator-(BigInt& other) { BigInt result, *bigger = this, *little = &other; unsigned borrow = 0; if((*this).less(other)){ bigger = &other; little = this; result.setSig('-'); } unsigned bi = 0, li = 0; for(unsigned i = 0; i < (*bigger).num.size(); i++){ bi = (*bigger).locate(i); li = (*little).locate(i); if(bi < li + borrow){ result.num.push_back(bi+10 - li - borrow); borrow = 1; }else{ result.num.push_back(bi - li - borrow); borrow = 0; } } result.delTailZero(); reverse(result.num.begin(),result.num.end()); return result; } BigInt BigInt::operator*(BigInt& other){ BigInt interResult, result; // 12938 A unsigned carry = 0; //* 123 B for (unsigned i = 0 ; i < other.num.size(); i++) // B { carry = 0; unsigned tmpi = i; interResult.num.clear(); // 计算前,将中间结果清除。 while (tmpi > 0) { interResult.num.push_back(0); tmpi--; } for (unsigned j = 0; j < num.size(); j++) // A { unsigned product = other.locate(i) * locate(j) + carry; carry = product / 10; interResult.num.push_back(product%10); // 保存临时结果 } if (carry > 0) { interResult.num.push_back(carry); } reverse(interResult.num.begin(),interResult.num.end()); result = interResult + result; } return result; } BigInt BigInt::operator/(BigInt& other){ // 仅仅保留整数部分 A > B , A == B A < B 。 所以有这三种情况。 A >= B 进行除法运算。 BigInt result; // 截取一段去除 other BigInt tmp; unsigned index = 0; unsigned quotient = 0; // 商 bool contact = false; if((*this).less(other)){ result.num.push_back(0); }else{ // 进行除法运算 index = other.num.size(); // 构造一个长度为 len的临时对象 tmp.num.assign(num.begin(),num.begin()+index); if (index == num.size()) // 小于,大于,== 三个操作 { while(!tmp.less(other)){ quotient++; tmp = tmp - other; // = 9 } result.num.push_back(quotient); } else { while(index < num.size()){ quotient = 0; while(tmp.less(other)){ // 首先除数肯定比被除数大,若小整数部分肯定为了,所以追加数字,住 if(index < num.size()){ if(contact == true) // 当一次拼接完成后,才判断是商0,还是商1. result.num.push_back(0); // 小于某数补0; tmp.num.push_back(num.at(index)); contact = true; } else{ break; } index += 1; } contact = false; tmp.delHeadZero(); while(!tmp.less(other)){ quotient++; tmp = tmp - other; // = 9 } tmp.delHeadZero(); if(index <= num.size()) // 这里是 <= 而上面是小于 因为上面完成了index += 1 操作,所以这里少1。 result.num.push_back(quotient); } } } return result; } istream& operator>>(istream &is,BigInt &bi) { const char lOWBOUND = '0'; string num; is >> num; for(size_t i = 0; i < num.size(); i++) bi.num.push_back(num[i] - lOWBOUND); return is; } ostream& operator<<(ostream &os,const BigInt &bi) { if(bi.getSig() == '-'){ os <<"-"; } for(size_t i = 0; i < bi.num.size(); i++){ //os << bi.num[i]; printf("%d",bi.num[i]); } return os; } BigInt BigInt::newtonSqrt() // 牛顿迭代法求 平方根,仅算整数部分 { BigInt result, biTwo, // 2的大数表示 , lastResult; biTwo.num.push_back(2); unsigned resultLen = (unsigned)((this->num.size())/2.0 + 0.5); // 开方后数字位数 // 通过手算开放的办法先计算出结果的前5位 int result1 = 0; // 存放计算的中间及结果 int i1 = 0, n1 = 0, // 截取的两位数和后面两位 n2 = 0; // 待减的两位数字 if(this->num.size()>100) // 大于100位数,预处理。精确算出前5位。 { if (this->num.size()%2) // 共偶数位,先取一位算 { i1 = 1; // 下一次计算从第i位开始 int s = (int)(sqrt(this->num[0]*1.0)); result1 = result1*10 + s; lastResult.num.push_back(s); n1 = this->num[0] - s*s; } else { i1 = 2; int sum = this->num[0]*10+this->num[1]; int s = (int)(sqrt(sum*1.0)); lastResult.num.push_back(s); n1 = sum - s*s; } for ( ; i1< 8; i1 += 2) // 只预处理前8位 { n1 = n1*10 + this->num[i1]; n1 = n1*10 + this->num[i1+1]; n2 = result1*20; if (n1 < n2 ) { lastResult.num.push_back(0); result1 = result1 * 10; // 不够的话商0(左移一位) continue; } int j = 1; for (; j <= 9; j++) { if ((n2+1)*j > n1) { break; } else { n2++; } } lastResult.num.push_back(n2%10); result1 = result1*10 + n2%10; n1 = n1 - n2*(j-1); } } for (unsigned i = (i1/2.0 + 0.5); i < resultLen; i++) // 构建初始值,前5位由手算除法 { lastResult.num.push_back(9); } while (true) // 牛顿迭代求 结果 { BigInt tmp = (*this)/lastResult; result = (lastResult + tmp)/biTwo; if(result.less(lastResult)) { lastResult = result; } else { break; } } return lastResult; } int main(int argc, char** argv) { BigInt A; cin >> A; cout << (A.newtonSqrt())<< endl; return 0; }
相关文章推荐
- CODEVS 3123 高精度练习之超大整数乘法
- Code[VS] 3123 高精度练习之超大整数乘法
- codevs 3123 高精度练习之超大整数乘法
- codevs 3116 高精度练习之加法
- codeVS 3115 高精度练习之减法
- codevs 3119 高精度练习之大整数开根 (各种高精+压位)
- CODE【VS】3118 高精度练习之除法(大数除以大数模板)
- code[vs] 3115 高精度练习之减法
- code[vs] 3116 高精度练习之加法
- CODEVS 3115高精度练习之减法
- code[vs] 3117 高精度练习之乘法
- Codevs 3115 高精度练习之减法
- codevs3115 高精度练习之加法
- codevs 3116 高精度练习之加法
- [codevs1569]最佳绿草 dfs练习
- 【基础练习】【堆】codevs1063 合并果子题解
- 【codevs 1080】线段树练习
- 【CodeVS 3123】高精度练习之超大整数乘法 &【BZOJ 2197】FFT快速傅立叶
- codevs 1080 线段树练习
- 【基础练习】【二分】codevs2072 分配房间题解