本節課主要講了大
然後講了時間複雜度的分析方法,以及分治法。作業題是:
使用karatsuba算法計算大數乘法:
So: what’s the product of the following two 64-digit numbers?
3141592653589793238462643383279502884197169399375105820974944592
2718281828459045235360287471352662497757247093699959574966967627
這兩個數應該是pi和e的64位。
小學學的計算的乘法複雜度是
代碼如下:
#include <iostream>
#include <ostream>
#include <istream>
#include <cstring>
using namespace std;
class uint128_base10_t {
public:
enum class HALF { HIGH, LOW };
static const int LENGTH = 128;
uint128_base10_t();
uint128_base10_t(const string &str);
~uint128_base10_t();
uint128_base10_t(const uint128_base10_t & d);
uint128_base10_t & operator = (const uint128_base10_t & d);
friend uint128_base10_t operator + (const uint128_base10_t &left, const uint128_base10_t &right);
friend uint128_base10_t operator - (const uint128_base10_t &left, const uint128_base10_t &right);
friend uint128_base10_t operator * (const uint128_base10_t &left, const uint128_base10_t &right);
friend uint128_base10_t operator << (uint128_base10_t &left, int i);
friend ostream& operator << (ostream &in, const uint128_base10_t &data);
friend bool operator < (const uint128_base10_t &left, const uint128_base10_t &right);
uint128_base10_t halfSplit(HALF h) const;
size_t getDataLength() const { return _length; };
inline const uint8_t *getData() const { return _data; };
private:
uint8_t *_data;
int _length;
size_t calcDataLength() const;
};
int main()
{
uint128_base10_t a(string("3141592653589793238462643383279502884197169399375105820974944592"));
uint128_base10_t b(string("2718281828459045235360287471352662497757247093699959574966967627"));
uint128_base10_t c = a*b;
cout << c << endl;
return 0;
}
uint128_base10_t::uint128_base10_t() {
_data = new uint8_t[LENGTH];
memset(_data, 0, LENGTH);
_length = 0;
}
uint128_base10_t::uint128_base10_t(const string &str) {
_data = new uint8_t[LENGTH];
memset(_data, 0, LENGTH);
size_t strLen = str.length();
for (int i(strLen-1); i >= 0; i--)
{
_data[i] = str[strLen - i - 1] - 0x30;
}
_length = strLen;
}
uint128_base10_t::~uint128_base10_t() {
delete[] _data;
_data = nullptr;
}
uint128_base10_t& uint128_base10_t::operator=(const uint128_base10_t &d) {
memset(_data, 0, LENGTH);
memcpy(_data, d.getData(), LENGTH);
_length = d.getDataLength();
return *this;
}
uint128_base10_t::uint128_base10_t(const uint128_base10_t &d) {
_data = new uint8_t[LENGTH];
memset(_data, 0, LENGTH);
memcpy(_data, d.getData(), LENGTH);
_length = d.getDataLength();
}
uint128_base10_t operator + (const uint128_base10_t &left, const uint128_base10_t &right) {
uint8_t carry(0);
uint128_base10_t result;
const uint8_t* leftData = left.getData();
const uint8_t* rightData = right.getData();
uint8_t* resultData = result._data;
for (int i(0); i < uint128_base10_t::LENGTH; i++) {
resultData[i] = leftData[i] + rightData[i] + carry;
carry = resultData[i] / 10;
resultData[i] = resultData[i] % 10;
}
result._length = result.calcDataLength();
return result;
}
uint128_base10_t operator - (const uint128_base10_t &left, const uint128_base10_t &right) {
uint128_base10_t result;
if (left < right) {
cout << "warning: left minus right but left is less than right, return zero" << endl;
}
else {
uint8_t borrow(0);
const uint8_t* leftData = left.getData();
const uint8_t* rightData = right.getData();
uint8_t* resultData = result._data;
for (int i(0); i < uint128_base10_t::LENGTH; i++) {
if (leftData[i] < rightData[i] + borrow) {
resultData[i] = leftData[i] + 10 - (rightData[i] + borrow);
borrow = 1;
}
else {
resultData[i] = leftData[i] - (rightData[i] + borrow);
borrow = 0;
}
}
}
result._length = result.calcDataLength();
return result;
}
bool operator < (const uint128_base10_t &left, const uint128_base10_t &right) {
const uint8_t* leftData = left.getData();
const uint8_t* rightData = right.getData();
bool ret = false;
for (int i(uint128_base10_t::LENGTH - 1); i >= 0; i--) {
if (leftData[i] < rightData[i]) {
ret = true;
break;
}
else if (leftData[i] > rightData[i]) {
ret = false;
break;
}
}
return ret;
}
size_t uint128_base10_t::calcDataLength() const {
int i;
for (i = LENGTH - 1; i >= 0; i--) {
if (_data[i] != 0) {
break;
}
}
if (i < 0) i = 0;
return i+1;
}
uint128_base10_t uint128_base10_t::halfSplit(HALF h) const{
uint128_base10_t result;
size_t length = getDataLength();
//if (length > 1 && length % 2 != 0) {
// cout << "warning: length = " << length << " is even" << endl;
//}
size_t even = (length % 2 != 0) ? 1 : 0;
size_t halfLength = length / 2 + even;
if (h == HALF::LOW) {
memcpy(result._data, _data, halfLength);
result._length = halfLength;
}
else {
memcpy(result._data, _data + halfLength, halfLength - even);
result._length = halfLength - even;
}
return result;
}
uint128_base10_t operator << (uint128_base10_t &left, int i) {
uint128_base10_t result;
for (int j(uint128_base10_t::LENGTH - 1); j >= 0 ; j--) {
if (j - i >= 0)
result._data[j] = left._data[j - i];
else
result._data[j] = 0;
}
result._length += i;
return result;
}
uint128_base10_t operator *(const uint128_base10_t &left, const uint128_base10_t &right) {
uint128_base10_t result;
cout << left << " * " << right << endl;
if (left.getDataLength() <= 1 && right.getDataLength() <= 1) {
uint8_t temp = left._data[0] * right._data[0];
result._data[2] = temp / 100;
result._data[1] = (temp / 10) % 10;
result._data[0] = temp % 10;
}
else {
uint128_base10_t a = left.halfSplit(uint128_base10_t::HALF::HIGH);
uint128_base10_t b = left.halfSplit(uint128_base10_t::HALF::LOW);
uint128_base10_t c = right.halfSplit(uint128_base10_t::HALF::HIGH);
uint128_base10_t d = right.halfSplit(uint128_base10_t::HALF::LOW);
uint128_base10_t ac = a*c;
int acShift = b.getDataLength() + d.getDataLength();
uint128_base10_t bd = b*d;
uint128_base10_t ad = a*d;
int adShift = b.getDataLength();
uint128_base10_t bc = b*c;
int bcShift = d.getDataLength();
uint128_base10_t acShiftRes = (ac << acShift);
uint128_base10_t adShiftRes = (ad << adShift);
uint128_base10_t bcShiftRes = (bc << bcShift);
result = acShiftRes + bd + adShiftRes + bcShiftRes;
}
result._length = result.calcDataLength();
return result;
}
ostream& operator << (ostream &out, const uint128_base10_t &d) {
const uint8_t *data = d.getData();
bool flag = false;
for (int i(uint128_base10_t::LENGTH - 1); i >= 0; i--) {
if (!(data[i] == 0 && flag == false)) {
out << (char)(data[i] + 0x30);
flag = true;
}
}
if (flag == false)
cout << 0;
return out;
}
另外就是C++裏邊有幾點,以前一直沒有總結的。
就是下邊的代碼,t2和t3其實調用的都是Copy構造函數,而不是那個等號初始化會調用等號,t4=t1纔會調用等號
#include <iostream>
using namespace std;
class T {
T() {cout << "1" << endl;}
T(const T& t) {cout << "2" << endl;}
T& operator = (const T& t) {cout << "3" << endl; return *this;};
};
int main() {
T t1; // 輸出1
T t2(t1); //輸出2
T t3 = t1; //輸出2
T t4; //輸出1
t4 = t1; //輸出3
}