当单独计算 ,因为 ,double的最大取值为1.79769e+308,所以 肯定超过了double的表示范围。
同样,对于300!也是如此。
那我们应该怎么去计算和存储结果呢?
从数学角度出发,对于超级大的数,运算方式、运算规律等肯定保持不变的。
很多时候,我们主要是利用相关的定理、公式进行简化或者极限处理。
由于我项目里的精度要求不是很高,于是,可以采用相对宽松的方式解决这个问题:
科学计数法!
/*
* @file BigNumeric.hpp
* @brief 模板类,用于大数计算,以科学计数法为实现形式,尾数部分有效位数12,指数部分完全准确.
* 直接在工程中引入该hpp文件即可使用该类,重载了+-/*以及幂运算和开方等.
* 由于指数部分采用的市 int ,故限制了本类使用时科学计数法的最大表示范围为:
* a*10^2147483647 (-1.0<=a<=1.0)
**
* @author DongFengChuiLiu
* @email [email protected]
* @version 1.0
* @date 2023/10/15
*/
#ifndef __BigNumeric_h
#define __BigNumeric_h
#include
#include
template
class BigNumeric
{
private:
_T mantissa; //尾数
int exponent; //指数
public:
BigNumeric(_T num)
{
if (num == (_T)0)
{
exponent = 0;
mantissa = 0;
}
else
{
exponent = std::floor(std::log10(std::abs(num)));
mantissa = num / std::pow(10.0, exponent);
}
}
BigNumeric(_T mnt,int exp)
{
this->mantissa = mnt;
this->exponent = exp;
}
~BigNumeric() {}
BigNumeric(const BigNumeric& other)
{
if (this == &other)
return;
this->exponent = other.exponent;
this->mantissa = other.mantissa;
}
BigNumeric& operator=(const BigNumeric& other)
{
if(this == &other)
return *this;
this->exponent = other.exponent;
this->mantissa = other.mantissa;
return *this;
}
public:
//取 BigNumeric 对象的实际值
_T value()
{
if (this->exponent >= 308) return std::numeric_limits<_T>::infinity();
return this->mantissa * std::pow(10.0, this->exponent);
}
//乘法运算
// BigNumeric * BigNumeric
BigNumeric operator*(const BigNumeric opr)
{
BigNumeric<_T> resmnt(this->mantissa * opr.mantissa);
resmnt.exponent = CheckRange((_T)resmnt.exponent + this->exponent + opr.exponent);
return resmnt;
}
// BigNumeric * _T
BigNumeric operator*(const _T opr)
{
return *this * BigNumeric<_T>(opr);
}
//_T * BigNumeric
friend BigNumeric operator*(const _T opr, BigNumeric opr1)
{
return opr1 * opr;
}
//除法
// BigNumeric / BigNumeric
BigNumeric operator/(const BigNumeric opr)
{
BigNumeric<_T> resmnt(this->mantissa / opr.mantissa);
resmnt.exponent = CheckRange((_T)resmnt.exponent + this->exponent - opr.exponent);
return resmnt;
}
// BigNumeric / _T
BigNumeric operator/(const _T opr)
{
return *this / BigNumeric<_T>(opr);
}
// _T / BigNumeric
friend BigNumeric operator/(const _T opr, const BigNumeric opr1)
{
return BigNumeric<_T>(opr) / opr1;
}
//加法
// BigNumeric + BigNumeric
BigNumeric operator+(const BigNumeric opr)
{
if (this->exponent - opr.exponent > 15) return *this;
else if (this->exponent - opr.exponent < -15) return opr;
int min = this->exponent > opr.exponent ? opr.exponent : this->exponent;
BigNumeric<_T> resmnt(this->mantissa * std::pow(10.0, this->exponent - min) + opr.mantissa * std::pow(10.0, opr.exponent - min));
resmnt.exponent = CheckRange((_T)resmnt.exponent + min);
return resmnt;
}
// BigNumeric + _T
BigNumeric operator+(const _T opr)
{
return *this + BigNumeric<_T>(opr);
}
// _T + BigNumeric
friend BigNumeric operator+(const _T opr, BigNumeric opr1)
{
return opr1 + opr;
}
//减法
// BigNumeric - BigNumeric
BigNumeric operator-(const BigNumeric opr)
{
return *this + BigNumeric<_T>(opr) * (-1.0);
}
// BigNumeric - _T
BigNumeric operator-(const _T opr)
{
return *this - BigNumeric<_T>(opr);
}
// _T - BigNumeric
friend BigNumeric operator-(const _T opr, BigNumeric opr1)
{
return opr1 - opr;
}
//开方
// BigNumeric^0.5
BigNumeric Sqrt()
{
BigNumeric<_T> result(0.0);
_T bgnmant = std::sqrt(this->mantissa);
int bgnexp = this->exponent;
if (bgnexp % 2 == 0)
{
result.mantissa = bgnmant;
result.exponent = bgnexp / 2;
}
else
{
BigNumeric temp(bgnmant * std::sqrt(10.0));
result.mantissa = temp.mantissa;
result.exponent = temp.exponent + bgnexp / 2;
}
return result;
}
//幂
// BigNumeric^_T
BigNumeric Pow(_T exp)
{
BigNumeric temp(Vpow(this->mantissa, exp) * Vpow(10.0, this->exponent * (exp - (int)exp)));
temp.exponent = CheckRange((_T)temp.exponent + (_T)this->exponent * exp);
return temp;
}
public:
//整数阶乘 int!
static BigNumeric Factorial(const int opr)
{
if (opr < 0) return 1.0 / Factorial(-1.0 * opr + 1);
else if (opr == 0) return BigNumeric(1.0);
return Factorial(opr - 1) * opr;
}
//e指数幂运算 e^_T
static BigNumeric Epow(const _T exp)
{
BigNumeric res(1.0);
double e = 2.71828182845904523536;
if (exp <= 700) return BigNumeric(std::pow(e, exp));
int count = exp / 700;
BigNumeric bgn(std::pow(e, 700));
for (size_t i = 0; i < count; i++)
res = res * bgn;
BigNumeric bgn1(std::pow(e, exp - count * 700));
res = res * bgn1;
return res;
}
//e^BigNumeric
static BigNumeric Epow(const BigNumeric opr)
{
BigNumeric res(1.0);
double e = 2.71828182845904523536;
BigNumeric mnt(std::pow(e, opr.mantissa));
int count = std::abs(opr.exponent) > 1000 ? 1000 : std::abs(opr.exponent);
if (count == 0) return mnt;
if(opr.exponent < 0) res = mnt.Pow(0.1);
else res = mnt.Pow(10.0);
for (size_t i = 0; i < count - 1; i++)
{
if (opr.exponent < 0) res = res.Pow(0.1);
else res = res.Pow(10.0);
}
return res;
}
//任意底数的幂运算 a^_T
static BigNumeric Vpow(const _T e, const _T exp)
{
BigNumeric res(1.0);
BigNumeric bgnmant(e);
int chk = bgnmant.exponent == 0 ? exp : CheckRange(exp * bgnmant.exponent);
if (chk <= 300) return BigNumeric(std::pow(e, exp));
int count = exp / 300;
BigNumeric bgn(std::pow(bgnmant.mantissa, 300));
for (size_t i = 0; i < count; i++)
{
res = res * bgn;
res.exponent = CheckRange(res.exponent + (_T)bgnmant.exponent * 300);
}
BigNumeric bgn1(std::pow(bgnmant.mantissa, exp - count * 300));
res = res * bgn1;
res.exponent = CheckRange(res.exponent + (_T)bgnmant.exponent * (exp - count * 300));
return res;
}
private:
//控制指数的值范围
static int CheckRange(const _T num)
{
if (num >= (_T)2147483647) return 2147483647;
else if( num <= (_T)-2147483648) return -2147483648;
return num;
}
};
#endif // !__BigNumeric_h
//测试代码
#include "BigNumeric.hpp"
int main()
{
// 乘法测试
/*BigNumeric bignum(2.13e303);
BigNumeric bignum1(5e303);
BigNumeric res = bignum * bignum1;
res = bignum * 2;
res = 2 * bignum;
double t = res.value();*/
// 除法测试
/*BigNumeric bignum(2.13e303);
BigNumeric bignum1(4.26e303);
BigNumeric res = bignum1 / bignum;
res = 240.0 / bignum;
res = bignum / 2.13e302;*/
//加法测试
/*BigNumeric bignum(987654321);
BigNumeric bignum1(9);
BigNumeric res(bignum + bignum1);
res = bignum + 9;
res = 9 + bignum;*/
//减法测试
/*BigNumeric bignum(987654321);
BigNumeric bignum1(9);
BigNumeric res(bignum - bignum1);
res = bignum - 9;
res = 987654321 - bignum;*/
//幂测试
/*BigNumeric bignum(2.15 * 1.0e303);
BigNumeric TMP = (bignum*54321).Sqrt();
BigNumeric TMP1 = (bignum * 54321).Pow(0.5);
bignum = BigNumeric(9.15);
BigNumeric TMP2 = bignum.Pow(400);
double t = TMP2.value();*/
//阶乘测试
BigNumeric bignum = BigNumeric::Factorial(300);
BigNumeric bignum1 = BigNumeric::Epow(1000);
bignum = bignum1 / bignum;
double t = bignum.value();
return 0;
}
结果:6.4369310844548986e-181,尾数部分有效位数为 12,指数部分完全准确。