加強的數學函數庫(第1次發佈,功能不斷增長中)

/*- ==========================================================
*     文件名  :MathFunc.h
*     開發人員:袁培榮
*     當前版本:1.3.3.2595 (第1次發佈,功能不斷增長中)
*     建立時間:2012-05-28
*     修改時間:2012-05-30
*     功能說明:加強的數學函數庫的聲明
*     版權說明:版權全部 袁培榮 YuanPeirong 
*     編譯環境:Windows 7(x64) SP1 簡體中文專業版
*     編譯器:  Visual Studio 2010 SP1(中文旗艦版)
                MinGW 20120426 GNU GCC 4.6.2
                Visual C++ 6.0 SP6(中文企業版)
- ==========================================================*/

//編譯測試狀況:
// 1.Visual Studio 2010 SP1(中文旗艦版):
//   在Release和Debug下都編譯經過,測試運行正常。
// 2.MinGW 20120426 GNU GCC 4.6.2:
//   編譯經過,測試運行正常。
// 3.Visual C++ 6.0 SP6(中文企業版)
//   未測試。

#ifndef MathFunc_H_TYCppStdLib              //防止頭文件重複包含
#define MathFunc_H_TYCppStdLib

#ifdef MathFunc_DLL_API                     //爲導出DLL預留
#else
#define MathFunc_DLL_API _declspec(dllimport)
#endif

#include <cstdlib>
#include <cmath>
#include <ctime>
#include <vector>     //vector容器
#include <algorithm>  //泛型算法
#include <numeric>    //泛化算法
//#include <functional> //標準庫的函數對象類型在此定義

using namespace std;

namespace TYCppStdLib   //全部功能都封裝在命名空間TYCppStdLib中
{
    //產生一個隨機整數
    int Random(
        int minValue=-32768,      //設置數據的最大值(包含)
        int maxValue=32767,       //設置數據的最大值(包含)
        bool isPrime=false        //是否必需要返回質數
    );
    
    //產生隨機純小數
    double Random(
        double minValue=0,   //設置數據的最小值(包含)
        double maxValue=1,   //設置數據的最大值(包含)
        bool get0and1=false  //指明是否能夠產生0和1
    );
    
    //產生一組隨機整數(此函數是之前寫的,將要被我棄用,由於使用了不安全的數組)
    //建議使用功能更增強大的 RandomVecInt函數(在下文中定義)
    bool Random(
        int *data,           //用於存放產生的整數的數組首地址 
        int num,             //設置要產生的數據個數
        int minValue=-32768, //設置數據的最小值(包含)
        int maxValue=32767,  //設置數據的最大值(包含)
        bool different=false //設置數據是否要互不相同
    );
    
    //爲Random函數定義相應的類,方便生成函數對象做爲泛型算法的發生器
    class Random_cls
    {
    private:
        int minValue;
        int maxValue;
        bool isPrime;
    public:
        Random_cls(int min, int max, bool isp);
        int operator()();
    };
    
    bool IsPrime(int n);               //判斷質數
    //獲取n之內(含n)的全部質數的個數
    int GetPrime(int n);                 
    //獲取n之內(含n)的全部質數,並返回質數的個數
    int GetPrime(int n, vector<int> &vec); 
    //int GetPrime(int n, int *p); //數組版本,因不安全,不想支持    
    bool IsSquare(int n);              //判斷徹底平方數
    
    //求兩個數的最大公約數
    int GetGCD(int m, int n);
    //求一組數據的最大公約數(不安全,不推薦使用)
    int GetGCD(const int *p, int count); 
    //或者是int GetGCD(const int p[], int count);
    //求一組數據的最大公約數(安全,推薦使用)
    int GetGCD(vector<int> &vec);
    
    //求兩個數的最小公倍數
    int GetLCM(int m, int n);
    //求一組數據的最小公倍數(不安全,不推薦使用)
    int GetLCM(const int *p, int count);
    //或者是int GetLCM(const int p[], int count);
    //求一組數據的最小公倍數(安全,推薦使用)
    int GetLCM(vector<int> &vec);
    
    int GetFactorial(int n);  //求階乘(13之內)(非遞歸和遞歸方式實現)
    //得到0到n的階乘結果(n超過13時設爲13)
    //這裏不用到GetFactorial,由於效率過低
    void FacVecInt(vector<int> &vec, int n);    
    
    int InversionData(int n); //求整數的逆序數,如6589返回9856
    
    //如下用到 vector 的函數均可以寫相應的數組版本
    //可是由於數組是不安全的東西,不想再支持數組
    
    //獲取數字的位數
    int DivideDigit(int n);
    //獲取數字的各個位上的數值,並返回分離出的數字個數
    int DivideDigit(
        int n,               //待求數字
        vector<int> &vec,    //存儲結果
        bool forward=true    //ture:高位在前存儲,false:低位在前存儲
    );
    //獲取數字的各個位上的數值(高位在前),並返回分離出的數字個數
    //int DivideDigitA(int n, vector<int> &vec); //再也不須要
    //獲取數字的各個位上的數值(低位在前),並返回分離出的數字個數
    //int DivideDigitB(int n, vector<int> &vec); //再也不須要
    
    //將一組數據按位合成一個數
    int JoinDigit(
        const vector<int> &vec, //一組數據
        bool forward=true,      //ture:高位在前,false:低位在前
        bool onlyBit=false      //數據中的每一位是否只取其個位
    );
    
    //生成一組隨機數據(用隨機數據初始化vector<int>)
    void RandomVecInt(
        vector<int> &vec,      //存放數據的容器
        int num,               //產生數據的個數
        int minValue=-32768,   //設置數據的最大值(包含)
        int maxValue=32767,    //設置數據的最大值(包含)
        bool isPrime=false     //產生的數據是否必須爲質數
    );
    
    //求Fibonacci數列的第N項 F1=1 F2=1 F3=2 ……(非遞歸和遞歸方式實現)
    int Fibonacci(int n);
    //求Fibonacci數列的前N項(用Fibonacci數列初始化vector<int>)
    //這裏不用到Fibonacci函數,由於效率過低
    void FibVecInt(vector<int> &vec, int num); 
    
    //求一組數據的和
    template<typename T>
    T GetSum(const vector<T> &vec);
    // template<typename T> //初始實現版本
    // T GetSum(typename vector<T>::const_iterator start, typename vector<T>::const_iterator end);
    //調用方式:T sum=GetSum(s, e)或者 GetSum<T>(s, e)
    template<typename T, typename InputIterator> //更加泛化的實現版本
    T GetSum(InputIterator start, InputIterator end);
    //調用方式:T sum=GetSum(s, e)或者 GetSum<T>(s, e)
    
    //求一組數據的算術平均數(涉及到除法,所以返回值轉爲double,下同)
    template<typename T>
    double GetMean(const vector<T> &vec);
    
    //求一組數據的方差
    template<typename T>
    double GetVariance(const vector<T> &vec);

    //求一組數據的標準差
    template<typename T>
    double GetStDev(const vector<T> &vec);
    
    //將一組數據反序,並覆蓋原數據
    template<typename T>
    void InverseVec(vector<T> &vec); //結果覆蓋原數據
    //將一組數據反序,不覆蓋原數據
    template<typename T>
    void InverseVec(
        const vector<T> &vec1,      //原數據
        vector<T> &vec2             //逆序數據
    );
    
    //比較兩個數的大小
    template<typename T>
    bool IsBig(const T &m, const T &n);
    template<typename T>
    bool IsSmall(const T &m, const T &n);
    
    //將一組數據進行排序,並覆蓋原數據
    template<typename T>
    void SortVec(
        vector<T> &vec,        //結果覆蓋原數據
        bool smallToBig=true,  //ture:從小到大,false:從大到小
        bool eraseUnique=false //ture:去除重複值,false:不去除重複值
    ); 
    //將一組數據進行排序,不覆蓋原數據
    template<typename T>
    void SortVec(
        const vector<T> &vec1, //原數據
        vector<T> &vec2,       //逆序數據
        bool smallToBig=true,  //ture:從小到大,false:從大到小
        bool eraseUnique=false //ture:去除重複值,false:不去除重複值
    );
    
    //生成等差數列(Arithmetic Sequence)(用等差數列初始化vector<T>)
    template<typename T>
    void AriVecT(
        vector<T> &vec, //存儲數據
        T fisrt,        //首項
        T tolerance,    //公差
        T num           //項數
    );
    
    //生成等比數列(Geometric Sequence)(用等比數列初始化vector<T>)
    template<typename T>
    void GeoVecT(
        vector<T> &vec, //存儲數據
        T fisrt,        //首項
        T comRatio,     //公比
        T num           //項數
    );
    
    // 僅爲測試
    // template<typename T>
    // T GetTest(T n);

}

//爲了兼容各編譯器,特別是VC++6.0這種低級的舊版本編譯器
//只好採用模板的包含編譯模式
//模板的實現放在.hpp文件中,編譯時不單獨編譯
//而事實上, Visual Studio 2010也不能採用更先進的分離編譯模式
//而對C++標準支持得最好的MinGW也不能支持更先進的分離編譯模式
//除了國外極少數的冷門商業編譯器支持分離編譯模式
//我現有的編譯器都不僅支持,所以只能頭文件反向包含源文件的作法
//採用了boost的作法,將其反綴名定爲 .hpp ,即 .h + .cpp
#include "MathFunc.hpp" 
//在編譯時,應將此hpp文件當作頭文件而非源文件,即不單獨編譯
#endif

//摘自:SGI STL
/*   template<typename _InputIterator, typename _Tp>
    inline _Tp
    accumulate(_InputIterator __first, _InputIterator __last, _Tp __init)
    {
      // concept requirements
      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
      __glibcxx_requires_valid_range(__first, __last);

      for (; __first != __last; ++__first)
    __init = __init + *__first;
      return __init;
    } */

/*- ==========================================================
*     文件名  :MathFunc.cpp
*     開發人員:袁培榮
*     當前版本:1.3.3.2595 (第1次發佈,功能不斷增長中)
*     建立時間:2012-05-28
*     修改時間:2012-05-30
*     功能說明:加強的數學函數庫的實現
*     版權說明:版權全部 袁培榮 YuanPeirong 
*     編譯環境:Windows 7(x64) SP1 簡體中文專業版
*     編譯器:  Visual Studio 2010 SP1(中文旗艦版)
                MinGW 20120426 GNU GCC 4.6.2
                Visual C++ 6.0 SP6(中文企業版)
- ==========================================================*/

//編譯測試狀況:
// 1.Visual Studio 2010 SP1(中文旗艦版):
//   在Release和Debug下都編譯經過,測試運行正常。
// 2.MinGW 20120426 GNU GCC 4.6.2:
//   編譯經過,測試運行正常。
// 3.Visual C++ 6.0 SP6(中文企業版)
//   未測試。

#ifndef MathFunc_DLL_ForAPI
#define MathFunc_DLL_ForAPI

#define MathFunc_DLL_API _declspec(dllexport) //爲導出DLL預留

#endif

#include "../Include/MathFunc.h"

using namespace std;
using namespace TYCppStdLib;

//產生一個隨機整數
int TYCppStdLib::Random(
    int minValue,        //設置數據的最大值(包含)
    int maxValue,        //設置數據的最大值(包含)
    bool isPrime         //是否必需要返回質數
)
{
    if(maxValue<minValue)
        return 0;//return false;
    if(minValue<-32768)
        minValue=-32768;
    if(maxValue>32767)
        maxValue=32767;
    int ix;
    static bool randomFisrt=true;
    if(randomFisrt)
        srand(time(static_cast<time_t>(0)));
    randomFisrt=false;
    ix=rand();
    ix=ix%(maxValue-minValue+1)+minValue;
    if(!isPrime)
        return ix;
    bool isp=IsPrime(ix);
    if(isp)
        return ix;
    while(!isp)
    {
        ix=rand();
        ix=ix%(maxValue-minValue+1)+minValue;
        isp=IsPrime(ix);
    }
    return ix;
}

//產生隨機純小數
double TYCppStdLib::Random(double minValue, double maxValue, bool get0and1)
{
    if(maxValue<minValue)
        return 0;//return false;
    if(minValue<0)
        minValue=0;
    if(maxValue>1)
        maxValue=1;
    double dx;
    int ix1, ix2;
    ix1=(int)(minValue*32767);
    ix2=(int)(maxValue*32767);
    ix1=Random(ix1, ix2);
    if(false==get0and1 && 0==minValue && 1==maxValue)
    {
        if(!ix1)
            ix1=1;
        if(ix1==32767)
            ix1=32766;
    }
    dx=(double)(ix1)/32767;
    return dx;
}

//產生一組隨機整數(此函數是之前寫的,將要被我棄用,由於使用了不安全的數組)
bool TYCppStdLib::Random(int *data, int num, int minValue, int maxValue, bool different)
{

    if(num<1 || maxValue<minValue)
        return false;
    if(minValue<-32768)
        minValue=-32768;
    if(maxValue>32767)
        maxValue=32767;
    if(different && (maxValue-minValue+1)<num)
        return false;
    int ii, ij, ix;
    for(ii=0;ii<num;ii++)
    {
        while(1)
        {
            ix=Random(minValue, maxValue);
            if(!different)
                break;
            for(ij=0;ij<ii;ij++)
            {
                if(ix==*(data+ij))
                    break;
            }
            if(ij==ii)
                break;
        }
        *(data+ii)=ix;
    }
    return true;
}

//如下的函數是正確的,只是將數組形參寫成指針形式更好,所以棄用
// 產生一批隨機整數
// bool Random(
    // int data[], //用於存放產生的整數的數組
    // int num,    //設置要產生的數據個數
    // int minValue=-32768, //設置數據的最小值(包含)
    // int maxValue=32767,//設置數據的最大值(包含)
    // bool different=false //設置數據是否要互不相同
// );

// bool Random(int data[], int num, int minValue, int maxValue, bool different)
// {

    // if(num<1 || maxValue<minValue)
        // return false;
    // if(minValue<-32768)
        // minValue=-32768;
    // if(maxValue>32767)
        // maxValue=32767;
    // if(different && (maxValue-minValue+1)<num)
        // return false;
    // int ii, ij=0, ix;
    // for(ii=0;ii<num;ii++)
    // {
        // while(1)
        // {
            // ix=Random(minValue, maxValue);
            // if(!different)
                // break;
            // for(ij=0;ij<ii;ij++)
            // {
                // if(ix==data[ij])
                    // break;
            // }
            // if(ij==ii)
                // break;
        // }
        // data[ii]=ix;
    // }
    // return true;
// }

//爲Random函數定義相應的類,方便生成函數對象做爲泛型算法的發生器
TYCppStdLib::Random_cls::Random_cls(int min, int max, bool isp)
{
    minValue=min;
    maxValue=max;
    isPrime=isp;
}

int TYCppStdLib::Random_cls::operator()()
{
    return Random(minValue, maxValue, isPrime);    
}

//判斷質數
bool TYCppStdLib::IsPrime(int n)
{
    n=abs(n); //容許n是負數
    if(n<2)
        return false;
    int m=static_cast<int>(sqrt(static_cast<double>(n)))+1;
    for(int i=2; i<m+1; i++) //i<m或i<m+1
        if(n%i==0)
            return false;
    return true;
}

//獲取n之內(含n)的全部質數的個數
int TYCppStdLib::GetPrime(int n)
{
    if(n<2)
        return 0;
    if(2==n)
        return 1;
    int num=1;
    for(int i=3; i<=n; i=i+2)
        if(IsPrime(i))
            num++;
    return num;
}  

//獲取n之內(含n)的全部質數,並返回質數的個數
int TYCppStdLib::GetPrime(int n, vector<int> &vec)
{
    vec.clear();
    if(n<2)
        return 0;
    if(2==n)
    {
        vec.push_back(2);
        return 1;
    }
    vec.push_back(2);
    for(int i=3; i<=n; i=i+2)
        if(IsPrime(i))
            vec.push_back(i);
    return static_cast<int>(vec.size());
}

//判斷徹底平方數
bool TYCppStdLib::IsSquare(int n) 
{
    if(n<0)
        return false;
    int m=static_cast<int>(sqrt(static_cast<double>(n)));
    if(m*m==n)
        return true;
    return false;
}

//求兩個數的最大公約數
int TYCppStdLib::GetGCD(int m, int n)
{
    if(!m && !n)
        return 0;
    if(!m)
        return n;
    if(!n)
        return m;
    int r;
    while(r=m%n)
    {
        m=n;
        n=r;
    }
    return abs(n);
}

//求一組數據的最大公約數(不安全,不推薦使用)
int TYCppStdLib::GetGCD(const int *p, int count)
{ 
    if(!p || count<2)  
        return 0;
    int gcd=p[0]; 
    for(int i=1; i!=count; i++)
        gcd=GetGCD(gcd,p[i]);
    return abs(gcd);
}

//求一組數據的最大公約數(安全,推薦使用)
int TYCppStdLib::GetGCD(vector<int> &vec)
{
    int vsize=vec.size();
    if(vsize<2)
        return 0;
    int gcd=vec[0];
    for(int i=1; i!=vsize; i++)
        gcd=GetGCD(gcd, vec[i]);
    return abs(gcd);
}

//求兩個數的最小公倍數
int TYCppStdLib::GetLCM(int m, int n) 
{
    if(!m || !n)
        return 0;
    int lcm=m*n/GetGCD(m, n); //GetGCD(m, n)不會再返回0
    return abs(lcm);          //由於返回0的狀況在前面已經排除
}

//求一組數據的最小公倍數(不安全,不推薦使用)
int TYCppStdLib::GetLCM(const int *p, int count)
{ 
    if(!p || count<2)
        return 0;
    int lcm=p[0];
    for(int i=1; i!=count; i++)
        lcm=GetLCM(lcm, p[i]);
    return abs(lcm);
}

//求一組數據的最小公倍數(安全,推薦使用)
int TYCppStdLib::GetLCM(vector<int> &vec)
{
    int vsize=vec.size();
    if(vsize<2)
        return 0;
    int lcm=vec[0];
    for(int i=1; i!=vsize; i++)
        lcm=GetLCM(lcm, vec[i]);
    return abs(lcm);
}

//求階乘(13之內)(非遞歸)
int TYCppStdLib::GetFactorial(int n)
{
    if(n<0 || n>13)
        return 0;
    if(n<2)
        return 1;
    int fac=1;
    for(int i=2; i<=n; i++)
        fac=fac*i;
    return fac;
}

//如下爲求階乘的遞歸實現,兩種方法效率幾乎相同
//但爲減少函數重複調用開銷,選擇非遞歸方式

//求階乘(13之內)(遞歸)
// int TYCppStdLib::GetFactorial(int n)
// {
    // if(n<0 || n>13)
        // return 0;
    // if(n<2)
        // return 1;
    // return GetFactorial(n-1)*n;
// }

//得到0到n的階乘結果(n超過13時設爲13)
//這裏不用到GetFactorial,由於效率過低
void TYCppStdLib::FacVecInt(vector<int> &vec, int n)
{
    vec.clear();
    if(n<0)
        return;
    vec.push_back(1);
    if(0==n)
        return;
    vec.push_back(1);
    if(1==n)
        return;
    if(n>13)
        n=13;
    int fac=1;
    for(int i=1; i!=n; i++)
    {
        fac=fac*(i+1);
        vec.push_back(fac);
    }
}

//求整數的逆序數,如6589返回9856
int TYCppStdLib::InversionData(int n)
{
    int s=0;
    while(n)
    {
        s=10*s+n%10;
        n=n/10;
    }
    return s;
}

//獲取數字的位數
int TYCppStdLib::DivideDigit(int n)
{
    n=abs(n);
    if(0==n)
        return 1;
    int num=0;
    while(n)
    {
        n=n/10;
        num++;
    }
    return num;
}

//獲取數字的各個位上的數值,並返回分離出的數字個數
int TYCppStdLib::DivideDigit(
    int n,               //待求數字
    vector<int> &vec,    //存儲結果
    bool forward         //ture:高位在前存儲,false:低位在前存儲
)
{
    n=abs(n);
    vec.clear();
    int num=0;
    if(0==n)
    {
        vec.push_back(0);
        return 1;
    }
    if(forward)
    {
        while(n)
        {
            vec.insert(vec.begin(), n%10);
            n=n/10;
            num++;
        }
    }
    else
    {
        while(n)
        {
            vec.push_back(n%10);
            n=n/10;
            num++;
        }
    }
    return num;
}

//如下兩個函數的功能已經被集成到上面的函數中

//獲取數字的各個位上的數值(高位在前),並返回分離出的數字個數
// int TYCppStdLib::DivideDigitA(int n, vector<int> &vec)
// {
    // n=abs(n);
    // vec.clear();
    // if(0==n)
    // {
        // vec.push_back(0);
        // return 1;
    // }
    // int num=0;
    // while(n)
    // {
        // vec.insert(vec.begin(), n%10);
        // n=n/10;
        // num++;
    // }
    // return num;
// }

//獲取數字的各個位上的數值(低位在前),並返回分離出的數字個數
// int TYCppStdLib::DivideDigitB(int n, vector<int> &vec)
// {
    // n=abs(n);
    // vec.clear();
    // if(0==n)
    // {
        // vec.push_back(0);
        // return 1;
    // }
    // int num=0;
    // while(n)
    // {
        // vec.push_back(n%10);
        // n=n/10;
        // num++;
    // }
    // return num;
// }

//將一組數據按位合成一個數
int TYCppStdLib::JoinDigit(
        const vector<int> &vec, //一組數據
        bool forward,           //ture:高位在前,false:低位在前
        bool onlyBit            //數據中的每一位是否只取其個位
)
{
    if(vec.empty())
        return 0;
    int sum=0;
    vector<int>::size_type si;
    if(forward)
    {
        for(si=0; si!=vec.size(); si++)
        {
            if(onlyBit)
                sum=sum*10+(vec[si]%10);
            else
                sum=sum*10+vec[si];
        }
    }
    else
    {
        for(si=vec.size()-1; si!=-1; si--)
        {
            if(onlyBit)
                sum=sum*10+(vec[si]%10);
            else
                sum=sum*10+vec[si];
        }
    }
    return sum;
}

//生成一組隨機數據(用隨機數據初始化vector<int>)
void TYCppStdLib::RandomVecInt(
    vector<int> &vec,      //存放數據的容器
    int num,               //產生數據的個數
    int minValue,          //設置數據的最大值(包含)
    int maxValue,          //設置數據的最大值(包含)
    bool isPrime           //產生的數據是否必須爲質數
)
{
    vec.clear();
    if (num<1)
        return;
    vec.resize(num);
    generate(vec.begin(), vec.end(), 
             Random_cls(minValue, maxValue, isPrime));
    return;
}

//求Fibonacci數列的第N項 F1=1 F2=1 F3=2 ……(非遞歸)
int TYCppStdLib::Fibonacci(int n)
{
    if(n<1)
        return 0;
    if(1==n || 2==n)
        return 1;
    int fib;
    int n_1=1;
    int n_2=1;
    for(int i=2; i!=n; i++)
    {
        fib=n_1+n_2;
        n_2=n_1;
        n_1=fib;
    }
    return fib;
}

//如下爲求Fibonacci數列的第N項的遞歸實現,兩種方法效率幾乎相同
//但爲減少函數重複調用開銷,選擇非遞歸方式

//求Fibonacci數列的第N項 F1=1 F2=1 F3=2 ……(遞歸)
// int TYCppStdLib::Fibonacci(int n)
// {
    // if(n<1)
        // return 0;
    // if(1==n || 2==n)
        // return 1;
    // return (Fibonacci(n-1)+Fibonacci(n-2));
// }

//求Fibonacci數列的前N項(用Fibonacci數列初始化vector<int>)
//這裏不用到Fibonacci函數,由於效率過低
void TYCppStdLib::FibVecInt(vector<int> &vec, int num)
{
    vec.clear();
    if(num<1)
        return;
    vec.push_back(1);
    if(1==num)
        return;
    vec.push_back(1);
    if(2==num)
        return;
    int n;
    int n_1=1;
    int n_2=1;
    for(int i=2; i!=num; i++)
    {
        n=n_1+n_2;
        vec.push_back(n);
        n_2=n_1;
        n_1=n;
    }
}

// 僅爲測試
// template<typename T>
// T TYCppStdLib::GetTest(T n)
// {
    // return (-n);
// }

/*- ==========================================================
*     文件名  :MathFunc.hpp
*     開發人員:袁培榮
*     當前版本:1.3.3.2595 (第1次發佈,功能不斷增長中)
*     建立時間:2012-05-28
*     修改時間:2012-05-30
*     功能說明:加強的數學函數庫的模板實現
*     版權說明:版權全部 袁培榮 YuanPeirong 
*     編譯環境:Windows 7(x64) SP1 簡體中文專業版
*     編譯器:  Visual Studio 2010 SP1(中文旗艦版)
                MinGW 20120426 GNU GCC 4.6.2
                Visual C++ 6.0 SP6(中文企業版)
- ==========================================================*/

//編譯測試狀況:
// 1.Visual Studio 2010 SP1(中文旗艦版):
//   在Release和Debug下都編譯經過,測試運行正常。
// 2.MinGW 20120426 GNU GCC 4.6.2:
//   編譯經過,測試運行正常。
// 3.Visual C++ 6.0 SP6(中文企業版)
//   未測試。

#ifndef MathFunc_HPP_TYCppStdLib  //防止頭文件重複包含
#define MathFunc_HPP_TYCppStdLib

#include <iostream>
//求一組數據的和
//export template<typename T>
template<typename T>
T TYCppStdLib::GetSum(const vector<T> &vec)
{
    T sum=accumulate(vec.begin(), vec.end(), static_cast<T>(0));
    return sum;
}

//初始實現版本
// template<typename T>
// T TYCppStdLib::GetSum(
      // typename vector<T>::const_iterator start
    // , typename vector<T>::const_iterator end
// )
// {
    // T sum=accumulate(start, end, static_cast<T>(0));
    // return sum;
// }

//更加泛化的實現版本
template<typename T, typename InputIterator>
T TYCppStdLib::GetSum(InputIterator start, InputIterator end)
{
    T sum=accumulate(start, end, static_cast<T>(0));
    return sum;
}

//求一組數據的算術平均數(涉及到除法,所以返回值轉爲double,下同)
template<typename T>
double TYCppStdLib::GetMean(const vector<T> &vec)
{
    int num=static_cast<int>(vec.size());
    if(0==num)
        return static_cast<double>(0);
    T sum=accumulate(vec.begin(), vec.end(), static_cast<T>(0));
    return (static_cast<double>(sum))/(static_cast<double>(num));
}

//求一組數據的方差(第1正確實現版本)
// template<typename T>
// double TYCppStdLib::GetVariance(const vector<T> &vec)
// {
    // double mean=GetMean(vec);
    // vector<double> temp;
    // for(vector<double>::size_type si=0; si!=vec.size(); si++)
    // {                                            // vec爲空也不會出錯
        // double vsi=static_cast<double>(vec[si]);
        // temp.push_back((vsi-mean)*(vsi-mean));
    // }
    // return GetMean(temp);
// }

//求一組數據的方差(優化實現版本)
//===
//優化緣由:
// 1.避免構造臨時vector,
// 2.避免調用外部函數對臨時vector的遍歷
// 3.減小外部函數的調用次數
// 4.更快的處理空數據
// 5.減小內存佔用
//===
template<typename T>
double TYCppStdLib::GetVariance(const vector<T> &vec)
{
    int num=static_cast<int>(vec.size());
    if(0==num)
        return static_cast<double>(0);
    double mean=GetMean(vec);
    double sum=0;             //sum和平均數有關,而平均數已是double了
    for(vector<double>::size_type si=0; si!=vec.size(); si++)
    {
        double vsi=static_cast<double>(vec[si]);
        sum=sum+((vsi-mean)*(vsi-mean));
    }
    return sum/(static_cast<double>(num));
}


//求一組數據的標準差
template<typename T>
double TYCppStdLib::GetStDev(const vector<T> &vec)
{
    return sqrt(GetVariance(vec));
}

//將一組數據反序,並覆蓋原數據
template<typename T>
void TYCppStdLib::InverseVec(vector<T> &vec)  //結果覆蓋原數據
{
    vector<T> vec2;
    for(typename vector<T>::size_type si=0; si!=vec.size(); si++)
        vec2.insert(vec2.begin(), vec[si]);
    vec=vec2;
    return;
}

//將一組數據反序,不覆蓋原數據
template<typename T>
void TYCppStdLib::InverseVec(
    const vector<T> &vec1,     //原數據
    vector<T> &vec2            //逆序數據
)
{
    vec2.clear();
    for(typename vector<T>::size_type si=0; si!=vec1.size(); si++)
        vec2.insert(vec2.begin(), vec1[si]);
    return;
}

//比較兩個數的大小
template<typename T>
bool TYCppStdLib::IsBig(const T &m, const T &n)
{
    return m>=n;
}
template<typename T>
bool TYCppStdLib::IsSmall(const T &m, const T &n)
{
    return m<n;
}

//將一組數據進行排序,並覆蓋原數據
template<typename T>
void TYCppStdLib::SortVec(
    vector<T> &vec,        //結果覆蓋原數據
    bool smallToBig,       //ture:從小到大,false:從大到小
    bool eraseUnique       //ture:去除重複值,false:不去除重複值
)
{
    if(smallToBig)
        sort(vec.begin(), vec.end(), IsSmall<T>); //標準庫有less和less_equal
        //也能夠寫成sort(vec.begin(), vec.end());
        //但在MinGW和VS2010的Release下編譯經過,運行正常
        //VS2010的Debug下編譯經過,運行錯誤
        //但寫成sort(vec.begin(), vec.end(), IsSmall<T>);
        //在MinGW和VS2010的Release,Debug下都編譯經過而運行正常
    else
        sort(vec.begin(), vec.end(), IsBig<T>); //標準庫有greater和greater_equal
    if(eraseUnique)
    {
        typename vector<T>::iterator end_unique=
            unique(vec.begin(), vec.end());
        vec.erase(end_unique, vec.end());
    }
}
//將一組數據進行排序,不覆蓋原數據
template<typename T>
void TYCppStdLib::SortVec(
    const vector<T> &vec1,   //原數據
    vector<T> &vec2,         //逆序數據
    bool smallToBig,         //ture:從小到大,false:從大到小
    bool eraseUnique         //ture:去除重複值,false:不去除重複值
)
{
    vec2=vec1;
    SortVec(vec2, smallToBig, eraseUnique);
}

//生成等差數列(Arithmetic Sequence)(用等差數列初始化vector<T>)
template<typename T>
void TYCppStdLib::AriVecT(
    vector<T> &vec, //存儲數據
    T fisrt,        //首項
    T tolerance,    //公差
    T num           //項數
)
{
    vec.clear();
    if(num<1)
        return;
    for(int i=0; i!=num; i++)
    {
        vec.push_back(fisrt);
        fisrt=fisrt+tolerance;
    }
}

//生成等比數列(Geometric Sequence)(用等比數列初始化vector<T>)
template<typename T>
void TYCppStdLib::GeoVecT(
    vector<T> &vec, //存儲數據
    T fisrt,        //首項
    T comRatio,     //公比
    T num           //項數
)
{
    vec.clear();
    if(num<1)
        return;
    for(int i=0; i!=num; i++)
    {
        vec.push_back(fisrt);
        fisrt=fisrt*comRatio;
    }
}

#endif

/*- ==========================================================
*     文件名  :test1.cpp
*     開發人員:袁培榮
*     當前版本:1.3.3.2595 (第1次發佈,功能不斷增長中)
*     建立時間:2012-05-28
*     修改時間:2012-05-30
*     功能說明:加強的數學函數庫的測試代碼
*     版權說明:版權全部 袁培榮 YuanPeirong 
*     編譯環境:Windows 7(x64) SP1 簡體中文專業版
*     編譯器:  Visual Studio 2010 SP1(中文旗艦版)
                MinGW 20120426 GNU GCC 4.6.2
                Visual C++ 6.0 SP6(中文企業版)
- ==========================================================*/

//編譯測試狀況:
// 1.Visual Studio 2010 SP1(中文旗艦版):
//   在Release和Debug下都編譯經過,測試運行正常。
// 2.MinGW 20120426 GNU GCC 4.6.2:
//   編譯經過,測試運行正常。
// 3.Visual C++ 6.0 SP6(中文企業版)
//   未測試。

#include <iostream>
#include "../Include/MathFunc.h"
//#include <vector>  //MathFunc.h中已經包含此頭文件


using namespace std;
using namespace TYCppStdLib;

template<typename T> //僅爲方便輸出容器的每一項
void CoutVecT(const vector<T> &vec);

int main(int argc, char* argv[])
{
    if(IsPrime(5))
        cout<<"5是質數"<<endl;
    else
        cout<<"5不是質數"<<endl;
        
    if(IsPrime(9))
        cout<<"9是質數"<<endl;
    else
        cout<<"9不是質數"<<endl;
        
    if(IsSquare(5))
        cout<<"5是徹底平方數"<<endl;
    else
        cout<<"5不是徹底平方數"<<endl;
        
    if(IsSquare(9))
        cout<<"9是徹底平方數"<<endl;
    else
        cout<<"9不是徹底平方數"<<endl;
    
    cout<<"27和18的最大公約數是:"<<GetGCD(27, 18)<<endl;
    cout<<"27和18的最小公倍數是:"<<GetLCM(27, 18)<<endl;
    
    int arr[5]={6,9,36,18,72};
    cout<<"數組arr的最大公約數是:"<<GetGCD(arr, 5)<<endl;
    cout<<"數組arr的最小公倍數是:"<<GetLCM(arr, 5)<<endl;
    
    vector<int> v1;
    v1.push_back(6);
    v1.push_back(9);
    v1.push_back(36);
    v1.push_back(18);
    v1.push_back(72);
    cout<<"容器v1的最大公約數是:"<<GetGCD(v1)<<endl;
    cout<<"容器v1的最小公倍數是:"<<GetLCM(v1)<<endl;
    
    cout<<"-1的階乘是:"<<GetFactorial(-1)<<endl;
    cout<<"0的階乘是:"<<GetFactorial(0)<<endl;
    cout<<"1的階乘是:"<<GetFactorial(1)<<endl;
    cout<<"2的階乘是:"<<GetFactorial(2)<<endl;
    cout<<"5的階乘是:"<<GetFactorial(5)<<endl;
    cout<<"13的階乘是:"<<GetFactorial(13)<<endl;
    cout<<"15的階乘是:"<<GetFactorial(15)<<endl;
    cout<<"0-15的階乘爲:"<<endl;
    vector<int> fac(10);
    FacVecInt(fac, 15);
    CoutVecT(fac);
    
    cout<<"-1234的逆序數是"<<InversionData(-1234)<<endl;
    cout<<"-1的逆序數是"<<InversionData(-1)<<endl;
    cout<<"0的逆序數是"<<InversionData(0)<<endl;
    cout<<"1的逆序數是"<<InversionData(1)<<endl;
    cout<<"1234的逆序數是"<<InversionData(1234)<<endl;
    cout<<"123456的逆序數是"<<InversionData(123456)<<endl;
    
    vector<int> v2(10);
    int i=17;
    cout<<GetPrime(i)<<endl;
    cout<<i<<"之內有"<<GetPrime(i, v2)<<"個質數"<<endl;
    CoutVecT(v2);
    
    vector<int> v3(10,9);
    vector<int> v4;
    vector<int> v5;
    
    v5.push_back(2); //2+4+6=12 平均4
    v5.push_back(4); //方差 (4+0+4)/3
    v5.push_back(6);  
    
    cout<<"v3和:"<<GetSum(v3)<<endl;
    cout<<"v4和:"<<GetSum(v4)<<endl;
    cout<<"v5和:"<<GetSum(v5)<<endl;
    
    vector<int>::iterator is=v3.begin();
    vector<int>::iterator ie=v3.end();
    is++;
    is++;
    cout<<"v3後七項和:"<<GetSum<int>(is, ie)<<endl;
    
    cout<<"v3平均:"<<GetMean(v3)<<endl;
    cout<<"v4平均:"<<GetMean(v4)<<endl;
    cout<<"v5平均:"<<GetMean(v5)<<endl;
    
    cout<<"v3方差:"<<GetVariance(v3)<<endl;
    cout<<"v4方差:"<<GetVariance(v4)<<endl;
    cout<<"v5方差:"<<GetVariance(v5)<<endl;
    
    cout<<"v3標準差:"<<GetStDev(v3)<<endl;
    cout<<"v4標準差:"<<GetStDev(v4)<<endl;
    cout<<"v5標準差:"<<GetStDev(v5)<<endl;
    
    cout<<"數字分離"<<endl;
    int i2=256;
    vector<int> v6(10,1);
    vector<int> v7(10,2);
    cout<<DivideDigit(i2)<<endl;
    cout<<DivideDigit(i2, v6)<<endl;
    cout<<DivideDigit(i2, v7, false)<<endl;
    CoutVecT(v6);
    CoutVecT(v7);
    
    cout<<"數字合成"<<endl;
    vector<int> v8;
    v8.push_back(15);
    v8.push_back(16);
    cout<<JoinDigit(v8,true, true)<<endl;
    cout<<JoinDigit(v8,true, false)<<endl;
    cout<<JoinDigit(v8,false, true)<<endl;
    cout<<JoinDigit(v8,false, false)<<endl;
    
    cout<<"數據反序"<<endl;
    vector<int> v9;
    v9.push_back(11);
    v9.push_back(22);
    v9.push_back(33);
    InverseVec(v9);
    CoutVecT(v9);

    vector<int> v10;
    v10.push_back(11);
    v10.push_back(22);
    v10.push_back(33);
    vector<int> v11(20);
    InverseVec(v10, v11);
    CoutVecT(v10);
    CoutVecT(v11);
    

    cout<<"測試隨機數"<<endl;
    for(int ii=0; ii<5; ii++)
        cout<<Random(0, 50, true)<<" ";
    cout<<endl;
    
    cout<<"測試數據排序"<<endl;
    vector<int> v12, v13;
    RandomVecInt(v12, 10,0, 20);
    CoutVecT(v12);
    SortVec(v12, v13, true, true);
    CoutVecT(v12);
    CoutVecT(v13);
    
    cout<<"等差數列:"<<endl;
    vector<int> v14;
    AriVecT(v14, 1, 2, 10);
    CoutVecT(v14);
    
    cout<<"等比數列:"<<endl;
    vector<int> v15;
    GeoVecT(v15, 1, 2, 10);
    CoutVecT(v15);
    
    cout<<"測試Fibonacci():"<<endl;
    cout<<"Fibonacci(-1)="<<Fibonacci(-1)<<endl;
    cout<<"Fibonacci(-1)="<<Fibonacci(-1)<<endl;
    for(int fib=1; fib<11; fib++)
        cout<<Fibonacci(fib)<<" ";
    cout<<endl;
    
    cout<<"測試FibVecInt:"<<endl;
    vector<int> v16;
    FibVecInt(v16,10);
    CoutVecT(v16);
    
    return 0;
}

