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

* 符号付き、加算・減算の実装 [#tef9ed2b]
説明書くのが面倒になってきたので、符号付き、加算・減算まで実装したものを
出しておこう。

まずはテストプログラム
 // bcdtest3.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;
 	return 0;
 }

これから実行ファイルを作るには g++ の場合
 g++ bcdtest3.cpp bcd.cpp -o bcdtest3.exe

あるいは、Visual C++ では
 cl /W3 /EHsc bcdtest3.cpp bcd.cpp

ヘッダファイル
 // 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);
 
 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);
 
 protected:
 	bool m_neg;
 	int m_ndig;
 	std::vector<char> m_buf;
 };
 
 } // namespace
 
 #endif	// BCD_H_INCLUDED

本体
 // 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::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;
 }
 
 } // namespace

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