您的位置:首页 > 其它

codevs 3119 高精度练习之大整数开根

2015-01-04 11:17 381 查看
利用牛顿迭代法,来算。但是需要大数运算支持。此外牛顿迭代法中初值选取时,精确求出前5位。求前5位通过手算平方根的办法来求。用int类型即可。

手算平方根 参考 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: