#include "bigdecimal.h"
#include<QDebug>
BigDecimal::BigDecimal()
{
}
BigDecimal::BigDecimal(QString decimal)
{
this->decimal=decimal;
}
QString BigDecimal::add(QString a, QString b)
{
//如果小数点在开头
if(a.startsWith("."))a="0"+a;
if(b.startsWith("."))b="0"+b;
if(a.startsWith("-."))a=a.replace(QRegExp("^-\\."),"-0.");
if(b.startsWith("-."))b=b.replace(QRegExp("^-\\."),"-0.");
if(!isNum(a)||!isNum(b))return "NaN";
//如果小数点在结尾
a=a.replace(QRegExp("[.]$"),"");
b=b.replace(QRegExp("[.]$"),"");
//判断a,b是否为负数
bool aIsFushu=a.startsWith("-");
bool bIsFushu=b.startsWith("-");
//去掉负号
if(aIsFushu)a=a.mid(1);
if(bIsFushu)b=b.mid(1);
if(!aIsFushu&&bIsFushu){//a正b负
return subtract(a,b);
}else if(aIsFushu&&!bIsFushu){//a负b正
return subtract(b,a);
}else if(aIsFushu&&bIsFushu){//a负b负
return "-"+add(a,b);
}
//a正b正
//a小数长度
int dotA=a.contains(".")?a.length()-1-a.lastIndexOf("."):0;
//b小数长度
int dotB=b.contains(".")?b.length()-1-b.lastIndexOf("."):0;
//最终小数位
int dot=dotA>=dotB?dotA:dotB;
//去小点变整数
int posA=a.lastIndexOf("."),posB=b.lastIndexOf(".");
if(posA>0)a=a.remove(posA,1);
if(posB>0)b=b.remove(posB,1);
//结尾补0使小数位对齐
QString endZeroA,endZeroB;
endZeroA=endZeroA.fill('0',dot-dotA);
endZeroB=endZeroB.fill('0',dot-dotB);
a=a+endZeroA;
b=b+endZeroB;
//前补0使字符串等长
int lenA=a.length();//防止输入00000这类的串导致的位数错误
int lenB=b.length();
int len=lenA>=lenB?lenA:lenB;
QString preZeroA,preZeroB;
preZeroA=preZeroA.fill('0',len-lenA);
preZeroB=preZeroB.fill('0',len-lenB);
a=preZeroA+a;
b=preZeroB+b;
QString result="";
int jing=0;
for (int i =len-1; i>=0; i--) {
bool ok1,ok2;
int aa=a.mid(i,1).toInt(&ok1,10);//转换失败返回0
int bb=b.mid(i,1).toInt(&ok2,10);
if(!(ok1&&ok2))return "NaN";
int res=aa+bb+jing;//对位相加的结果
int remain=res>=10?res-10:res;
if(i==0)remain=res;
jing=res>=10?1:0;
result=QString("%1").arg(remain)+result;
}
if(dot!=0){
result=result.insert(result.length()-dot,".");
}
//去掉前置的0
QRegExp reg("^0+");
result=result.replace(reg,"");
if(result.isEmpty())result="0";
if(result.startsWith("."))result="0"+result;//纠正.25类型的偏差
return result;
}
QString BigDecimal::subtract(QString a, QString b)
{
//如果小数点在开头
if(a.startsWith("."))a="0"+a;
if(b.startsWith("."))b="0"+b;
if(a.startsWith("-."))a=a.replace(QRegExp("^-\\."),"-0.");
if(b.startsWith("-."))b=b.replace(QRegExp("^-\\."),"-0.");
if(!isNum(a)||!isNum(b))return "NaN";
//如果小数点在结尾
a=a.replace(QRegExp("[.]$"),"");
b=b.replace(QRegExp("[.]$"),"");
//判断a,b是否为负数
bool aIsFushu=a.startsWith("-");
bool bIsFushu=b.startsWith("-");
//去掉负号
if(aIsFushu)a=a.mid(1);
if(bIsFushu)b=b.mid(1);
if(!aIsFushu&&bIsFushu){//a正b负
return add(a,b);
}else if(aIsFushu&&!bIsFushu){//a负b正
return "-"+add(a,b);
}else if(aIsFushu&&bIsFushu){//a负b负
return subtract(b,a);
}
//a正b正
//a小数长度
int dotA=a.contains(".")?a.length()-1-a.lastIndexOf("."):0;
//b小数长度
int dotB=b.contains(".")?b.length()-1-b.lastIndexOf("."):0;
//最终小数位
int dot=dotA>=dotB?dotA:dotB;
//去小点变整数
int posA=a.lastIndexOf("."),posB=b.lastIndexOf(".");
if(posA>0)a=a.remove(posA,1);
if(posB>0)b=b.remove(posB,1);
//结尾补0使小数位对齐
QString endZeroA,endZeroB;
endZeroA=endZeroA.fill('0',dot-dotA);
endZeroB=endZeroB.fill('0',dot-dotB);
a=a+endZeroA;
b=b+endZeroB;
//前补0使字符串等长
//防止输入00000这类的串导致的位数错误
int lenA=a.length();
int lenB=b.length();
int len=lenA>=lenB?lenA:lenB;
QString preZeroA,preZeroB;
preZeroA=preZeroA.fill('0',len-lenA);
preZeroB=preZeroB.fill('0',len-lenB);
a=preZeroA+a;
b=preZeroB+b;
QString result="";
int jie=0;//借位
bool isFushu=false;//是否是负数
for (int i =len-1; i>=0; i--) {
bool ok1,ok2;
int aa=a.mid(i,1).toInt(&ok1,10);//转换失败返回0
int bb=b.mid(i,1).toInt(&ok2,10);
if(!(ok1&&ok2))return "NaN";
int res=aa-bb-jie;//对位相减的结果,jie之前被借回的数
int remain=res<0?res+10:res;
jie=res<0?1:0;
if(i==0&&jie==1)//最高位需借时,即为负数
{
isFushu=true;
result="";
jie=0;
break;
}
result=QString("%1").arg(remain)+result;
}
if(isFushu){
for (int i =len-1; i>=0; i--) {
bool ok1,ok2;
int aa=a.mid(i,1).toInt(&ok1,10);//转换失败返回0
int bb=b.mid(i,1).toInt(&ok2,10);
if(!(ok1&&ok2))return "NaN";
int res=bb-aa-jie;//对位相加的结果
int remain=res<0?res+10:res;
jie=res<0?1:0;
result=QString("%1").arg(remain)+result;
}
}
if(dot!=0){
result=result.insert(result.length()-dot,".");
}
//去掉前置的0
QRegExp reg("^0+");
result=result.replace(reg,"");
if(result.isEmpty())result="0";
if(result.startsWith("."))result="0"+result;
result=isFushu?"-"+result:result;//是负数加负号
return result;
}
QString BigDecimal::multiply(QString a, QString b)
{
//如果小数点在开头
if(a.startsWith("."))a="0"+a;
if(b.startsWith("."))b="0"+b;
if(a.startsWith("-."))a=a.replace(QRegExp("^-\\."),"-0.");
if(b.startsWith("-."))b=b.replace(QRegExp("^-\\."),"-0.");
if(!isNum(a)||!isNum(b))return "NaN";
//如果小数点在结尾
a=a.replace(QRegExp("[.]$"),"");
b=b.replace(QRegExp("[.]$"),"");
QString result="0";
//确定计算结果的正负
bool isFuA=a.startsWith("-");
bool isFuB=b.startsWith("-");
bool isFuRes=false;
if(!isFuA&&!isFuB)isFuRes=false;//a正b正
if(!isFuA&&isFuB)isFuRes=true;//a正b负
if(isFuA&&!isFuB)isFuRes=true;//a负b正
if(isFuA&&isFuB)isFuRes=false;//a负b负
//去掉负号
if(isFuA)a=a.mid(1);
if(isFuB)b=b.mid(1);
//确定结果的小数位数
int decLenA=a.contains(".")?a.length()-1-a.lastIndexOf("."):0;
int decLenB=b.contains(".")?b.length()-1-b.lastIndexOf("."):0;
int decLenRes=decLenA+decLenB;
//去掉小数点
int posA=a.lastIndexOf("."),posB=b.lastIndexOf(".");
if(posA>0)a=a.remove(posA,1);
if(posB>0)b=b.remove(posB,1);
//b的长度
int lenB=b.length();
for (int i =lenB-1; i>=0; i--) {
QString strB=b.mid(i,1);
QString res=moreXsingle(a,strB);
if(res=="NaN")return res;
//每次计算要补的0
QString zero=QString("0").repeated((lenB-1-i));
res=res+zero;
result=add(result,res);
}
//加小数点
if(decLenRes>0){
QString zero1="0";
//对于结果不足小数位时前补0
result=zero1.repeated(decLenRes-result.length()+1)+result;
result=result.insert(result.length()-decLenRes,".");
//两者取小数多者
int lenMax=decLenA>decLenB?decLenA:decLenB;
//截掉结尾的0数
int num1=decLenRes-lenMax;
result=result.replace(QRegExp(QString("0{%1}$").arg(num1)),"");//去掉结尾的0
}
if(result.endsWith("."))result=result.left(result.length()-1);
//加负号
if(isFuRes)result="-"+result;
return result;
}
QString BigDecimal::divide(QString a, QString b, int decimalLen)
{
//如果小数点在开头
if(a.startsWith("."))a="0"+a;
if(b.startsWith("."))b="0"+b;
if(a.startsWith("-."))a=a.replace(QRegExp("^-\\."),"-0.");
if(b.startsWith("-."))b=b.replace(QRegExp("^-\\."),"-0.");
if(!isNum(a)||!isNum(b))return "NaN";
//如果小数点在结尾
a=a.replace(QRegExp("[.]$"),"");
b=b.replace(QRegExp("[.]$"),"");
//判断b是否为0
QString tempb=b;
QString tmp=b.replace(QRegExp("^-"),"").replace(".","")
.replace(QRegExp("^0"),"");
if(tmp.isEmpty())return "NaN";
b=tempb;
QString result="0";
//确定计算结果的正负
bool isFuA=a.startsWith("-");
bool isFuB=b.startsWith("-");
bool isFuRes=false;
if(!isFuA&&!isFuB)isFuRes=false;//a正b正
if(!isFuA&&isFuB)isFuRes=true;//a正b负
if(isFuA&&!isFuB)isFuRes=true;//a负b正
if(isFuA&&isFuB)isFuRes=false;//a负b负
//去掉负号
a=a.replace(QRegExp("^-"),"");
b=b.replace(QRegExp("^-"),"");
//获取小数位数
int decLenA=a.contains(".")?a.length()-1-a.lastIndexOf("."):0;
int decLenB=b.contains(".")?b.length()-1-b.lastIndexOf("."):0;
int decMax=decLenA>=decLenB?decLenA:decLenB;//取小数位数大者
//分子分母同乘倍数,转换为整数
QString beishu="1"+QString("0").repeated(decMax);
a=multiply(a,beishu);
b=multiply(b,beishu);
//如果小数点后有虚0,则删除之,以便使用整数乘法
a=a.replace(QRegExp("\\.0+$"),"");
b=b.replace(QRegExp("\\.0+$"),"");
int lenA=a.length();
//初始化被除数
QString aa="";
QString cha="";
//是否整除
bool zhengChu=false;
for (int i =0; i < lenA+decimalLen+1; ++i) {
if(i<lenA)aa=cha+a.mid(i,1);
else aa=cha+"0";
//试商
zhengChu=false;//是否整除
for (int j = 9; j>=0; j--) {
QString res=QString("%1").arg(j);
QString ji=multiply(res,b);
cha=subtract(aa,ji);
if(cha.startsWith("-")){
cha="";
continue;
}else{//试商成功
if(i==lenA){
result+=".";
}
result+=res;
//当有小数时才去判断是否整除,不出小数只是补0,无需跳出
if(i>=lenA){
//差和余数中不全为0时即为整除,需跳出不再往下计算
if((cha+a.mid(i+1)).indexOf(QRegExp("[1-9]+"))==-1){
zhengChu=true;
break;
}else{
zhengChu=false;
}
}
break;
}
}
if(zhengChu)break;
}
result=result.replace(QRegExp("^0+"),"");
if(result.isEmpty())result="0";//纠正上一步全为0替换成""的偏差
if(result.startsWith("."))result="0"+result;//纠正.25之类的偏差
if(isFuRes)result="-"+result;
if(!zhengChu)//如果除不尽,则按定位四余五入
result=BigDecimal(result).round(decimalLen).toString();
else{//如果整除,删除小数点后末尾的0或.00等
result=result.replace(QRegExp(".0+$|0+$"),"");
}
return result;
}
BigDecimal BigDecimal::round(int len)
{
if(!isNum(decimal))return BigDecimal("NaN");
//数字的总长(含小数点)
int decLen=decimal.length();
//是否是小数
bool isDecimal=decimal.contains(".");
//是否是负数
bool isFu=decimal.startsWith("-");
//小数点的位置
int dotIndex=isDecimal?decimal.lastIndexOf("."):decLen-1;
//小数位长度
int dotLen=decLen-1-dotIndex;
//整数位长度
int intLen=isDecimal?dotIndex:decLen;
//---开始判断是否是数字---
QString newDecimal=decimal;
//去掉小数点
if(decimal.contains("."))newDecimal=newDecimal.remove(dotIndex,1);
//去掉负号
newDecimal=newDecimal.replace(QRegExp("^-"),"");
for (int i = 0; i < newDecimal.length(); ++i) {
bool ok;
newDecimal.mid(i,1).toInt(&ok,10);
if(!ok)return BigDecimal("0");
}
//---结束判断是否是数字---
QString result="";
QString zero="";
if(len<=0){
if(isFu)intLen=intLen-1;
newDecimal=newDecimal.mid(0,intLen);
if(intLen<-len)return BigDecimal("0");
int numAfterLen=newDecimal.mid(intLen+len,1).toInt();
if(numAfterLen>=5)
result=add(newDecimal.left(intLen+len)+QString("0").repeated(-len),"1"+QString("0").repeated(-len));
else result=newDecimal.left(intLen+len)+QString("0").repeated(-len);
result=result.replace(QRegExp("^0+"),"");
if(result.isEmpty())return BigDecimal("0");
if(isFu)result="-"+result;
}else{
if(!isDecimal){//如果是整数
zero=zero.fill('0',len);
result=decimal+"."+zero;
}else if(dotLen<=len){//如果小数位少于len
zero=zero.fill('0',len-dotLen);
result=decimal+zero;
}else{//如果小数位多于len
int numAfterLen=decimal.mid(dotIndex+len+1,1).toInt();
if(numAfterLen>=5){
result=isFu?add(decimal.mid(0,dotIndex+len+1),"-0."+QString("0").repeated(len-1)+"1"):
add(decimal.mid(0,dotIndex+len+1),"0."+QString("0").repeated(len-1)+"1");
}else{
result=decimal.mid(0,dotIndex+1+len);
}
}
}
return BigDecimal(result);
}
BigDecimal BigDecimal::ceiling(int len)
{
if(!isNum(decimal))return BigDecimal("NaN");
if(len<0)return decimal;
bool isFu=decimal.startsWith("-");
bool isDecimal=decimal.contains(".");
//转为正数
decimal=decimal.replace(QRegExp("^-"),"");
QString result="";
if(!isDecimal){
result=decimal;
}else{
//获取小数位数
int intLen=decimal.lastIndexOf(".");
int decLen=decimal.length()-1-intLen;
if(decLen<=len)result=decimal;//原数返回
else if(len>0&&!isFu)result= add(decimal.left(intLen+1+len),"0."+QString("0").repeated(len-1)+"1");
else if(len>0&&isFu)result= decimal.left(intLen+1+len);
else if(!isFu) result=add(decimal.left(intLen),"1");
else if(isFu) result=decimal.left(intLen);
}
if(isFu)result="-"+result;
return BigDecimal(result);
}
BigDecimal BigDecimal::floor(int len)
{
if(!isNum(decimal))return BigDecimal("NaN");
if(len<0)return BigDecimal(decimal);
bool isFu=decimal.startsWith("-");
bool isDecimal=decimal.contains(".");
//转为正数
decimal=decimal.replace(QRegExp("^-"),"");
QString result="";
if(!isDecimal){
result=decimal;
}else{
//获取小数位数
int intLen=decimal.lastIndexOf(".");
int decLen=decimal.length()-1-intLen;
if(decLen<=len)result=decimal;//原数返回
else if(len>0&&!isFu)result= decimal.left(intLen+1+len);
else if(len>0&&isFu)result= add(decimal.left(intLen+1+len),"0."+QString("0").repeated(len-1)+"1");
else if(!isFu) result=decimal.left(intLen);
else if(isFu) result=add(decimal.left(intLen),"1");
}
if(isFu)result="-"+result;
return BigDecimal(result);
}
QString BigDecimal::toString()
{
return this->decimal;
}
BigDecimal BigDecimal::operator+(const BigDecimal &bigDecimal)
{
QString result=add(this->decimal,bigDecimal.decimal);
return BigDecimal(result);
}
BigDecimal BigDecimal::operator-(const BigDecimal &bigDecimal)
{
QString result=subtract(this->decimal,bigDecimal.decimal);
return BigDecimal(result);
}
BigDecimal BigDecimal::operator*(const BigDecimal &bigDecimal)
{
QString result=multiply(this->decimal,bigDecimal.decimal);
return BigDecimal(result);
}
BigDecimal BigDecimal::operator/(const BigDecimal &bigDecimal)
{
QString a=this->decimal;
QString b=bigDecimal.decimal;
//获取小数位数,最大保留10位
QString result=divide(a,b,10);
return BigDecimal(result);
}
bool BigDecimal::operator>(const BigDecimal &bigDecimal)
{
if(compare(this->decimal,bigDecimal.decimal)==-2)return false;
return compare(this->decimal,bigDecimal.decimal)==1;
}
bool BigDecimal::operator==(const BigDecimal &bigDecimal)
{
if(compare(this->decimal,bigDecimal.decimal)==-2)return false;
return compare(this->decimal,bigDecimal.decimal)==0;
}
bool BigDecimal::operator>=(const BigDecimal &bigDecimal)
{
if(compare(this->decimal,bigDecimal.decimal)==-2)return false;
return compare(this->decimal,bigDecimal.decimal)>=0;
}
bool BigDecimal::operator<(const BigDecimal &bigDecimal)
{
if(compare(this->decimal,bigDecimal.decimal)==-2)return false;
return compare(this->decimal,bigDecimal.decimal)==-1;
}
bool BigDecimal::operator<=(const BigDecimal &bigDecimal)
{
if(compare(this->decimal,bigDecimal.decimal)==-2)return false;
return compare(this->decimal,bigDecimal.decimal)<=0;
}
int BigDecimal::compare(QString a, QString b)
{
QString cha=subtract(a,b);
if(cha=="NaN")return -2;
if(cha.contains("-"))return -1;
else if(cha=="0")return 0;
else return 1;
}
QString BigDecimal::moreXsingle(QString a, QString b)
{
if(a.isEmpty()||b.isEmpty())return "NaN";
QString result="0";
bool ok;
int numB=b.toInt(&ok,10);
if(!ok||b.contains("-"))return "NaN";
int len=a.length();
for (int i =len-1; i>=0;i--) {
QString strA=a.mid(i,1);
int numA=strA.toInt(&ok,10);
if(!ok)return "NaN";
int res=numA*numB;
//每次计算要补的0
QString zero=QString("0").repeated(len-1-i);
QString resStr=QString("%1").arg(res)+zero;
result=add(result,resStr);
}
return result;
}
bool BigDecimal::isNum(QString decimal)
{
QRegExp reg("^-?[0-9]+[.]?[0-9]*$");
reg.setCaseSensitivity(Qt::CaseSensitive);
if(reg.indexIn(decimal)==-1)return false;
else return true;
}