大整数类-实现加减法

上次写了一个“无符号大整数加法”,是比较容易的,这次实现了完整的大整数的加减法,支持有符号的!不过实现起来感觉不是很顺畅,感觉可以优化的地方还很多,先贴一下代码,日后再来优化。

另,思路主要是模拟手算的过程,计算方式在注释里有说清楚。

// BigInteger.h
#ifndef __BIG_INTEGER__H__
#define __BIG_INTEGER__H__

#include 
using namespace std;

class BigInteger {
public:
    BigInteger(string str);
    BigInteger add(const BigInteger& other);
    BigInteger sub(const BigInteger& other);
    friend ostream& operator << (ostream& out, BigInteger& num);

private:
    string m_data;
    bool m_isNeg;

private:
    static void align(string& str, int len);
    static bool strip(string& str);
    static bool isOKChar(char ch);
    static BigInteger addAbsoluteValue(const BigInteger& A, const BigInteger& B);
    static BigInteger subAbsoluteValue(const BigInteger& A, const BigInteger& B);
    static int compareAbsoluteValue(const BigInteger& A, const BigInteger& B);
};

#endif
// BigInteger.cpp
#include "BigInteger.h"
#include <assert.h>
#include 
using namespace std;


// 使一个表示数字的字符串对齐到len的长度,方便后续位对位的运算
void BigInteger::align(string& str, int len) {
    if (len > str.size())
        str.insert(0, len - str.size(), '0');
}


// 判断字符是否是合法的,即是否为数字或+-号
bool BigInteger::isOKChar(char ch) {
    return (ch >= '0' && ch <= '9') || (ch == '+') || (ch == '-');
}


// 使得字符串str合法化,并返回其正负符号
bool BigInteger::strip(string& str) {
    int left = 0, right = str.size() - 1;

    // 去除前缀中非法的字符
    while (left <= right && !isOKChar(str[left]))
        ++left;

    // 看看是否有符号
    bool isNeg = false;
    if (str[left] == '-' || str[left] == '+') {
        isNeg = str[left] == '-';
        ++left;
    }

    // 去掉前缀多余的0
    while (left <= right && str[left] == '0')
        ++left;

    // 去除后缀里非法的字符
    while (right >= left && !isOKChar(str[right]))
        --right;

    // 如果这个数字是0,那么应该保留一个0
    if (left > right)
        str = "0";
    else if (left != 0 || right != str.size() - 1)
        str = str.substr(left, right - left + 1);// 有改变才取子串
    return isNeg;
}


BigInteger::BigInteger(string str)
: m_data(str), m_isNeg(false) {
    m_isNeg = strip(m_data);
}


// 比较两个大整数的绝对值大小
int BigInteger::compareAbsoluteValue(const BigInteger& A, const BigInteger& B) {
    if (A.m_data == B.m_data)
        return 0;

    // 对数据的copy做处理
    string dataA = A.m_data, dataB = B.m_data;
    int len = max(dataA.size(), dataB.size()), borrow = 0;
    BigInteger::align(dataA, len);
    BigInteger::align(dataB, len);
    // 模拟手算的减法
    for (int i = len - 1; i >= 0; --i) {
        int delta = dataA[i] - dataB[i] - borrow;
        borrow = 0;
        while (delta < 0) {
            delta += 10;
            ++borrow;
        }
    }
    // 如果最后有借位,说明被减数是小于减数的!
    return (borrow == 0) ? 1 : -1;
}


// 调用这个函数,必须保证:A的绝对值比B的大
BigInteger BigInteger::subAbsoluteValue(const BigInteger& A, const BigInteger& B) {
    string dataA = A.m_data, dataB = B.m_data;
    int len = max(dataA.size(), dataB.size()), borrow = 0;
    BigInteger::align(dataA, len);
    BigInteger::align(dataB, len);
    string result(len, '0');
    for (int i = len-1; i >= 0; --i) {
        int delta = dataA[i] - dataB[i] - borrow;
        borrow = 0;
        while (delta < 0) {
            delta += 10;
            ++borrow;
        }
        result[i] += delta;
    }

    // 最后断言一下:要满足A的绝对值比B的大
    assert(borrow == 0);
    return BigInteger(result);
}


// 直接将两个数字的绝对值相加
BigInteger BigInteger::addAbsoluteValue(const BigInteger& A, const BigInteger& B) {
    string dataA = A.m_data, dataB = B.m_data;
    int len = max(dataA.size(), dataB.size());
    BigInteger::align(dataA, len);
    BigInteger::align(dataB, len);

    string result(len, '0');
    int toAdd = 0;
    for (int i = len-1; i >= 0; --i) {
        int sum = (dataA[i] - '0') + (dataB[i] - '0') + toAdd;
        toAdd = sum / 10;
        result[i] += sum % 10;
    }

    // 处理最后的进位
    if (toAdd > 0)
        result.insert(result.begin(), toAdd+'0');

    return BigInteger(result);
}


// 大整数加法
BigInteger BigInteger::add(const BigInteger& other) {
    // 加法:同号,结果=绝对值相加,符号取相同的符号
    if (m_isNeg == other.m_isNeg) {
        BigInteger result = addAbsoluteValue(*this, other);
        result.m_isNeg = m_isNeg;
        return result;
    } else {
        // 加法:异号,结果=大的绝对值-小的绝对值,符号取绝对值大的那个
        if (compareAbsoluteValue(*this, other) >= 0) {
            BigInteger result = subAbsoluteValue(*this, other);
            result.m_isNeg = m_isNeg;
            return result;
        } else {
            BigInteger result = subAbsoluteValue(other, *this);
            result.m_isNeg = other.m_isNeg;
            return result;
        }
    }
}


// 大整数减法
BigInteger BigInteger::sub(const BigInteger& other) {
    // 减法:异号,结果=绝对值相加,符号取被减数的符号
    if (m_isNeg != other.m_isNeg) {
        BigInteger result = addAbsoluteValue(*this, other);
        result.m_isNeg = m_isNeg;
        return result;
    } else {
        // 减法:同号,结果=大的绝对值-小的绝对值,符号取绝对值大的那个
        if (compareAbsoluteValue(*this, other) >= 0) {
            BigInteger result = subAbsoluteValue(*this, other);
            result.m_isNeg = m_isNeg;
            return result;
        } else {
            BigInteger result = subAbsoluteValue(other, *this);
            result.m_isNeg = !m_isNeg;
            return result;
        }
    }
}


// 输出大整数,包括符号位
ostream& operator << (ostream& out, BigInteger& num) {
    if (num.m_isNeg) {
        string pre(1, '-');
        out << pre;
    }
    out << num.m_data;
    return out;
}
// main.cpp
// 不懂规范化的测试是硬伤
#include 
#include "BigInteger.h"
using namespace std;


int main() {
    BigInteger A("+00123"), B(" -0666  "), C("9"), D("111"), E("1000"), F("101"), G("999"), H("0");
    BigInteger bi2 = C.add(D), bi3 = D.add(C), bi4 = F.sub(D), bi5 = E.sub(C), bi6 = G.add(D), bi7 = H.sub(G);
    cout << bi2 << ' ' << bi3 << ' ' << bi4 << ' ' << bi5 << ' ' << bi6 << ' ' << bi7 << endl;

    BigInteger bi8 = A.sub(A);
    cout << bi8 << endl;


    return 0;
}
objs = main.o BigInteger.o
CC = g++

out: $(objs)
    $(CC) -o out $(objs)

main.o: main.cpp
BigInteger.o: BigInteger.h


clean:
    rm *.o out

你可能感兴趣的:(算法,笔试面试)