[[C++ BCD class の作成 (6)]]

* 乗算の導入(再) [#w69cfde8]
さて、[[C++ BCD class の作成 (3)]]で導入した乗算の std::vector<char>版を
作るのは容易である。

まずはテストプログラム
 // bcdtest4.cpp
 
 #include "bcd.h"
 
 int main(int argc, char* argv[])
 {
 	using namespace mylib;
 	if(argc != 3)
 	{
 		std::cout << "Usage: " << argv[0] << " int int" << std::endl;
 		return 1;
 	}
 	BCD bcd1(argv[1]);
 	BCD bcd2(argv[2]);
 	std::cout << bcd1 << " + " << bcd2 << " = " << bcd1 + bcd2 << std::endl;
 	std::cout << bcd1 << " - " << bcd2 << " = " << bcd1 - bcd2 << std::endl;
 	std::cout << bcd1 << " * " << bcd2 << " = " << bcd1 * bcd2 << std::endl;
 	return 0;
 }

** 実装 [#v91001eb]
ヘッダファイル(bcd.h)
 // bcd.h
 
 #ifndef BCD_H_INCLUDED
 #define BCD_H_INCLUDED
 
 #include <vector>
 #include <iostream>
 
 namespace mylib
 {
 
 class BCD
 {
 	// Global I/O operators
 	friend std::ostream& operator<<(std::ostream& os, const BCD& bcd);
 	friend BCD operator+(const BCD& a, const BCD& b);
 	friend BCD operator-(const BCD& a, const BCD& b);
 	friend BCD operator*(const BCD& a, const BCD& b);
 
 public:
 	BCD(const char* s = 0);
 	BCD(int n);
 
 protected:
 	static int abscmp(const BCD& a, const BCD& b);
 	static BCD absadd(const BCD& a, const BCD& b);
 	static BCD abssub(const BCD& a, const BCD& b);
 	static BCD absmul(const BCD& a, const BCD& b);
 
 protected:
 	bool m_neg;
 	int m_ndig;
 	std::vector<char> m_buf;
 };
 
 } // namespace
 
 #endif	// BCD_H_INCLUDED

本体(bcd.cpp)
 // bcd.cpp
 
 #include "bcd.h"
 
 namespace mylib
 {
 
 std::ostream&
 operator<<(std::ostream& os, const BCD& bcd)
 {
 	if(bcd.m_ndig > 0)
 	{
 		if(bcd.m_neg)
 			os << (char)'-';
 		for(int i = bcd.m_ndig; i > 0; i--)
 			os << (char)(bcd.m_buf[i - 1] | '0');
 	}
 	else
 		os << (char)'0';
 	return os;
 }
 
 BCD
 operator+(const BCD& a, const BCD& b)
 {
 	if(!a.m_neg && !b.m_neg)
 		return BCD::absadd(a, b);
 
 	if(a.m_neg && b.m_neg)
 	{
 		BCD c = BCD::absadd(a, b);
 		c.m_neg = true;
 		return c;
 	}
 	// different sign
 	if(a.m_neg)
 		return BCD::abssub(b, a);
 	return BCD::abssub(a, b);
 }
 
 BCD
 operator-(const BCD& a, const BCD& b)
 {
 	if(!a.m_neg && !b.m_neg)
 		return BCD::abssub(a, b);
 
 	if(a.m_neg && b.m_neg)
 		return BCD::abssub(b, a);
 
 	// different sign
 	if(a.m_neg)
 	{
 		BCD c = BCD::absadd(a, b);
 		c.m_neg = true;
 		return c;
 	}
 	return BCD::absadd(a, b);
 }
 
 BCD
 operator*(const BCD& a, const BCD& b)
 {
 	if(a.m_neg == b.m_neg)
 		return BCD::absmul(a, b);
 	BCD c = BCD::absmul(a, b);
 	c.m_neg = true;
 	return c;
 }
 
 BCD::BCD(const char* s)
 {
 	m_neg = false;
 	m_ndig = 0;
 	if(s == 0)
 		return;
 
 	int n = 0;
 	if(s[n] == '-')
 	{
 		m_neg = true;
 		n++;
 	}
 	else if(s[n] == '+')
 		n++;
 
 	int k = n;
 	while((s[n] >= '0') && (s[n] <= '9'))
 	{
 		m_ndig++;
 		n++;
 	}
 	if(m_ndig == 0)
 
 	while((k < n) && (s[k] == '0'))
 		k++;
 
 	if(k == n)
 		return;
 	m_ndig = n - k;
 
 	int k = m_ndig;
 	while(k)
 	while(n > k)
 	{
 		m_buf.push_back((char)(s[n - 1] - '0'));
 		n--; k--;
 		n--;
 	}
 }
 
 BCD::BCD(int n)
 {
 	m_neg = false;
 	m_ndig = 0;
 	if(n < 0)
 	{
 		n = -n;
 		m_neg = true;
 	}
 	while( n )
 	{
 		m_buf.push_back((char)(n % 10));
 		m_ndig++;
 		n = n / 10;
 	}
 }
 
 int
 BCD::abscmp(const BCD& a, const BCD& b)
 {
 	// returns
 	//    1   if abs(a) > abs(b)
 	//    0   if abs(a) == abs(b)
 	//   -1   if abs(a) < abs(b)
 
 	if(a.m_ndig > b.m_ndig)
 		return 1;
 	else if(a.m_ndig < b.m_ndig)
 		return (-1);
 
 	// same digits
 	if(a.m_ndig == 0)
 		return 0;	// both zero
 	for(int i = a.m_ndig - 1; i >= 0; i--)
 	{
 		if(a.m_buf[i] > b.m_buf[i])
 			return 1;
 		else if(a.m_buf[i] < b.m_buf[i])
 			return (-1);
 	}
 	return 0;
 }
 
 BCD
 BCD::absadd(const BCD& a, const BCD& b)
 {
 	BCD c;
 	int n1 = a.m_ndig;
 	int n2 = b.m_ndig;
 	int n = n1;
 	if(n2 > n1)
 		n = n2;
 	int iv = 0;
 	for(int i = 0; i < n; i++)
 	{
 		if(i < n1)
 			iv += (int)a.m_buf[i];
 		if(i < n2)
 			iv += (int)b.m_buf[i];
 		c.m_buf.push_back((char)(iv % 10));
 		c.m_ndig++;
 		iv = iv / 10;
 	}
 	if(iv)
 	{
 		c.m_buf.push_back((char)(iv % 10));
 		c.m_ndig++;
 	}
 	return c;
 }
 
 BCD
 BCD::abssub(const BCD& a, const BCD& b)
 {
 	BCD c;
 	int n1 = a.m_ndig;
 	int n2 = b.m_ndig;
 	int n = n1;
 	if(n2 > n1)
 		n = n2;
 	bool invert = false;
 	if(BCD::abscmp(a, b) < 0)
 		invert = true;
 	int iv = 0;
 	int borrow = 0;
 	for(int i = 0; i < n; i++)
 	{
 		if(invert)
 		{
 			if(i < n2)
 				iv = (int)b.m_buf[i];
 			else
 				iv = 0;
 			if(i < n1)
 				iv -= (int)a.m_buf[i];
 		}
 		else
 		{
 			if(i < n1)
 				iv = (int)a.m_buf[i];
 			else
 				iv = 0;
 			if(i < n2)
 				iv -= (int)b.m_buf[i];
 		}
 		iv -= borrow;
 		if(iv < 0)
 		{
 			iv += 10;
 			borrow = 1;
 		}
 		else
 			borrow = 0;
 		c.m_buf.push_back((char)(iv % 10));
 		if(iv)
 			c.m_ndig = i + 1;
 	}
 	if(invert)
 		c.m_neg = true;
 	return c;
 }
 
 BCD
 BCD::absmul(const BCD& a, const BCD& b)
 {
 	BCD c;	// Zero
 	if((a.m_ndig == 0) || (b.m_ndig == 0))
 		return c;
 
 	// Both are non-zero
 	for(int i = 0; i < (a.m_ndig + b.m_ndig); i++)
 		c.m_buf.push_back((char)0);
 	for(int j = 0; j < b.m_ndig; j++)
 	{
 		for(int i = 0; i < a.m_ndig; i++)
 		{
 			int iv = (int)a.m_buf[i] * (int)b.m_buf[j] + (int)c.m_buf[i + j];
 			c.m_buf[i + j] = (char)(iv % 10);
 			int k = i + j + 1;
 			while(iv > 9)
 			{
 				iv = (int)c.m_buf[k] + (iv / 10);
 				c.m_buf[k++] = (char)(iv % 10);
 			}
 		}
 	}
 	for(int i = 0; i < (a.m_ndig + b.m_ndig); i++)
 	{
 		if(c.m_buf[i] != 0)
 			c.m_ndig = i + 1;
 	}
 	return c;
 }
 
 } // namespace

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS