?? 高精度浮點數(shù).c
字號:
類的聲明文件:TLargeFloat.h
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TLargeFloat.h: interface for the TLargeFloat class.
// 超高精度浮點數(shù)類TLargeFloat
// 2004.03.28 by HouSisong@263.net
//////////////////////////////////////////////////////////////////////
// Update 2004.03.31 by HouSisong
// Update 2004.04.05 by HouSisong
// Update 2004.04.13 by HouSisong 添加異常觸發(fā)能力,TLargeFloat捕獲所有非法運算拋出TLargeFloatException異常
#ifndef _TLARGE_FLOAT_H__INCLUDED_
#define _TLARGE_FLOAT_H__INCLUDED_
#include <vector>
#include <sstream>
#include <string>
#include <Exception>
#include <limits>
#include <algorithm>
class TLargeFloat;//超高精度浮點數(shù)類TLargeFloat
class TLargeFloatException;//超高精度浮點數(shù)異常類
//改進方向:
// 1.強力優(yōu)化ArrayMUL數(shù)組乘運算(當(dāng)前算法復(fù)雜度為n*n),
// 可以使用二分算法來降低運算量,并使用復(fù)雜度為n*log(n)的快速復(fù)利葉變換或數(shù)論變換)
// 2.增加運算精度動態(tài)控制能力,有利于優(yōu)化,減少乘法量;
// 3.添加新的基本運算函數(shù),如:指數(shù)運算power、對數(shù)運算log、三角函數(shù)sin,cos,tan等
// 4.可以考慮:內(nèi)部使用2的次方的底數(shù);這樣的話,輸出函數(shù)就會麻煩一些了
//////注意:如果浮點數(shù)與TLargeFloat進行混合運算;
// 可能會產(chǎn)生誤差(有效位數(shù)會受到浮點數(shù)影響);
// 整數(shù) 或 為可表示整數(shù)的浮點數(shù) 參與運算不會產(chǎn)生誤差;
//超高精度浮點數(shù)異常類
class TLargeFloatException :public std::exception
{
private:
std::string m_ErrorMsg;
public:
TLargeFloatException() {};
TLargeFloatException(const char * Error_Msg) :m_ErrorMsg(Error_Msg){ }
virtual const char* what() const throw() { return m_ErrorMsg.c_str();}
virtual ~TLargeFloatException() throw() {}
};
//TCatchIntError只是對整數(shù)類型TInt進行的包裝
//設(shè)計TCatchIntError是為了當(dāng)整數(shù)運算超出值域的時候,拋出異常
//超高精度浮點數(shù)類的指數(shù)運算時使用
template <typename TInt,typename TException,TInt MinValue,TInt MaxValue>
//<要包裝的整數(shù)類型,超界時拋出的異常類型,TInt最小值,TInt最大值>
class TCatchIntError
{
private:
typedef TCatchIntError<TInt,TException,MinValue,MaxValue> SelfType;
TInt m_Int;
SelfType& inc(TInt uValue)
{
if (MaxValue-uValue<m_Int)
throw TException("ERROR:TCatchIntError::inc(); ");
m_Int+=uValue;
return (*this);
}
SelfType& dec(TInt uValue)
{
if (MinValue+uValue>m_Int)
throw TException("ERROR:TCatchIntError::dec()");
m_Int-=uValue;
return (*this);
}
public:
TCatchIntError() :m_Int(0){}
TCatchIntError(TInt Value) :m_Int(Value){}
TCatchIntError(const SelfType& Value) :m_Int(Value.m_Int){}
TInt AsInt()const { return m_Int; }
SelfType& operator +=(TInt Value) //throw(TLargeFloatException)
{ if (Value<0) return dec(-Value);
else return inc(Value); }
SelfType& operator -=(TInt Value) //throw(TLargeFloatException)
{ if (Value<0) return inc(-Value);
else return dec(Value); }
SelfType& operator +=(const SelfType& Value) { return (*this)+=(Value.m_Int); }//throw(TLargeFloatException)
SelfType& operator -=(const SelfType& Value) { return (*this)-=(Value.m_Int); }//throw(TLargeFloatException)
};
////填寫編譯器支持的較大的整數(shù)類型
//__int64 Int64_Min() { return std::numeric_limits<__int64>::min(); }//返回0, :(
//__int64 Int64_Max() { return std::numeric_limits<__int64>::max(); }//返回0, :(
//const __int64 Int64_Min = - __int64(9223372036854775808);//注意負(fù)號
//const __int64 Int64_Max = __int64(9223372036854775807);
const long int Int64_Min = -2147483648;//注意負(fù)號
const long int Int64_Max = 2147483647;
namespace Private_
{
template<typename T>
inline const T& min(const T& x,const T& y)//求最小值
{
if (x>y)
return y;
else
return x;
}
template<typename T>
inline const T& max(const T& x,const T& y)//求最大值
{
if (x>y)
return x;
else
return y;
}
template<typename T>
inline const T abs(const T& x)//求絕對值
{
if (x<0)
return -x;
else
return x;
}
template<typename T>
inline void swap(T& x,T& y) //交換兩個變量的值
{
T temp=x;
x=y;
y=temp;
}
}//end namespace
//超高精度浮點數(shù)類
class TLargeFloat
{
private:
enum {
emLongDoubleDigits=std::numeric_limits<long double>::digits10,//long double的10進制有效精度
emLongDoubleMaxExponent=std::numeric_limits<long double>::max_exponent10,//long double的最大10進制指數(shù)
emLongDoubleMinExponent=std::numeric_limits<long double>::min_exponent10 };//long double的最小10進制指數(shù)
typedef TLargeFloat SelfType;
typedef TLargeFloatException TException;
typedef long int Int32bit;//32bit位的整數(shù)類型,超過也可以
//typedef __int64 TMaxInt; //填寫編譯器支持的較大的整數(shù)類型
typedef long int TMaxInt; //填寫編譯器支持的較大的整數(shù)類型
typedef TCatchIntError<TMaxInt,TException,Int64_Min,Int64_Max> ExpInt;//注意:后面的兩個值為TMaxInt的最小值和最大值
typedef std::vector<Int32bit> TArray;//小數(shù)位使用的數(shù)組類型
enum { em10Power=4, emBase=10000};//數(shù)組為10000進制,數(shù)組的一個元素表示一位,對應(yīng)4個十進制位
Int32bit m_Sign; //符號位 正:1, 負(fù):-1, 零: 0
ExpInt m_Exponent; //保存10為底的指數(shù)
TArray m_Digits; //小數(shù)部分 排列順序是TArray[0]為第一個小數(shù)位,依此類推;取值范圍0--999
void Abs_Add(const SelfType& Value);//絕對值加 x:=|x|+|y|;
void Abs_Sub_Abs(const SelfType& Value);//絕對值減的絕對值x:=| |x|-|y| |;
void MoveLeft10Power(TMaxInt MoveCount);//十進制指數(shù)移動 值不變指數(shù)增大MoveCount
void MoveRight10Power(TMaxInt MoveCount);//十進制指數(shù)移動 值不變指數(shù)減小MoveCount
void MulInt(TMaxInt iValue);//乘以一個整數(shù);
void DivInt(TMaxInt iValue);//除以一個整數(shù);
void Clear();//清零
void Chs();//求負(fù)
int Compare(const SelfType& Value) const;//比較兩個數(shù);(*this)>Value 返回1,小于返回-1,相等返回0
void Canonicity();//規(guī)格化 轉(zhuǎn)化值到合法格式
static std::string DigitToString(Int32bit iDigit);//將數(shù)組的一個元素轉(zhuǎn)換為字符串表示
static void toEqExponent(SelfType& x,SelfType& y);//值不變,x,y的小數(shù)點對齊
static void SetSameSizeMax(SelfType& x,SelfType& y);//使兩個高精度數(shù)的有效位數(shù)相同,位數(shù)小的進行提升
static bool FloatIsInteger(long double fValue);//判斷浮點數(shù)是否為可表示整數(shù)
static unsigned int DigitsSize(unsigned int uiDigitsLength);//
//數(shù)組乘 (卷積result[i+j]=x[i]*y[j];) //ArrayMUL 是需要優(yōu)化的首要目標(biāo)
static void ArrayMUL(const Int32bit* x,const Int32bit* y,Int32bit* result,unsigned int MulSize);
class TCharacter{};
TLargeFloat(long double DefultFloatValue,const TCharacter&);//內(nèi)部使用,浮點數(shù)轉(zhuǎn)化為 TLargeFloat
void Abs();//絕對值
void Rev();//求倒數(shù)1/x
void RevSqrt();//求1/x^0.5;
void Sqrt();//求x^0.5;
public:
class TDigits//TDigits用來設(shè)置TLargeFloat的精度;//增加這個類是為了避免TLargeFloat的構(gòu)造函數(shù)的可能誤用
{
private:
unsigned int m_eDigits;
public:
explicit TDigits(unsigned int uiDigitsLength) :m_eDigits(uiDigitsLength){}
unsigned int GetDigits()const { return m_eDigits; }
};
TLargeFloat(const SelfType& Value);
TLargeFloat(long double DefultValue,const TDigits& DigitsLength);//TDigits (十進制的)有效位數(shù)
virtual ~TLargeFloat(){}
void swap(SelfType& Value);//交換值
unsigned int GetDigitsLength() const;//返回當(dāng)前的10進制有效位數(shù)
void SetDigitsLength(unsigned int uiDigitsLength);//重新設(shè)置10進制有效位數(shù)
void SetDigitsLength(const TDigits& DigitsLength) { SetDigitsLength(DigitsLength.GetDigits()); }
long double AsFloat() const;//轉(zhuǎn)化為浮點數(shù)
std::string AsString() const;//轉(zhuǎn)換為字符串
const SelfType operator - () const;//求負(fù) //注意:不能使用SelfType&
const SelfType& operator + () const;//求正 //注意:可以使用SelfType&,因為值不變
SelfType& operator = (long double fValue); //注意:轉(zhuǎn)換可能存在小的誤差
SelfType& operator = (const SelfType& Value); //編譯器默認(rèn)的也行
SelfType& operator *= (long double fValue);
SelfType& operator /= (long double fValue);
SelfType& operator += (long double fValue);
SelfType& operator -= (long double fValue);
SelfType& operator += (const SelfType& Value);
SelfType& operator -= (const SelfType& Value);
SelfType& operator *= (const SelfType& Value);
SelfType& operator /= (const SelfType& Value);
friend const TLargeFloat operator + (const TLargeFloat& x,const TLargeFloat& y);
friend const TLargeFloat operator - (const TLargeFloat& x,const TLargeFloat& y);
friend const TLargeFloat operator * (const TLargeFloat& x,const TLargeFloat& y);
friend const TLargeFloat operator / (const TLargeFloat& x,const TLargeFloat& y);
friend const TLargeFloat operator + (const TLargeFloat& x,long double y);
friend const TLargeFloat operator - (const TLargeFloat& x,long double y);
friend const TLargeFloat operator * (const TLargeFloat& x,long double y);
friend const TLargeFloat operator / (const TLargeFloat& x,long double y);
friend const TLargeFloat operator + (long double x,const TLargeFloat& y);
friend const TLargeFloat operator - (long double x,const TLargeFloat& y);
friend const TLargeFloat operator * (long double x,const TLargeFloat& y);
friend const TLargeFloat operator / (long double x,const TLargeFloat& y);
friend bool operator ==(const TLargeFloat& x,const TLargeFloat& y);
friend bool operator < (const TLargeFloat& x,const TLargeFloat& y);
friend bool operator ==(const TLargeFloat& x,long double y);
friend bool operator < (const TLargeFloat& x,long double y);
friend bool operator ==(long double x,const TLargeFloat& y) { return (y==x); }
friend bool operator < (long double x,const TLargeFloat& y) { return (y>x); }
friend bool operator !=(const TLargeFloat& x,const TLargeFloat& y) { return !(x==y); }
friend bool operator > (const TLargeFloat& x,const TLargeFloat& y) { return (y<x); }
friend bool operator >=(const TLargeFloat& x,const TLargeFloat& y) { return !(x<y); }
friend bool operator <=(const TLargeFloat& x,const TLargeFloat& y) { return !(x>y); }
friend bool operator !=(const TLargeFloat& x,long double y) { return !(x==y); }
friend bool operator > (const TLargeFloat& x,long double y) { return (y<x); }
friend bool operator >=(const TLargeFloat& x,long double y) { return !(x<y); }
friend bool operator <=(const TLargeFloat& x,long double y) { return !(x>y); }
friend bool operator !=(long double x,const TLargeFloat& y) { return !(x==y); }
friend bool operator > (long double x,const TLargeFloat& y) { return (y<x); }
friend bool operator >=(long double x,const TLargeFloat& y) { return !(x<y); }
friend bool operator <=(long double x,const TLargeFloat& y) { return !(x>y); }
friend std::ostream& operator << (std::ostream& cout, const TLargeFloat& Value) { return cout<<Value.AsString(); }
friend void swap(TLargeFloat& x,TLargeFloat& y) { x.swap(y); }
friend const TLargeFloat abs(const TLargeFloat& x) { TLargeFloat result(x); result.Abs(); return result; }//絕對值,|x|
friend const TLargeFloat sqrt(const TLargeFloat& x) { TLargeFloat result(x); result.Sqrt(); return result;} //開方,x^0.5
friend const TLargeFloat revsqrt(const TLargeFloat& x) { TLargeFloat result(x); result.RevSqrt(); return result; }//求1/x^0.5;
friend const TLargeFloat sqr(const TLargeFloat& x) { return x*x; };//平方,x^2
};
void LargeFloat_UnitTest();//正確性測試
//下面的代碼是用來測試的
//例子:
//計算圓周率PI
//經(jīng)過測試,計算中97%的時間都在運行ArrayMUL函數(shù)
TLargeFloat GetBorweinPI();//使用Borwein四次迭代式
void Debug_toCout(const std::string& strx,const TLargeFloat& x);//調(diào)試輸出
#endif // _TLARGE_FLOAT_H__INCLUDED_
// TLargeFloat.h
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
類的實現(xiàn)文件:TLargeFloat.cpp
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TLargeFloat.cpp: implementation of the TLargeFloat class.
// 超高精度浮點數(shù)類TLargeFloat
//////////////////////////////////////////////////////////////////////
//#include "stdafx.h"//
#include "TLargeFloat.h"
#include "assert.h"
#include <math.h>
#include <iostream>
//計算圓周率PI
TLargeFloat GetBorweinPI()
{
/*
Borwein四次迭代式:
初值:
a0=6-4*2^0.5; y0=2^0.5-1;
重復(fù)計算:
y(n+1)=[1-(1-y^4)^0.25]/[1+(1-y^4)^0.25];
y=y(n+1);
a(n+1)=a*(1+y)^4-2^(2*n+3)*y*(1+y+y*y);
最后計算:
PI=1/a;
*/
TLargeFloat::TDigits sCount(1000);//計算采用1000位精度 計算出的PI后面35位無效
TLargeFloat a(0.0,sCount),y(0.0,sCount);
TLargeFloat PI(0.0,sCount);
TLargeFloat temp(0.0,sCount),temp2(0.0,sCount);
TLargeFloat pow(0.0,sCount);
pow=(2*2*2);//2^(2*n+3); (n=0);
//a0=6-4*2^0.5;
temp=2;
temp=sqrt(temp);
a=6-4*temp;
//y0=2^0.5-1;
y=temp-1;
//1
int m=8;//
int n=0;
while (true)
{
//y(n+1)=[1-(1-y^4)^0.25]/[1+(1-y^4)^0.25];
temp=1-sqr(sqr(y));
temp=revsqrt(revsqrt(temp));//等價于 temp=sqrt(sqrt(temp));
y=(1-temp)/(1+temp);
//a(n+1)=a*(1+y)^4-2^(2*n+3)*y*(1+y+y*y);
temp=sqr(sqr(1+y));
a=a*temp-pow*y*(1+y+y*y);
pow*=4;
++n;
if (m>int(sCount.GetDigits())) break;
m*=4;//四階收斂
}
//PI=1/a;
PI=1/a;
return PI;
}
/////////
bool TLargeFloat::FloatIsInteger(long double fValue)//浮點數(shù)是否為可表示整數(shù)
{
return (TMaxInt(floor(fValue))==fValue);
}
unsigned int TLargeFloat::DigitsSize(unsigned int uiDigitsLength)
{
if (!(uiDigitsLength>=1))
{
throw TException("ERROR:TLargeFloat::DigitsSize()");
}
return (uiDigitsLength+(em10Power-1))/em10Power;//計算出需要的數(shù)組大小
}
TLargeFloat::TLargeFloat(long double DefultFloatValue,const TDigits& DigitsLength)
:m_Digits(DigitsSize(DigitsLength.GetDigits()),0)
{
m_Exponent=0;
m_Sign=0;
*this=DefultFloatValue;
}
TLargeFloat::TLargeFloat(long double FloatValue,const TCharacter&)//內(nèi)部使用 浮點數(shù)轉(zhuǎn)化為 TLargeFloat,并采用默認(rèn)精度
:m_Digits(DigitsSize(emLongDoubleDigits),0)
{
m_Exponent=0;
m_Sign=0;
*this=FloatValue;
}
TLargeFloat::TLargeFloat(const SelfType& Value)
:m_Digits(Value.m_Digits)
{
m_Exponent=Value.m_Exponent;
m_Sign=Value.m_Sign;
}
TLargeFloat::SelfType& TLargeFloat::operator = (const SelfType& Value)
{
m_Digits=Value.m_Digits;
m_Exponent=Value.m_Exponent;
m_Sign=Value.m_Sign;
return *this;
}
void TLargeFloat::SetDigitsLength(unsigned int uiDigitsLength)//重新設(shè)置10進制有效位數(shù)
{
m_Digits.resize(DigitsSize(uiDigitsLength),0);
}
unsigned int TLargeFloat::GetDigitsLength() const//返回當(dāng)前的10進制有效位數(shù)
{
return m_Digits.size()*em10Power;
}
void TLargeFloat::Clear()
{
//清零
int size=m_Digits.size();
for (int i=0;i<size;++i)
m_Digits[i]=0;
m_Exponent=0;
m_Sign=0;
}
TLargeFloat::SelfType& TLargeFloat::operator = (long double fValue)
{
Clear();
if (0==fValue)
{
//do nothing;
}
else
{
if (fValue>0)
m_Sign=1;
else
{
m_Sign=-1;
fValue=-fValue;
}
if (FloatIsInteger(fValue))//對 為"可表示整數(shù)" 的浮點數(shù) 進行特殊處理 無誤差轉(zhuǎn)換
{
long double tf=fValue;
int n=0;
for (;;++n)
{
if (0==tf) break;
tf/=emBase;
tf=floor(tf);
}
m_Exponent=n*em10Power;
for (int i=0;i<n;++i)
{
m_Digits[n-1-i]=Int32bit(TMaxInt(fValue)%emBase);
fValue=floor(fValue/emBase);
}
}
else//一般的浮點數(shù) 轉(zhuǎn)化中可能產(chǎn)生小的誤差
{
m_Exponent=int(floor(log10(fValue)))+1;//得到10為底的指數(shù)
fValue/=pow(10.0,(long double)(m_Exponent.AsInt()));
int size=m_Digits.size();
int minsize=Private_::min(size,emLongDoubleDigits/em10Power+1);
for (int i=0;i<minsize;++i)//得到小數(shù)位
{
if (0==fValue) break;
fValue*=emBase;
Int32bit IValue=Int32bit(floor(fValue));
fValue-=IValue;
m_Digits[i]=IValue;
if (i==minsize-1)
{
if (fValue*emBase*2>=emBase)//四舍五入
{
m_Digits[i]+=1;
for (int j=i;j>0;--j)
{
if (m_Digits[j]>=emBase)//進位
{
m_Digits[j-1]+=1;
m_Digits[j]-=emBase;
}
else
break;
}//for j
}//if
}//if
}
}//for i
}
Canonicity();
return *this;
}
long double TLargeFloat::AsFloat() const
{
//
if ( ((m_Exponent.AsInt())>=emLongDoubleMaxExponent)
||((m_Exponent.AsInt())<=emLongDoubleMinExponent) )
{
throw TException("ERROR:TLargeFloat::AsFloat()");
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -