VC++の使い方

VC++の使い方 > VC++ Tips > シンプルな多倍長ライブラリ
このページの内容
多倍長とは
この多倍長ライブラリの特徴
ソース
ありがたいスポンサー様
All About ソフトウエアエンジニア
ネットで8%割引!自動車保険はアメリカンホーム・ダイレクト
人生の「チャンス」と「ピンチ」にモビット!
保険料が一生上がらない、保険料最大50%割引の一生涯の医療保険!

多倍長とは

シミュレーションなどで小数点を含む数値を扱うときは、fload か double を用いるのが普通ですが、double だと 1.7×10-308から 1.7×10308までしか表現できません。これより小さな値や大きな値を扱いたい場合はどうしたらよいでしょう。

そこで多倍長の登場です。数値を表わすために独自実装するのです。ここでは、C++ を使って実装してみました。

この多倍長ライブラリの特徴

シンプルさ。それだけです。

機能豊富なものが欲しい人はC++による多倍長計算ライブラリなど色々なものが公開されています。これらのライブラリでは、計算速度が早かったり、多倍長の sin , cos に対応していたり、とにかく機能豊富です。ただし、ソースが膨大なため、自分のプログラムに組み込むにはやや抵抗があります。

気軽に多倍長を使いたい人には、このライブラリが向いているでしょう。四則演算と入出力しか搭載していません。その分、シンプルで、ソースも理解しやすいと思います。

ソース

Double.h と Double.cpp から出来ています。誰が作っても一緒だと思うので、特に著作権は主張しません。仮数部を 0〜1 の double で表わし、指数部を int で表わしています。だいたい ±21億桁まで表現できますよ(にやり

// Double.h
// 多倍長小数クラス
//============================================================================//
// 更新:02/12/26(木)
// 概要:なし。
// 補足:なし。
//============================================================================//

#ifndef  __DOUBLE_H__
#define  __DOUBLE_H__

#include <iostream>
using namespace std;


class Double
{
	double	dblMantissa ;	// 仮数
	int	intExponent ;	// 指数

public:
// コンストラクタおよびデストラクタ
	Double( double = 0) ;
	Double( const Double&) ;
	~Double() ;

// 設定
	void SetDouble( double) ;
private:
	void Validate( double) ;


// 演算
	friend ostream &operator<<(ostream &, const Double &);
	friend istream &operator>>(istream &, Double &);
	friend const Double operator+(const Double &, const Double &) ;
	friend const Double operator-(const Double &, const Double &) ;
	friend const Double operator*(const Double &, const Double &) ;
	friend const Double operator/(const Double &, const Double &) ;
	friend bool operator==(const Double &, const Double &);
	friend bool operator==(const Double &, double);
	friend bool operator==(double, const Double &);
	friend bool operator!=(const Double &, const Double &);
	friend bool operator!=(const Double &, double);
	friend bool operator!=(double, const Double &);

public:
	Double& operator=( const Double&) ;
	Double& operator+=(const Double&);
	Double& operator-=(const Double&);
	Double& operator*=(const Double&);
	Double& operator/=(const Double&);
	operator double() const ;
} ;

#endif
// Double.cpp
// 多倍長小数クラス
//============================================================================//
// 更新:02/12/26(木)
// 概要:なし。
// 補足:なし。
//============================================================================//

#include "Double.h"


/******************************************************************************/
//		コンストラクタおよびデストラクタ
/******************************************************************************/
// コンストラクタ
//============================================================================//
// 更新:02/12/25(水)
// 概要:なし。
// 補足:なし。
//============================================================================//

Double::Double( double d) 
{
	SetDouble( d) ;
}


/******************************************************************************/
// コピーコンストラクタ
//============================================================================//
// 更新:02/12/26(木)
// 概要:なし。
// 補足:なし。
//============================================================================//

Double::Double( const Double& d)
: dblMantissa( d.dblMantissa), intExponent( d.intExponent)
{
}


/******************************************************************************/
// デストラクタ
//============================================================================//
// 更新:02/12/25(水)
// 概要:なし。
// 補足:なし。
//============================================================================//

Double::~Double() 
{
}



/******************************************************************************/
//		設定
/******************************************************************************/
// double から設定
//============================================================================//
// 更新:02/12/25(水)
// 概要:なし。
// 補足:なし。
//============================================================================//

void Double::SetDouble( double d)
{
	intExponent = 0 ;
	Validate( d) ;
}


/******************************************************************************/
// 仮数部を正当な値にする
//============================================================================//
// 更新:02/12/26(木)
// 概要:1.0 <= 仮数部 < 10.0 を満たすようにする。
// 補足:なし。
//============================================================================//

void Double::Validate( double d)
{
	// d が 0 の時は特別扱い
	if( d == 0)
	{
		dblMantissa = 0 ;
		intExponent = 0 ;
		return ;
	}

	double dblAbs = ( d > 0 ? d : -d) ;
	if( dblAbs >= 10.0)
	{
		while( dblAbs > 10.0)
		{
			dblAbs /= 10.0 ;
			intExponent++ ;
		}
	}
	else if( dblAbs < 1.0)
	{
		while( dblAbs < 1.0)
		{
			dblAbs *= 10.0 ;
			intExponent-- ;
		}
	}

	dblMantissa = ( d > 0 ? dblAbs : -dblAbs) ;
}


/******************************************************************************/
//		演算子
/******************************************************************************/
// 出力
//============================================================================//
// 更新:02/12/25(水)
// 概要:なし。
// 補足:なし。
//============================================================================//

ostream &operator<<(ostream& stream, const Double& d)
{
	ios_base::fmtflags iosOldSetting = cout.flags() ;
	cout.setf( ios::showpoint) ;
	cout.setf(ios::fixed) ;
	cout.precision( 4) ;
	cout.width( 8) ;
	stream << d.dblMantissa << "e" << d.intExponent ;
	cout.flags( iosOldSetting) ;
	return stream ;
}


/******************************************************************************/
// 入力
//============================================================================//
// 更新:02/12/25(水)
// 概要:なし。
// 補足:とりあえずは一端 double で取り込む。
//============================================================================//

istream &operator>>(istream& stream, Double& dbl)
{
	double d ;
	stream >> d ;
	dbl.SetDouble( d) ;
	return stream ;
}


/******************************************************************************/
// 加算
//============================================================================//
// 更新:02/12/26(木)
// 概要:なし。
// 補足:なし。
//============================================================================//

const Double operator+(const Double& left, const Double& right)
{
	Double d = left ;
	d += right ;

	return d ;
}


/******************************************************************************/
// 減算
//============================================================================//
// 更新:02/12/26(木)
// 概要:なし。
// 補足:なし。
//============================================================================//

const Double operator-(const Double& left, const Double& right)
{
	Double d = left ;
	d -= right ;

	return d ;
}


/******************************************************************************/
// 乗算
//============================================================================//
// 更新:02/12/25(水)
// 概要:なし。
// 補足:*= を使って実装。
//============================================================================//

const Double operator*(const Double& left, const Double& right)
{
	Double dblRet = left ;
	dblRet *= right ;
	return dblRet ;
}


/******************************************************************************/
// 除算
//============================================================================//
// 更新:02/12/25(水)
// 概要:なし。
// 補足:*= を使って実装。
//============================================================================//

const Double operator/(const Double& left, const Double& right)
{
	Double dblRet = left ;
	dblRet /= right ;
	return dblRet ;
}


/******************************************************************************/
// 等しいか
//============================================================================//
// 更新:02/12/26(木)
// 概要:なし。
// 補足:なし。
//============================================================================//

bool operator==( const Double& left, const Double& right)
{
	if( left.dblMantissa == 0)
	{
		return right.dblMantissa == 0 ;
	}
	else
	{
		return left.intExponent == right.intExponent && left.dblMantissa == right.dblMantissa ;
	}
}

bool operator==( const Double& left, double right)
{
	return left == Double( right) ;
}

bool operator==( double& left, const Double& right)
{
	return Double( left) == right ;
}


/******************************************************************************/
// 等しくないか
//============================================================================//
// 更新:02/12/26(木)
// 概要:なし。
// 補足:なし。
//============================================================================//

bool operator!=( const Double& left, const Double& right)
{
	return !( left == right) ;
}

bool operator!=( const Double& left, double right)
{
	return left != Double( right) ;
}

bool operator!=( double left, const Double& right)
{
	return Double( left) != right ;
}


/******************************************************************************/
//		メンバ関数の演算子オーバーロード
/******************************************************************************/
// 代入演算子
//============================================================================//
// 更新:02/12/26(木)
// 概要:なし。
// 補足:なし。
//============================================================================//

Double& Double::operator=( const Double& d)
{
	dblMantissa = d.dblMantissa ;
	intExponent = d.intExponent ;

	return *this ;
}


/******************************************************************************/
// 加算代入
//============================================================================//
// 更新:02/12/26(木)
// 概要:なし。
// 補足:加算時は大きい方にあわせるべし。
//============================================================================//

Double& Double::operator+=( const Double& right)
{
	// どちらかが 0 の時は特別
	if( dblMantissa == 0)
	{
		intExponent = right.intExponent ;
		dblMantissa = right.dblMantissa ;
		return *this ;
	}
	else if( right.dblMantissa == 0)
	{
		return *this ;
	}

	// 左辺が大きいとき
	if( intExponent >= right.intExponent)
	{
		double dblRightMantissa = right.dblMantissa ;
		for( int i = 0; i < intExponent - right.intExponent; i++)
		{
			dblRightMantissa /= 10.0 ;
		}

		dblMantissa += dblRightMantissa ;
	}
	// 右辺が大きいとき
	else
	{
		for( int i = 0; i < right.intExponent - intExponent; i++)
		{
			dblMantissa /= 10.0 ;
		}
		intExponent = right.intExponent ;
		dblMantissa += right.dblMantissa ;
	}

	Validate( dblMantissa) ;

	return *this ;
}


/******************************************************************************/
// 減算代入
//============================================================================//
// 更新:02/12/26(木)
// 概要:なし。
// 補足:なし。
//============================================================================//

Double& Double::operator-=(const Double& d)
{
	dblMantissa *= -1.0 ;
	*this += d ;
	dblMantissa *= -1.0 ;

	return *this ;
}


/******************************************************************************/
// 乗算代入
//============================================================================//
// 更新:02/12/26(木)
// 概要:なし。
// 補足:なし。
//============================================================================//

Double& Double::operator*=( const Double& right)
{
	intExponent += right.intExponent ;
	Validate( dblMantissa * right.dblMantissa) ;

	return *this ;
}


/******************************************************************************/
// 除算代入
//============================================================================//
// 更新:02/12/26(木)
// 概要:なし。
// 補足:ごめんやる気ない(藁。
//============================================================================//

Double& Double::operator/=( const Double& right)
{
	if( right.dblMantissa == 0)
	{
		cout << "Double : 0 divide exception.\n" ;
		abort() ;
	}

	intExponent -= right.intExponent ;
	Validate( dblMantissa / right.dblMantissa) ;

	return *this ;
}


/******************************************************************************/
// キャスト演算子
//============================================================================//
// 更新:02/12/26(木)
// 概要:なし。
// 補足:なし。
//============================================================================//

Double::operator double() const
{
	double d = dblMantissa ;
	int i = intExponent ;

	while( i != 0)
	{
		if( i > 0)
		{
			d *= 10.0 ;
			i-- ;
		}
		else
		{
			d /= 10.0 ;
			i++ ;
		}
	}

	return d ;
}