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