//僅爲方便輸出容器的每一項
template<typename T>
void CoutVecT(const vector<T> &vec)
{
    for(typename vector<T>::size_type si=0; si!=vec.size(); si++)
        cout<<vec[si]<<" ";
    cout<<endl;
}

//編譯命令:
// g++ MathFunc.cpp test1.cpp -o test1 && test1 -std=c++11(啓用C++11特性,在此不須要)
// g++ MathFunc.cpp test1.cpp -o test1 && test1

//=============
//運行結果:
//=============
// 5是質數
// 9不是質數
// 5不是徹底平方數
// 9是徹底平方數
// 27和18的最大公約數是:9
// 27和18的最小公倍數是:54
// 數組arr的最大公約數是:3
// 數組arr的最小公倍數是:72
// 容器v1的最大公約數是:3
// 容器v1的最小公倍數是:72
// -1的階乘是:0
// 0的階乘是:1
// 1的階乘是:1
// 2的階乘是:2
// 5的階乘是:120
// 13的階乘是:1932053504
// 15的階乘是:0
// 0-15的階乘爲:
// 1 1 2 6 24 120 720 5040 40320 362880 3628800 39916800 479001600 1932053504 
// -1234的逆序數是-4321
// -1的逆序數是-1
// 0的逆序數是0
// 1的逆序數是1
// 1234的逆序數是4321
// 123456的逆序數是654321
// 7
// 17之內有7個質數
// 2 3 5 7 11 13 17 
// v3和:90
// v4和:0
// v5和:12
// v3後七項和:72
// v3平均:9
// v4平均:0
// v5平均:4
// v3方差:0
// v4方差:0
// v5方差:2.66667
// v3標準差:0
// v4標準差:0
// v5標準差:1.63299
// 數字分離
// 3
// 3
// 3
// 2 5 6 
// 6 5 2 
// 數字合成
// 56
// 166
// 65
// 175
// 數據反序
// 33 22 11 
// 11 22 33 
// 33 22 11 
// 測試隨機數
// 11 7 47 7 31 
// 測試數據排序
// 20 9 14 2 13 15 3 10 20 17 
// 20 9 14 2 13 15 3 10 20 17 
// 2 3 9 10 13 14 15 17 20 
// 等差數列:
// 1 3 5 7 9 11 13 15 17 19 
// 等比數列:
// 1 2 4 8 16 32 64 128 256 512 
// 測試Fibonacci():
// Fibonacci(-1)=0
// Fibonacci(-1)=0
// 1 1 2 3 5 8 13 21 34 55 
// 測試FibVecInt:
// 1 1 2 3 5 8 13 21 34 55
//=============

01 #TYSoft GNU GCC MinGW g++ Makefile
02 #加強的數學函數庫的測試
03
04 #=====設置編譯器選項=====
05 CXX = g++
06 CCFLAGS =
07 #-ansi -W -Wall
08 #=====設置文件變量=====
09 SOFTNMAE = TYtest
10 OBJECTS = MathFunc.o test1.o
11 LOCFLAGS = ../Include/MathFunc.h
12 #======================
13
14 #=====將.o文件link成.exe文件=====
15 $(SOFTNMAE) : $(OBJECTS)
16     $(CXX) $(CCFLAGS) $(OBJECTS) -o $(SOFTNMAE)
17
18 #=====將.cpp文件編譯成.o文件=====
19 MathFunc.o : $(LOCFLAGS)
20 test1.o : $(LOCFLAGS)
21
22 #=====清理文件=====
23 .PHONY : clean
24 clean :
25     -rm $(SOFTNMAE) $(OBJECTS)
相關文章
相關標籤/搜索