[[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