decimal decimal::operator *(const decimal& value) const { const decimal& a = length() <= value.length() ? *this : value; const decimal& b = length() > value.length() ? *this : value; if (a.isZero()) { return decimal(0); } else if (a.isUnity()) { return b; } decimal c; const auto as = a.length(); const auto bs = b.length(); c.digits.resize(as + bs); for (size_t i = 0; i < as; i++) { const digit ad = a[i]; if (ad == 0) { continue; } decimal tmp; tmp.digits.resize(bs + i + 1); digit carry = 0; for (size_t j = 0; j < bs; j++) { digit d = b[j] * ad + carry; carry = d / 10; tmp[j + i] = d - (carry * 10); } if (carry) { tmp[bs + i] = carry; } else { tmp.digits.resize(bs + i); } c += tmp; } c.remove_lz(); return c; }
char decimal::relation_to(const decimal& b) const { const decimal& a = *this; const auto as = a.length(); const auto bs = b.length(); if (as > bs) { return +1; } else if (bs > as) { return -1; } for (auto i = as; i > 0; i--) { digit d = a[i - 1] - b[i - 1]; if (d > 0) { return +1; } else if (d < 0) { return -1; } } return 0; }
decimal decimal::operator -=(const decimal& b) { if (b.isZero()) { return *this; } decimal& a = *this; const size_t w = a.length(); if (b.length() > w) { throw underflow_error("Negative values not allowed"); } bool borrow = false; for (size_t i = 0; i < w; i++) { digit d = a[i] - b[i] - (borrow ? 1 : 0); borrow = d < 0; a[i] = borrow ? 10 + d : d; } if (borrow) { throw underflow_error("Negative values not allowed"); } remove_lz(); return *this; }
decimal decimal::operator +=(const decimal& b) { if (isZero()) { *this = b; return *this; } else if (b.isZero()) { return *this; } decimal& a = *this; const size_t w = max(a.length(), b.length()); digits.resize(w + 1); bool carry = false; for (size_t i = 0; i < w; i++) { digit d = a[i] + b[i] + (carry ? 1 : 0); carry = d >= 10; a[i] = carry ? d - 10 : d; } if (carry) { a[w] = 1; } else { digits.resize(w); } return *this; }
decimal decimal::parallel_multiply(const decimal& l, const decimal& r) { const decimal& a = l.length() <= r.length() ? l : r; const decimal& b = l.length() > r.length() ? l : r; if (a.isZero()) { return decimal(0); } else if (a.isUnity()) { return b; } const auto as = a.length(); const auto bs = b.length(); const size_t cores = std::thread::hardware_concurrency(); const size_t workers = min<size_t>(cores, (as / 1000)); if (workers == 0) { return l * r; } decimal result; result.digits.resize(as + bs); mutex mx; function<int(size_t, size_t)> partial_product = [&a, &b, as, bs, &mx, &result] (size_t begin, size_t end) { decimal c; c.digits.resize(as + bs); decimal tmp; tmp.digits.reserve(bs + end + 1); for (size_t i = begin; i < end; i++) { const digit ad = a[i]; if (ad == 0) { continue; } fill(tmp.digits.begin(), tmp.digits.end(), 0); tmp.digits.resize(bs + i + 1); digit carry = 0; for (size_t j = 0; j < bs; j++) { digit d = b[j] * ad + carry; carry = d / 10; tmp[j + i] = d - (carry * 10); } if (carry) { tmp[bs + i] = carry; } else { tmp.digits.resize(bs + i); } c += tmp; } lock_guard<mutex> lock(mx); result += c; return 0; }; vector<future<int>> futures; futures.reserve(workers); for (size_t worker = 0; worker < workers; worker++) { const auto begin = (as * worker) / workers; const auto end = (as * (worker + 1)) / workers; futures.emplace_back(async(std::launch::async, partial_product, begin, end)); } for (size_t worker = 0; worker < workers; worker++) { auto& future = futures[worker]; future.get(); } result.remove_lz(); return result; }