This weekend I followed the wiki to implement the basic big integer multiplication. I use the Toom-3 algorithm to implement. But the time spends unexpectedly at the beginning is slower than long multiplication(grade-school multiplication) and gone forever. I hope the program can over the grade-school multiplication within 500 digits, How should I do, please?
I try to optimize, I reserve the vector capacity and remove the supernumerary code. But is not very effective.
And should I use the vector<long long> to be my base digits?
The whole source code in Github:
typedef long long BigIntBase;
typedef vector<BigIntBase> BigIntDigits;
// ceil(numeric_limits<BigIntBase>::digits10 / 2.0) - 1;
static const int digit_base_len = 9;
// b
static const BigIntBase digit_base = 1000000000;
class BigInt {
public:
BigInt(int digits_capacity = 0, bool nega = false) {
negative = nega;
digits.reserve(digits_capacity);
}
BigInt(BigIntDigits _digits, bool nega = false) {
negative = nega;
digits = _digits;
}
BigInt(const span<const BigIntBase> &range, bool nega = false) {
negative = nega;
digits = BigIntDigits(range.begin(), range.end());
}
BigInt operator+(const BigInt &rhs) {
if ((*this).negative == rhs.negative)
return BigInt(plus((*this).digits, rhs.digits), (*this).negative);
if (greater((*this).digits, rhs.digits))
return BigInt(minus((*this).digits, rhs.digits), (*this).negative);
return BigInt(minus(rhs.digits, (*this).digits), rhs.negative);
}
BigInt operator-(const BigInt &rhs) { return *this + BigInt(rhs.digits, !rhs.negative); }
BigInt operator*(const BigInt &rhs) {
if ((*this).digits.empty() || rhs.digits.empty()) {
return BigInt();
} else if ((*this).digits.size() == 1 && rhs.digits.size() == 1) {
BigIntBase val = (*this).digits[0] * rhs.digits[0];
return BigInt(val < digit_base ? BigIntDigits{val} : BigIntDigits{val % digit_base, val / digit_base}, (*this).negative ^ rhs.negative);
} else if ((*this).digits.size() == 1)
return BigInt(multiply(rhs, (*this).digits[0]).digits, (*this).negative ^ rhs.negative);
else if (rhs.digits.size() == 1)
return BigInt(multiply((*this), rhs.digits[0]).digits, (*this).negative ^ rhs.negative);
return BigInt(toom3(span((*this).digits), span(rhs.digits)), (*this).negative ^ rhs.negative);
}
string to_string() {
if (this->digits.empty())
return "0";
stringstream ss;
if (this->negative)
ss << "-";
ss << std::to_string(this->digits.back());
for (auto it = this->digits.rbegin() + 1; it != this->digits.rend(); ++it)
ss << setw(digit_base_len) << setfill('0') << std::to_string(*it);
return ss.str();
}
BigInt from_string(string s) {
digits.clear();
negative = s[0] == '-';
for (int pos = max(0, (int)s.size() - digit_base_len); pos >= 0; pos -= digit_base_len)
digits.push_back(stoll(s.substr(pos, digit_base_len)));
if (s.size() % digit_base_len)
digits.push_back(stoll(s.substr(0, s.size() % digit_base_len)));
return *this;
}
private:
bool negative;
BigIntDigits digits;
const span<const BigIntBase> toom3_slice_num(const span<const BigIntBase> &num, const int &n, const int &i) {
int begin = n * i;
if (begin < num.size()) {
const span<const BigIntBase> result = num.subspan(begin, min((int)num.size() - begin, i));
return result;
}
return span<const BigIntBase>();
}
BigIntDigits toom3(const span<const BigIntBase> &num1, const span<const BigIntBase> &num2) {
int i = ceil(max(num1.size() / 3.0, num2.size() / 3.0));
const span<const BigIntBase> m0 = toom3_slice_num(num1, 0, i);
const span<const BigIntBase> m1 = toom3_slice_num(num1, 1, i);
const span<const BigIntBase> m2 = toom3_slice_num(num1, 2, i);
const span<const BigIntBase> n0 = toom3_slice_num(num2, 0, i);
const span<const BigIntBase> n1 = toom3_slice_num(num2, 1, i);
const span<const BigIntBase> n2 = toom3_slice_num(num2, 2, i);
BigInt pt0 = plus(m0, m2);
BigInt pp0 = m0;
BigInt pp1 = plus(pt0.digits, m1);
BigInt pn1 = pt0 - m1;
BigInt pn2 = multiply(pn1 + m2, 2) - m0;
BigInt pin = m2;
BigInt qt0 = plus(n0, n2);
BigInt qp0 = n0;
BigInt qp1 = plus(qt0.digits, n1);
BigInt qn1 = qt0 - n1;
BigInt qn2 = multiply(qn1 + n2, 2) - n0;
BigInt qin = n2;
BigInt rp0 = pp0 * qp0;
BigInt rp1 = pp1 * qp1;
BigInt rn1 = pn1 * qn1;
BigInt rn2 = pn2 * qn2;
BigInt rin = pin * qin;
BigInt r0 = rp0;
BigInt r4 = rin;
BigInt r3 = divide(rn2 - rp1, 3);
BigInt r1 = divide(rp1 - rn1, 2);
BigInt r2 = rn1 - rp0;
r3 = divide(r2 - r3, 2) + multiply(rin, 2);
r2 = r2 + r1 - r4;
r1 = r1 - r3;
BigIntDigits result = r0.digits;
if (!r1.digits.empty()) {
shift_left(r1.digits, i);
result = plus(result, r1.digits);
}
if (!r2.digits.empty()) {
shift_left(r2.digits, i << 1);
result = plus(result, r2.digits);
}
if (!r3.digits.empty()) {
shift_left(r3.digits, i * 3);
result = plus(result, r3.digits);
}
if (!r4.digits.empty()) {
shift_left(r4.digits, i << 2);
result = plus(result, r4.digits);
}
return result;
}
BigIntDigits plus(const span<const BigIntBase> &lhs, const span<const BigIntBase> &rhs) {
if (lhs.empty())
return BigIntDigits(rhs.begin(), rhs.end());
if (rhs.empty())
return BigIntDigits(lhs.begin(), lhs.end());
int max_length = max(lhs.size(), rhs.size());
BigIntDigits result;
result.reserve(max_length + 1);
for (int w = 0; w < max_length; ++w)
result.push_back((lhs.size() > w ? lhs[w] : 0) + (rhs.size() > w ? rhs[w] : 0));
for (int w = 0; w < result.size() - 1; ++w) {
result[w + 1] += result[w] / digit_base;
result[w] %= digit_base;
}
if (result.back() >= digit_base) {
result.push_back(result.back() / digit_base);
result[result.size() - 2] %= digit_base;
}
return result;
}
BigIntDigits minus(const span<const BigIntBase> &lhs, const span<const BigIntBase> &rhs) {
if (lhs.empty())
return BigIntDigits(rhs.begin(), rhs.end());
if (rhs.empty())
return BigIntDigits(lhs.begin(), lhs.end());
BigIntDigits result;
result.reserve(lhs.size() + 1);
for (int w = 0; w < lhs.size(); ++w)
result.push_back((lhs.size() > w ? lhs[w] : 0) - (rhs.size() > w ? rhs[w] : 0));
for (int w = 0; w < result.size() - 1; ++w)
if (result[w] < 0) {
result[w + 1] -= 1;
result[w] += digit_base;
}
while (!result.empty() && !result.back())
result.pop_back();
return result;
}
void shift_left(BigIntDigits &lhs, const int n) {
if (!lhs.empty()) {
BigIntDigits zeros(n, 0);
lhs.insert(lhs.begin(), zeros.begin(), zeros.end());
}
}
BigInt divide(const BigInt &lhs, const int divisor) {
BigIntDigits reminder(lhs.digits);
BigInt result(lhs.digits.capacity(), lhs.negative);
for (int w = reminder.size() - 1; w >= 0; --w) {
result.digits.insert(result.digits.begin(), reminder[w] / divisor);
reminder[w - 1] += (reminder[w] % divisor) * digit_base;
}
while (!result.digits.empty() && !result.digits.back())
result.digits.pop_back();
return result;
}
BigInt multiply(const BigInt &lhs, const int multiplier) {
BigInt result(lhs.digits, lhs.negative);
for (int w = 0; w < result.digits.size(); ++w)
result.digits[w] *= multiplier;
for (int w = 0; w < result.digits.size(); ++w)
if (result.digits[w] >= digit_base) {
if (w + 1 == result.digits.size())
result.digits.push_back(result.digits[w] / digit_base);
else
result.digits[w + 1] += result.digits[w] / digit_base;
result.digits[w] %= digit_base;
}
return result;
}
bool greater(const BigIntDigits &lhs, const BigIntDigits &rhs) {
if (lhs.size() == rhs.size()) {
int w = lhs.size() - 1;
while (w >= 0 && lhs[w] == rhs[w])
--w;
return w >= 0 && lhs[w] > rhs[w];
} else
return lhs.size() > rhs.size();
}
};
Digits
Grade-school
Toom-3
10
4588
10003
50
24147
109084
100
52165
286535
150
92405
476275
200
172156
1076570
250
219599
1135946
300
320939
1530747
350
415655
1689745
400
498172
1937327
450
614467
2629886
500
863116
3184277
The problem is that you do a million allocations in among others toom3_slice_num, here you could use a std::span (or a std::pair of iterator to the actual part) as the number you give is a const. toom3 is also allocator hell.
The multiply might allocate 1 more time. Count the bits needed or just add 1 to the size.
And the vectors should be pmr (with appropriate allocator) for nearly lock free allocations.
All this is wasted if not compiled with -O2 or -O3.
Related
I made a program for BigInteger in which I implemented Addition Subtraction and Karatsuba but it is giving wrong result. After several debuting I am not able to figure out the problem. Here is my code:-
//
// Created by bothra on 09/07/20.
//
#include <sstream>
#include"BigInteger.h++"
BigInteger::BigInteger(std::string a) {
digits = a;
}
BigInteger BigInteger::operator+(BigInteger othr) {
return add(othr);
}
BigInteger BigInteger::operator-(BigInteger othr) {
return Subtract(othr);
}
bool BigInteger::operator>(BigInteger othr) {
if(digits.size() > othr.digits.size()){
return true;
}
else if(digits.size() < othr.digits.size()){
return false;
}
else{
for(int i = digits.size() - 1;i >= 0;i--){
if(digits[i] < othr.digits[i]){
return false;
}
}
return true;
}
}
bool BigInteger::operator==(BigInteger othr) {
if(digits.size() == othr.digits.size()){
int flag = 0;
for(int i = digits.size() - 1;i >= 0;i--){
if(digits[i] < othr.digits[i]){
return false;
}
if(digits[i] > othr.digits[i]){
flag = 1;
}
}
if(flag == 0){
return true;
}
}
return false;
}
BigInteger::BigInteger(int a) {
}
BigInteger BigInteger::add(BigInteger other) {
if(sign == other.sign) {
int base = 10;
BigInteger ans("0");
std::string a = digits;
std::string b = other.digits;
std::string result = "";
int s = 0;
int i = a.size() - 1;
int j = b.size() - 1;
while (i >= 0 || j >= 0 || s == 1) {
s += ((i >= 0) ? a[i] - '0' : 0);
s += ((j >= 0) ? b[j] - '0' : 0);
result = char(s % base + '0') + result;
s /= base;
i--;
j--;
}
ans.sign = sign;
ans.digits = result;
return ans;
}
else{
return Subtract(other);
}
}
BigInteger BigInteger::MakeShifting(BigInteger a,int stepnum){
std::string shifted = a.digits;
for (int i = 0 ; i < stepnum ; i++)
shifted = shifted + '0';
return shifted;
}
int makeEqualLength(std::string &str1, std::string &str2)
{
int len1 = str1.size();
int len2 = str2.size();
if (len1 < len2)
{
for (int i = 0 ; i < len2 - len1 ; i++)
str1 = '0' + str1;
return len2;
}
else if (len1 > len2)
{
for (int i = 0 ; i < len1 - len2 ; i++)
str2 = '0' + str2;
}
return len1; // If len1 >= len2
}
std::string getString(char x)
{
std::string s(1, x);
return s;
}
std::string DecimalToBinary(long long int number)
{
std::string result = "";
int base = 10;
if (number <= 0){
return "0";
}
else{
int i = 0;
char temp;
while (number > 0){
long long int num= number % base;
temp = num + '0';
result = getString(temp) + result;
number = number / base;
i++;
}
return result;
}
}
BigInteger BigInteger::Subtract(BigInteger a)
{
if(a.sign != sign){
a.sign = sign;
BigInteger ans = add(a);
ans.sign = sign;
return ans;
}
if(*this > a) {
BigInteger ans("0");
std::string rhs = a.digits;
std::string lhs = digits;
int length = makeEqualLength(lhs, rhs);
int diff;
std::string result;
int base = 10;
for (int i = length - 1; i >= 0; i--) {
diff = (lhs[i] - '0') - (rhs[i] - '0');
if (diff >= 0) {
result = DecimalToBinary(diff) + result;
} else {
for (int j = i - 1; j >= 0; j--) {
lhs[j] = ((lhs[j] - '0') - 1) % 10 + '0';
if (lhs[j] != '1') {
break;
}
}
result = DecimalToBinary(diff + base) + result;
}
}
ans.sign = sign;
ans.digits = result;
return ans;
}
if(*this == a){
return BigInteger("0");
}
else{
BigInteger ans("0");
std::string rhs = digits;
std::string lhs = a.digits;
int length = makeEqualLength(lhs, rhs);
int diff;
std::string result;
int base = 79;
for (int i = length - 1; i >= 0; i--) {
diff = (lhs[i] - '0') - (rhs[i] - '0');
if (diff >= 0) {
result = DecimalToBinary(diff) + result;
} else {
for (int j = i - 1; j >= 0; j--) {
lhs[j] = ((lhs[j] - '0') - 1) % 10 + '0';
if (lhs[j] != '1') {
break;
}
}
result = DecimalToBinary(diff + base) + result;
}
}
ans.sign = a.sign;
ans.digits = result;
return ans;
}
}
BigInteger BigInteger::Multiply(BigInteger other)
{
std::string X = digits;
std::string Y = other.digits;
int n = makeEqualLength(X, Y);
if (n == 1) return BigInteger(DecimalToBinary((X[0] - '0') * (Y[0] - '0')));
int fh = n/2; // First half of string, floor(n/2)
int sh = (n-fh); // Second half of string, ceil(n/2)
// Find the first half and second half of first string.
std::string Xl = X.substr(0, fh);
std::string Xr = X.substr(fh, sh);
// Find the first half and second half of second string
std::string Yl = Y.substr(0, fh);
std::string Yr = Y.substr(fh, sh);
// Recursively calculate the three products of inputs of size n/2
BigInteger P1 = BigInteger(Xl).Multiply(BigInteger(Yl));
BigInteger P2 = BigInteger(Xr).Multiply(BigInteger(Yr));
BigInteger P3 = (BigInteger(Xl)+BigInteger(Xr)).Multiply(BigInteger(Yl) + BigInteger(Yr));
// return added string version
return (P2 + MakeShifting(P1,2*(n - n/2))) + (MakeShifting(P3 - (P1 + P2) , n - n/2));
}
and the header:
//
// Created by bothra on 09/07/20.
//
#ifndef BIGINTEGER_BIGINTEGER_H
#define BIGINTEGER_BIGINTEGER_H
#include<iostream>
class BigInteger{
public:
std::string digits;
bool sign = false;//false indicates positive
BigInteger(int a);
BigInteger(std::string a);
BigInteger operator + (BigInteger othr);
BigInteger operator - (BigInteger othr);
bool operator > (BigInteger othr);
bool operator ==(BigInteger othr);
BigInteger add(BigInteger other);
BigInteger MakeShifting(BigInteger a,int stepnum);
BigInteger Subtract(BigInteger other);
BigInteger Multiply(BigInteger other);
};
#endif //BIGINTEGER_BIGINTEGER_H
But this code Multiplication is not working . It is keep on giving incorrect answer.
For example here is a driver code:-
#include <iostream>
#include "BigInteger.h++"
int main() {
BigInteger a("429");
BigInteger b("429");
a = a.Multiply(b);
std::cout << a.digits;
return 0;
}
Here it does 429 * 429 :
Output : 1397541
Output should have been : 184041
Please help me out.
Thanks in advance
Much thanks for the help in additionally.
I'm trying to build a BVH Tree with Surface Area Heuristic, but everytime I compile my code it gives me random errors like:
"Access violation reading location"
"Run-Time Check Failure #2 - Stack around the variable 'x' was
corrupted."
"Stack overflow "
The errors happen in the BVH::buildSAH() function.
And I have tried to find a solution for the whole day, meaningless. Could it be something from the std::partition function or from sending variables with pointers to a recursion?
I'm reading from the book "Physically Based Rendering: From Theory to Implementation
By Matt Pharr, Greg Humphreys"
It works for 2 primitives in the area, but thats trivial...
If you would like to clone: https://github.com/vkaytsanov/MortonCode-BVH-KD
My BVH.hpp:
#include <vector>
#include <cassert>
#include <algorithm>
#include "memory.hpp"
#include "Screen.hpp"
#include "Point3D.hpp"
#include "BoundBox.hpp"
#pragma once
enum Axis{
X, Y, Z
};
struct MortonPrimitive{
int primitiveIndex;
uint32_t mortonCode;
};
struct BVHPrimitiveInfo {
BVHPrimitiveInfo() {}
BVHPrimitiveInfo(int primitiveNumber, const BoundBox& box) : primitiveNumber(primitiveNumber), box(box),
centroid(Point3D(box.pMin.x* 0.5f + box.pMax.x * 0.5f, box.pMin.y* 0.5f + box.pMax.y * 0.5f, box.pMin.z* 0.5f + box.pMax.z * 0.5f)) {}
int primitiveNumber;
BoundBox box;
Point3D centroid;
};
struct BVHNode {
void InitLeaf(int first, int n, const BoundBox& b) {
firstPrimOffset = first;
nPrimitives = n;
box = b;
children[0] = children[1] = nullptr;
}
void InitInterior(int axis, BVHNode* c0, BVHNode* c1) {
assert(c0 != NULL || c1 != NULL);
children[0] = c0;
children[1] = c1;
this->box = Union(c0->box, c1->box);
splitAxis = axis;
nPrimitives = 0;
}
BoundBox box;
BVHNode* children[2];
int splitAxis, firstPrimOffset, nPrimitives;
};
struct LinearBVHNode {
BoundBox bounds;
union {
int primitivesOffset; // leaf
int secondChildOffset; // interior
};
uint16_t nPrimitives; // 0 -> interior node
uint8_t axis; // interior node: xyz
uint8_t pad[1]; // ensure 32 byte total size
};
struct BVHLittleTree {
int startIndex;
int numPrimitives;
BVHNode* nodes;
};
struct BVH {
BVH(std::vector<std::shared_ptr<Primitive>> p) : primitives(std::move(p)) {
std::vector<BVHPrimitiveInfo> BVHPrimitives;
BVHPrimitives.reserve(primitives.size());
for (int i = 0; i < primitives.size(); i++) {
BVHPrimitives.push_back({ i, primitives[i]->box });
}
MemoryArena arena(1024 * 1024);
int totalNodes = 0;
std::vector<std::shared_ptr<Primitive>> orderedPrimitives;
orderedPrimitives.reserve(primitives.size());
BVHNode* root;
root = HLBVHBuild(arena, BVHPrimitives, &totalNodes, orderedPrimitives);
primitives.swap(orderedPrimitives);
BVHPrimitives.resize(0);
printf("BVH created with %d nodes for %d "
"primitives (%.4f MB), arena allocated %.2f MB\n",
(int)totalNodes, (int)primitives.size(),
float(totalNodes * sizeof(LinearBVHNode)) /
(1024.f * 1024.f),
float(arena.TotalAllocated()) /
(1024.f * 1024.f));
assert(root != NULL);
nodes = AllocAligned<LinearBVHNode>(totalNodes);
int offset = 0;
flattenBVHTree(root, &offset);
}
~BVH() { FreeAligned(nodes); }
BVHNode* build(std::vector<MortonPrimitive>&, std::vector<Primitive>&);
BVHNode* HLBVHBuild(MemoryArena& arena, const std::vector<BVHPrimitiveInfo>& BVHPrimitives, int* totalNodes, std::vector<std::shared_ptr<Primitive>>& orderedPrims);
BVHNode* emit(BVHNode*& nodes, const std::vector<BVHPrimitiveInfo>& BVHPrimitives, MortonPrimitive* mortonPrimitives, std::vector<std::shared_ptr<Primitive>>&, int, int*, int*, int);
BVHNode* buildSAH(MemoryArena& arena, std::vector<BVHNode*>& treeRoots, int start, int end, int* total) const;
int flattenBVHTree(BVHNode*, int*);
std::vector<std::shared_ptr<Primitive>> primitives;
LinearBVHNode* nodes = nullptr;
int maxPrimsInNode = 1;
};
inline uint32_t LeftShift3(uint32_t x) {
if (x == (1 << 10)) --x;
x = (x | (x << 16)) & 0b00000011000000000000000011111111;
x = (x | (x << 8)) & 0b00000011000000001111000000001111;
x = (x | (x << 4)) & 0b00000011000011000011000011000011;
x = (x | (x << 2)) & 0b00001001001001001001001001001001;
return x;
}
uint32_t EncodeMorton3(const Point3D& p) {
return (LeftShift3(p.z) << 2) |
(LeftShift3(p.y) << 1) |
(LeftShift3(p.x) << 0);
}
short bitValue(uint32_t& number, uint32_t& mask) {
return number & mask ? 1 : 0;
}
static void radixSort(std::vector<MortonPrimitive>* v)
{
std::vector<MortonPrimitive> tempVector(v->size());
const int bitsPerPass = 6;
const int nBits = 30;
static_assert((nBits % bitsPerPass) == 0,
"Radix sort bitsPerPass must evenly divide nBits");
const int nPasses = nBits / bitsPerPass;
for (int pass = 0; pass < nPasses; ++pass) {
// Perform one pass of radix sort, sorting _bitsPerPass_ bits
int lowBit = pass * bitsPerPass;
// Set in and out vector pointers for radix sort pass
std::vector<MortonPrimitive>& in = (pass & 1) ? tempVector : *v;
std::vector<MortonPrimitive>& out = (pass & 1) ? *v : tempVector;
// Count number of zero bits in array for current radix sort bit
const int nBuckets = 1 << bitsPerPass;
int bucketCount[nBuckets] = { 0 };
const int bitMask = (1 << bitsPerPass) - 1;
for (const MortonPrimitive& mp : in) {
int bucket = (mp.mortonCode >> lowBit) & bitMask;
++bucketCount[bucket];
}
// Compute starting index in output array for each bucket
int outIndex[nBuckets];
outIndex[0] = 0;
for (int i = 1; i < nBuckets; ++i)
outIndex[i] = outIndex[i - 1] + bucketCount[i - 1];
// Store sorted values in output array
for (const MortonPrimitive& mp : in) {
int bucket = (mp.mortonCode >> lowBit) & bitMask;
out[outIndex[bucket]++] = mp;
}
}
// Copy final result from _tempVector_, if needed
if (nPasses & 1) std::swap(*v, tempVector);
}
//BVHNode* BVH::build(std::vector<MortonPrimitive>& mortonPrimitives, std::vector<Primitive>& prims) {
//
//
//}
struct BucketInfo {
int count = 0;
BoundBox bounds;
};
BVHNode* BVH::HLBVHBuild(MemoryArena& arena, const std::vector<BVHPrimitiveInfo>& BVHPrimitives, int* totalNodes, std::vector<std::shared_ptr<Primitive>>& orderedPrims) {
BoundBox box;
for (const BVHPrimitiveInfo& pi : BVHPrimitives) {
box = box.Union(box, pi.centroid); // maybe it should be UNION #TODO
}
std::vector<MortonPrimitive> mortonPrims(BVHPrimitives.size());
for (int i = 0; i < BVHPrimitives.size(); i++) {
const int mortonBits = 10;
const int mortonScale = 1 << mortonBits;
mortonPrims[i].primitiveIndex = BVHPrimitives[i].primitiveNumber;
Point3D p = box.offset(BVHPrimitives[i].centroid);
p.x = p.x * mortonScale;
p.y = p.y * mortonScale;
p.z = p.z * mortonScale;
mortonPrims[i].mortonCode = EncodeMorton3(p);
}
radixSort(&mortonPrims);
//for (MortonPrimitive mp : mortonPrims) {
// std::cout << mp.primitiveIndex << " " << mp.mortonCode << std::endl;
//}
std::vector<BVHLittleTree> treesToBuild;
uint32_t mask = 0b00111111111111000000000000000000; // first 12 bits describe the position of the primitive
for (int start = 0, end = 1; end <= (int)mortonPrims.size(); end++) {
if (end == mortonPrims.size() || ((mortonPrims[start].mortonCode & mask) != (mortonPrims[end].mortonCode & mask))) {
int n = end - start;
int maxNodes = 2 * n;
BVHNode* nodes = arena.Alloc<BVHNode>(maxNodes, false);
treesToBuild.push_back({ start, n, nodes });
start = end;
}
}
int orderedPrimsOffset = 0;
orderedPrims.resize(primitives.size());
int nodesCreated = 0;
int firstBitIndex = 29 - 12;
for (int i = 0; i < treesToBuild.size(); i++) {
treesToBuild[i].nodes = BVH::emit(treesToBuild[i].nodes, BVHPrimitives, &mortonPrims[treesToBuild[i].startIndex], orderedPrims, treesToBuild[i].numPrimitives, &nodesCreated, &orderedPrimsOffset, firstBitIndex);
*totalNodes += nodesCreated;
}
totalNodes += nodesCreated;
std::vector<BVHNode*> finishedTrees;
finishedTrees.reserve(treesToBuild.size());
for (BVHLittleTree& tr : treesToBuild) {
finishedTrees.emplace_back(tr.nodes);
}
return buildSAH(arena, finishedTrees, 0, finishedTrees.size(), totalNodes);
}
BVHNode* BVH::emit(BVHNode*& nodes, const std::vector<BVHPrimitiveInfo>& BVHPrimitive, MortonPrimitive* mortonPrimitives, std::vector<std::shared_ptr<Primitive>>& orderedPrimitives, int primitivesCount, int* totalNodes, int* orderedPrimsOffset, int bitIndex) {
if (bitIndex == -1 || primitivesCount < maxPrimsInNode) {
(*totalNodes)++;
BVHNode* tmp = nodes++;
BoundBox box;
int firstPrimOffset = *orderedPrimsOffset;
for (int i = 0; i < primitivesCount; i++) {
int index = mortonPrimitives[i].primitiveIndex;
orderedPrimitives[firstPrimOffset + i] = primitives[index];
box = box.Union(box, BVHPrimitive[index].box);
}
tmp->InitLeaf(0, primitivesCount, box);
return tmp;
}
else {
int mask = 1 << bitIndex;
if ((mortonPrimitives[0].mortonCode & mask) == (mortonPrimitives[primitivesCount - 1].mortonCode & mask)){ // Next tree if nothing to split for this bit
return emit(nodes, BVHPrimitive, mortonPrimitives, orderedPrimitives, primitivesCount, totalNodes, orderedPrimsOffset, bitIndex - 1);
}
int start = 0;
int end = primitivesCount - 1;
while (start + 1 != end) {
int mid = (end - start) / 2 + start; // (start-end)/2
if ((mortonPrimitives[start].mortonCode & mask) == (mortonPrimitives[mid].mortonCode & mask)) {
start = mid;
}
else {
end = mid;
}
}
int split = end;
(*totalNodes)++;
BVHNode* tmp = nodes++;
BVHNode* lbvh[2];
lbvh[0] = emit(nodes, BVHPrimitive, mortonPrimitives, orderedPrimitives, split, totalNodes, orderedPrimsOffset, bitIndex-1);
lbvh[1] = emit(nodes, BVHPrimitive, &mortonPrimitives[split], orderedPrimitives, primitivesCount - split, totalNodes, orderedPrimsOffset, bitIndex - 1);
int axis = bitIndex % 3;
tmp->InitInterior(axis, lbvh[0], lbvh[1]);
return tmp;
}
}
BVHNode* BVH::buildSAH(MemoryArena& arena, std::vector<BVHNode*>& treeRoots, int start, int end, int* total) const {
int nodesCount = end - start;
if (nodesCount == 1) {
return treeRoots[start];
}
assert(nodesCount > 1);
(*total)++;
BVHNode* node = arena.Alloc<BVHNode>();
BoundBox box;
for (int i = start; i < end; i++) {
box = Union(box, treeRoots[i]->box);
}
BoundBox centroidBox;
for (int i = start; i < end; i++) {
Point3D centroid = Point3D((treeRoots[i]->box.pMin.x + treeRoots[i]->box.pMax.x) * 0.5f, (treeRoots[i]->box.pMin.y + treeRoots[i]->box.pMax.y) * 0.5f, (treeRoots[i]->box.pMin.z + treeRoots[i]->box.pMax.z) * 0.5f);
centroidBox = Union(centroidBox, centroid);
}
const int dimension = centroidBox.MaximumExtent();
const int nBuckets = 12;
struct Buckets {
int count = 0;
BoundBox box;
};
Buckets buckets[nBuckets];
for (int i = start; i < end; i++) {
float centroid = (treeRoots[i]->box.pMin[dimension] * 0.5f + treeRoots[i]->box.pMax[dimension] * 0.5f) ;
int b = nBuckets * ((centroid - centroidBox.pMin[dimension]) / (centroidBox.pMax[dimension] - centroidBox.pMin[dimension]));
if (b == nBuckets) b = nBuckets - 1;
//assert(b < nBuckets);
buckets[b].count++;
buckets[b].box = Union(buckets[b].box, treeRoots[i]->box);
}
float cost[nBuckets - 1];
for (int i = 0; i < nBuckets - 1; i++) {
BoundBox b0, b1;
int count0 = 0, count1 = 0;
for (int j = 0; j <= i; j++) {
b0 = Union(b0, buckets[j].box);
count0 += buckets[j].count;
}
for (int j = i+1; j < nBuckets; j++) {
b1 = Union(b1, buckets[j].box);
count1 += buckets[j].count;
}
cost[i] = (.125f + (count0 * b0.surfaceArea() + count1 * b1.surfaceArea())) / box.surfaceArea();
}
double minCost = cost[0];
int minCostSplitBucket = 0;
for (int i = 1; i < nBuckets - 1; ++i) {
if (cost[i] < minCost) {
minCost = cost[i];
minCostSplitBucket = i;
}
}
BVHNode** pmid = std::partition(&treeRoots[start], &treeRoots[end - 1] + 1, [=](const BVHNode* node) {
double centroid = (node->box.pMin[dimension]*0.5f + node->box.pMax[dimension] * 0.5f) ;
int b = nBuckets * ((centroid - centroidBox.pMin[dimension]) / (centroidBox.pMax[dimension] - centroidBox.pMin[dimension]));
if (b == nBuckets) b = nBuckets - 1;
return b <= minCostSplitBucket;
});
assert(pmid != NULL);
//std::cout << pmid << " " << &treeRoots[0];
int mid = pmid - &treeRoots[0];
//std::cout << start << " " << mid << std::endl;
//std::cout << mid << " " << end << std::endl;
std::cout << dimension << std::endl;
//assert(dimension < 3);
node->InitInterior(dimension, this->buildSAH(arena, treeRoots, start, mid, total), this->buildSAH(arena, treeRoots, mid, end, total));
return node;
}
int BVH::flattenBVHTree(BVHNode* node, int* offset) {
LinearBVHNode* linearNode = &nodes[*offset];
linearNode->bounds = node->box;
int myOffset = (*offset)++;
if (node->nPrimitives > 0) {
linearNode->primitivesOffset = node->firstPrimOffset;
linearNode->nPrimitives = node->nPrimitives;
}
else {
// Create interior flattened BVH node
linearNode->axis = node->splitAxis;
linearNode->nPrimitives = 0;
flattenBVHTree(node->children[0], offset);
linearNode->secondChildOffset = flattenBVHTree(node->children[1], offset);
}
return myOffset;
}
My Point3D.hpp
#include <cstdint>
#pragma once
struct Point3D {
float x;
float y;
float z;
Point3D(uint32_t, uint32_t, uint32_t);
Point3D();
int operator[](int);
int operator[](int) const;
Point3D operator+(int);
Point3D operator-(int);
Point3D operator-(Point3D&);
};
Point3D::Point3D() {
x = 0;
y = 0;
z = 0;
}
Point3D::Point3D(uint32_t x, uint32_t y, uint32_t z) {
this->x = x;
this->y = y;
this->z = z;
}
bool operator<(Point3D a, Point3D b) {
uint32_t xSquare = a.x * a.x;
uint32_t ySquare = a.y * a.y;
uint32_t zSquare = a.z * a.z;
uint32_t x2Square = b.x * b.x;
uint32_t y2Square = b.y * b.y;
uint32_t z2Square = b.z * b.z;
int64_t sum = std::sqrt(xSquare + ySquare + z2Square) - std::sqrt(x2Square + y2Square + z2Square);
return sum < 0 ||
sum == 0 && xSquare < x2Square ||
sum == 0 && xSquare == x2Square && ySquare < y2Square ||
sum == 0 && xSquare == x2Square && ySquare == y2Square && zSquare < z2Square;
}
bool operator>(Point3D a, Point3D b) {
uint32_t xSquare = a.x * a.x;
uint32_t ySquare = a.y * a.y;
uint32_t zSquare = a.z * a.z;
uint32_t x2Square = b.x * b.x;
uint32_t y2Square = b.y * b.y;
uint32_t z2Square = b.z * b.z;
int32_t sum = std::sqrt(xSquare + ySquare + z2Square) - std::sqrt(x2Square + y2Square + z2Square);
return sum > 0 ||
sum == 0 && xSquare > x2Square ||
sum == 0 && xSquare == x2Square && ySquare > y2Square ||
sum == 0 && xSquare == x2Square && ySquare == y2Square && zSquare > z2Square;
}
int Point3D::operator[](int i) {
if (i == 0) return x;
if (i == 1) return y;
return z;
}
Point3D Point3D::operator+(int i) {
this->x += i;
this->y += i;
this->z += i;
return *this;
}
Point3D Point3D::operator-(const int i) {
this->x -= i;
this->y -= i;
this->z -= i;
return *this;
}
Point3D Point3D::operator-(Point3D& p) {
this->x -= p.x;
this->y -= p.y;
this->z -= p.z;
return *this;
}
int Point3D::operator[](const int i) const {
if (i == 0) return x;
if (i == 1) return y;
return z;
}
My BoundBox.hpp
#include "Point3D.hpp"
#include "Vector3D.hpp"
#pragma once
struct BoundBox {
Point3D pMin;
Point3D pMax;
BoundBox(Point3D);
BoundBox(Point3D, Point3D);
BoundBox();
void setBounds(BoundBox);
void Union(BoundBox);
BoundBox Union(BoundBox&, Point3D&);
BoundBox Union(BoundBox, BoundBox);
BoundBox unite(BoundBox, BoundBox);
BoundBox unite(BoundBox);
const Point3D offset(const Point3D&);
Point3D diagonal();
const int MaximumExtent();
float surfaceArea();
};
BoundBox::BoundBox() {
float minNum = 0;
pMin = Point3D(800, 600, 300);
pMax = Point3D(minNum, minNum, minNum);
}
BoundBox::BoundBox(Point3D p){
pMin = p;
pMax = p;
}
BoundBox::BoundBox(Point3D p1, Point3D p2) {
pMin = Point3D(std::min(p1.x, p2.x), std::min(p1.y, p2.y), std::min(p1.z, p2.z));
pMax = Point3D(std::max(p1.x, p2.x), std::max(p1.y, p2.y), std::max(p1.z, p2.z));
}
BoundBox BoundBox::Union(BoundBox& box, Point3D& p) {
BoundBox newBox;
newBox.pMin = Point3D(std::min(box.pMin.x, p.x), std::min(box.pMin.y, p.y), std::min(box.pMin.z, p.z));
newBox.pMax = Point3D(std::max(box.pMax.x, p.x), std::max(box.pMax.y, p.y), std::max(box.pMax.z, p.z));
return newBox;
}
BoundBox BoundBox::Union(BoundBox box1, BoundBox box2) {
BoundBox newBox;
newBox.pMin = std::min(box1.pMin, box2.pMin);
newBox.pMax = std::max(box1.pMax, box2.pMax);
return newBox;
}
BoundBox Union(BoundBox box1, BoundBox box2) {
BoundBox newBox;
newBox.pMin = std::min(box1.pMin, box2.pMin);
newBox.pMax = std::max(box1.pMax, box2.pMax);
return newBox;
}
BoundBox BoundBox::unite(BoundBox b1, BoundBox b2) {
bool x = (b1.pMax.x >= b2.pMin.x) && (b1.pMin.x <= b2.pMax.x);
bool y = (b1.pMax.y >= b2.pMin.y) && (b1.pMin.y <= b2.pMax.y);
bool z = (b1.pMax.z >= b2.pMin.z) && (b1.pMin.z <= b2.pMax.z);
if (x && y && z) {
return Union(b1, b2);
}
}
BoundBox BoundBox::unite(BoundBox b2) {
bool x = (this->pMax.x >= b2.pMin.x) && (this->pMin.x <= b2.pMax.x);
bool y = (this->pMax.y >= b2.pMin.y) && (this->pMin.y <= b2.pMax.y);
bool z = (this->pMax.z >= b2.pMin.z) && (this->pMin.z <= b2.pMax.z);
if (x && y && z) {
return Union(*this, b2);
}
else return *this;
}
const int BoundBox::MaximumExtent() {
Point3D d = Point3D(this->pMax.x - this->pMin.x, this->pMax.y - this->pMin.y, this->pMax.z - this->pMin.z); // diagonal
if (d.x > d.y && d.x > d.z) {
return 0;
}
else if (d.y > d.z) {
return 1;
}
else {
return 2;
}
}
float BoundBox::surfaceArea() {
Point3D d = Point3D(this->pMax.x - this->pMin.x, this->pMax.y - this->pMin.y, this->pMax.z - this->pMin.z); // diagonal
return 2 * (d.x * d.y + d.x * d.z + d.y * d.z);
}
const Point3D BoundBox::offset(const Point3D& p) {
Point3D o = Point3D(p.x - pMin.x, p.y - pMin.y, p.z - pMin.z);
if (pMax.x > pMin.x) o.x /= pMax.x - pMin.x;
if (pMax.y > pMin.y) o.y /= pMax.y - pMin.y;
if (pMax.z > pMin.z) o.z /= pMax.z - pMin.z;
return o;
}
My memory.hpp
#include <list>
#include <cstddef>
#include <algorithm>
#include <malloc.h>
#include <stdlib.h>
#pragma once
#define ARENA_ALLOC(arena, Type) new ((arena).Alloc(sizeof(Type))) Type
void* AllocAligned(size_t size);
template <typename T>
T* AllocAligned(size_t count) {
return (T*)AllocAligned(count * sizeof(T));
}
void FreeAligned(void*);
class
#ifdef PBRT_HAVE_ALIGNAS
alignas(PBRT_L1_CACHE_LINE_SIZE)
#endif // PBRT_HAVE_ALIGNAS
MemoryArena {
public:
// MemoryArena Public Methods
MemoryArena(size_t blockSize = 262144) : blockSize(blockSize) {}
~MemoryArena() {
FreeAligned(currentBlock);
for (auto& block : usedBlocks) FreeAligned(block.second);
for (auto& block : availableBlocks) FreeAligned(block.second);
}
void* Alloc(size_t nBytes) {
// Round up _nBytes_ to minimum machine alignment
#if __GNUC__ == 4 && __GNUC_MINOR__ < 9
// gcc bug: max_align_t wasn't in std:: until 4.9.0
const int align = alignof(::max_align_t);
#elif !defined(PBRT_HAVE_ALIGNOF)
const int align = 16;
#else
const int align = alignof(std::max_align_t);
#endif
#ifdef PBRT_HAVE_CONSTEXPR
static_assert(IsPowerOf2(align), "Minimum alignment not a power of two");
#endif
nBytes = (nBytes + align - 1) & ~(align - 1);
if (currentBlockPos + nBytes > currentAllocSize) {
// Add current block to _usedBlocks_ list
if (currentBlock) {
usedBlocks.push_back(
std::make_pair(currentAllocSize, currentBlock));
currentBlock = nullptr;
currentAllocSize = 0;
}
// Get new block of memory for _MemoryArena_
// Try to get memory block from _availableBlocks_
for (auto iter = availableBlocks.begin();
iter != availableBlocks.end(); ++iter) {
if (iter->first >= nBytes) {
currentAllocSize = iter->first;
currentBlock = iter->second;
availableBlocks.erase(iter);
break;
}
}
if (!currentBlock) {
currentAllocSize = std::max(nBytes, blockSize);
currentBlock = AllocAligned<uint8_t>(currentAllocSize);
}
currentBlockPos = 0;
}
void* ret = currentBlock + currentBlockPos;
currentBlockPos += nBytes;
return ret;
}
template <typename T>
T* Alloc(size_t n = 1, bool runConstructor = true) {
T* ret = (T*)Alloc(n * sizeof(T));
if (runConstructor)
for (size_t i = 0; i < n; ++i) new (&ret[i]) T();
return ret;
}
void Reset() {
currentBlockPos = 0;
availableBlocks.splice(availableBlocks.begin(), usedBlocks);
}
size_t TotalAllocated() const {
size_t total = currentAllocSize;
for (const auto& alloc : usedBlocks) total += alloc.first;
for (const auto& alloc : availableBlocks) total += alloc.first;
return total;
}
private:
MemoryArena(const MemoryArena&) = delete;
MemoryArena & operator=(const MemoryArena&) = delete;
// MemoryArena Private Data
const size_t blockSize;
size_t currentBlockPos = 0, currentAllocSize = 0;
uint8_t * currentBlock = nullptr;
std::list<std::pair<size_t, uint8_t*>> usedBlocks, availableBlocks;
};
template <typename T, int logBlockSize>
class BlockedArray {
public:
// BlockedArray Public Methods
BlockedArray(int uRes, int vRes, const T* d = nullptr)
: uRes(uRes), vRes(vRes), uBlocks(RoundUp(uRes) >> logBlockSize) {
int nAlloc = RoundUp(uRes) * RoundUp(vRes);
data = AllocAligned<T>(nAlloc);
for (int i = 0; i < nAlloc; ++i) new (&data[i]) T();
if (d)
for (int v = 0; v < vRes; ++v)
for (int u = 0; u < uRes; ++u) (*this)(u, v) = d[v * uRes + u];
}
const int BlockSize() const { return 1 << logBlockSize; }
int RoundUp(int x) const {
return (x + BlockSize() - 1) & ~(BlockSize() - 1);
}
int uSize() const { return uRes; }
int vSize() const { return vRes; }
~BlockedArray() {
for (int i = 0; i < uRes * vRes; ++i) data[i].~T();
FreeAligned(data);
}
int Block(int a) const { return a >> logBlockSize; }
int Offset(int a) const { return (a & (BlockSize() - 1)); }
T& operator()(int u, int v) {
int bu = Block(u), bv = Block(v);
int ou = Offset(u), ov = Offset(v);
int offset = BlockSize() * BlockSize() * (uBlocks * bv + bu);
offset += BlockSize() * ov + ou;
return data[offset];
}
const T & operator()(int u, int v) const {
int bu = Block(u), bv = Block(v);
int ou = Offset(u), ov = Offset(v);
int offset = BlockSize() * BlockSize() * (uBlocks * bv + bu);
offset += BlockSize() * ov + ou;
return data[offset];
}
void GetLinearArray(T * a) const {
for (int v = 0; v < vRes; ++v)
for (int u = 0; u < uRes; ++u) * a++ = (*this)(u, v);
}
private:
// BlockedArray Private Data
T * data;
const int uRes, vRes, uBlocks;
};
void* AllocAligned(size_t size) {
return _aligned_malloc(size, 32);
}
void FreeAligned(void* ptr) {
if (!ptr) return;
_aligned_free(ptr);
}
and My Source.cpp
#include <iostream>
#include <vector>
#include <chrono>
#include "Point3D.hpp"
#include "Screen.hpp"
#include "BVH.hpp"
#define N 150
int main(){
auto startTime = std::chrono::high_resolution_clock::now();
Screen* screen = new Screen(800, 600, 300);
screen->generatePoints(N);
//for (MortonPrimitive m : mortonPrims) {
// std::cout << m.mortonCode << std::endl;
//}
std::vector<std::shared_ptr<Primitive>> primitives;
primitives.reserve(N);
for (int i = 0; i < N; i++) {
primitives.emplace_back(screen->castPointToPrimitive(i));
}
BVH test(primitives);
auto endTime = std::chrono::high_resolution_clock::now();
std::cout << "Time spent: " << std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count() << "ms\n";
getchar();
delete screen;
}
Probably it would be wise to first cleanup your github. This mean update stuff to the recent c++ standard. It seems that you can use c++17 so use it. Also please look at some names. For example 'nodes' is used as member variable as well as parameter name, this is confusion. Please also initialize relevant (all) member variables.
Now it seems that the code in buildSAH override memory. It seems that it it can write over the end of buckets array.
I'm trying to binary read png's.
Reading images that only use the None, sub, up or average filter work fine.
I used the documentation as described here: http://www.libpng.org/pub/png/spec/1.2/PNG-Filters.html
Original picure:
* Pixel struct *
struct Pixel
{
unsigned char r,g,b;
int all() const { return r + g + b; }
Pixel& operator+=(const Pixel& rhs)
{
this->r = (this->r + rhs.r) % 256;
this->g = (this->g + rhs.g) % 256;
this->b = (this->b + rhs.b) % 256;
return *this;
}
Pixel& operator-=(const Pixel& rhs)
{
this->r = (this->r - rhs.r) % 256;
this->g = (this->g - rhs.g) % 256;
this->b = (this->b - rhs.b) % 256;
return *this;
}
bool operator<=(const Pixel& rhs)
{
return ((this->r <= rhs.r) && (this->g <= rhs.g) && (this->b <= rhs.b));
}
friend Pixel& operator+(Pixel lhs, const Pixel& rhs)
{
lhs += rhs;
return lhs;
}
friend Pixel& operator-(Pixel lhs, const Pixel& rhs)
{
lhs -= rhs;
return lhs;
}
};
* First possibility *
void INC_Image::Paeth(std::vector<Pixel>& thesePixels, std::vector<Pixel>& priorPixels) const
{
for (int i{ 1 }; i < thesePixels.size(); i++)
{
Pixel tempPixel = thesePixels[i];
tempPixel.r = (thesePixels[i].r + PaethPredictor(thesePixels[i - 1].r, priorPixels[i].r, priorPixels[i - 1].r)) % 256;
tempPixel.g = (thesePixels[i].g + PaethPredictor(thesePixels[i - 1].g, priorPixels[i].g, priorPixels[i - 1].g)) % 256;
tempPixel.b = (thesePixels[i].b + PaethPredictor(thesePixels[i - 1].b, priorPixels[i].b, priorPixels[i - 1].b)) % 256;
thesePixels[i] = tempPixel;
}
}
unsigned char INC_Image::PaethPredictor(const unsigned char& previous, const unsigned char& prior, const unsigned char& priorPrevious) const
{
auto p = (previous + prior - priorPrevious) ;
auto pa = abs(p - previous) ;
auto pb = abs(p - prior) ;
auto pc = abs(p - priorPrevious) ;
if (pa <= pb && pa <= pc) return previous ;
else if (pb <= pc) return prior;
else return (priorPrevious );
}
With thesePixels == vector of 1 image line.
With priorPixels == vector of previous image line.
Result:
* Second possibility *
void INC_Image::Paeth(std::vector<Pixel>& thesePixels, std::vector<Pixel>& priorPixels) const
{
for (int i{ 1 }; i < thesePixels.size(); i++)
{
thesePixels[i] += PaethPredictor(thesePixels[i - 1], priorPixels[i], priorPixels[i - 1]);
}
}
Pixel INC_Image::PaethPredictor(const Pixel& previous, const Pixel& prior, const Pixel& priorPrevious) const
{
auto p = previous.all() + prior.all() - priorPrevious.all();
auto pa = abs(p - previous.all());
auto pb = abs(p - prior.all());
auto pc = abs(p - priorPrevious.all());
if (pa <= pb && pa <= pc) return previous;
else if (pb <= pc) return prior;
else return priorPrevious;
}
With thesePixels == vector of 1 image line.
With priorPixels == vector of previous image line.
Result:
I don't know what's wrong with the calculation.
I have a very large number represented by a string. Say String n = "64772890123784224827" . I want to divide the number by 3 efficiently. How can I do it? Some implementations are given below which can find out remainder. But how to get the quotient efficiently?
In Java, the number can be represented with BigInteger and the division operation can be done on BigInteger. But that takes too much time. Please help me find out the efficient way to divide this large number by 3.
Well following is a very basic implementation to find out the remainder:
#include <bits/stdc++.h>
using namespace std;
int divideByN(string, int);
int main()
{
string str = "-64772890123784224827";
//string str = "21";
int N = 3;
int remainder = divideByN(str, N);
cout << "\nThe remainder = " << remainder << endl;
return 0;
}
int divideByN(string s, int n)
{
int carry = 0;
int remainder = 0;
for(int i = 0; i < s.size(); i++)
{
if(i == 0 && s.at(i) == '-')
{
cout << "-";
continue;
}
//Check for any illegal characters here. If any, throw exception.
int tmp = (s.at(i) - '0') + remainder * carry;
cout << (tmp / n);
if(tmp % n == 0)
{
carry = 0;
remainder = 0;
}
else
{
remainder = tmp % n;
carry = 10;
}
}
return remainder;
}
Based on some good answers, here is a minimal implementation using lookup table to find out the remainder:
#include <bits/stdc++.h>
using namespace std;
int divideByN_Lookup(string, int);
int lookup[] = { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0 }; //lookup considering 3 as divisor.
int main() {
string str = "64772890123784224827";
int N = 3;
int remaninder_lookup = divideByN_Lookup(str, N);
cout << "Look up implementation of remainder = " << remaninder_lookup
<< endl;
return 0;
}
int divideByN_Lookup(string s, int n) {
int rem = 0;
int start = 0;
if (s.at(start) == '-')
start = 1;
for (unsigned int i = start; i < s.size(); i++)
rem = (rem + lookup[s.at(i) - '0']) % n;
return rem;
}
What about quotient? I know I can process all characters one by one and add the quotient to a char array or string. But what is the most efficient way to find out the quotient?
If all you need is the remainder after dividing by 3, make a look up table or function that converts each string character digit to an int, which is the remainder when you divide the digit by 3, and add up the ints across all digits in the string, and then there is a fact that the remainder when you divide your original number by 3 is the same as the remainder when you divide the sum of digits by 3. It would be virtually impossible to not be able to fit the sum of 0,1,2 values into a 32 or 64 byte integer. The input would simply have to be too large. And if it does start to become almost too large when you're summing the digits, then just take the remainder when you divide by 3 when you start getting close to the maximum value for an int. Then you can process any length number, using very few division remainder (modulus) operations (which is important because they are much slower than addition).
The reason why the sum-of-digits fact is true is that the remainder when you divide any power of 10 by 3 is always 1.
This is actually very simple. Since every power of 10 is equivalent to 1 modulo 3, all you have to do is add the digits together. The resulting number will have the same remainder when divided by 3 as the original large number.
For example:
3141592654 % 3 = 1
3+1+4+1+5+9+2+6+5+4 = 40
40 % 3 = 1
I think you can start processing from the left, dividing each digit by 3, and adding the remainder to the next one.
In your example you divide the 6, write 2, then divide the 4, write 1 and add the remainder of 1 to the 7 to get 17... Divide the 17... and so on.
EDIT:
I've just verified my solution works using this code. Note you may get a leading zero:
int main( int argc, char* argv[] )
{
int x = 0;
for( char* p = argv[1]; *p; p++ ) {
int d = x*10 + *p-'0';
printf("%d", d/3);
x = d % 3;
}
printf("\n");
return 0;
}
It's not optimal using so many divs and muls, but CS-wise it's O(N) ;-)
I wrote this a while ago.. Doesn't seem slow :S
I've only included the necessary parts for "division"..
#include <string>
#include <cstring>
#include <algorithm>
#include <stdexcept>
#include <iostream>
class BigInteger
{
public:
char sign;
std::string digits;
const std::size_t base = 10;
short toDigit(std::size_t index) const {return index >= 0 && index < digits.size() ? digits[index] - '0' : 0;}
protected:
void Normalise();
BigInteger& divide(const BigInteger &Divisor, BigInteger* Remainder);
public:
BigInteger();
BigInteger(const std::string &value);
inline bool isNegative() const {return sign == '-';}
inline bool isPositive() const {return sign == '+';}
inline bool isNeutral() const {return sign == '~';}
inline std::string toString() const
{
std::string digits = this->digits;
std::reverse(digits.begin(), digits.end());
if (!isNeutral())
{
std::string sign;
sign += this->sign;
return sign + digits;
}
return digits;
}
bool operator < (const BigInteger &other) const;
bool operator > (const BigInteger &other) const;
bool operator <= (const BigInteger &other) const;
bool operator >= (const BigInteger &other) const;
bool operator == (const BigInteger &other) const;
bool operator != (const BigInteger &other) const;
BigInteger& operator /= (const BigInteger &other);
BigInteger operator / (const BigInteger &other) const;
BigInteger Remainder(const BigInteger &other) const;
};
BigInteger::BigInteger() : sign('~'), digits(1, '0') {}
BigInteger::BigInteger(const std::string &value) : sign('~'), digits(value)
{
sign = digits.empty() ? '~' : digits[0] == '-' ? '-' : '+';
if (digits[0] == '+' || digits[0] == '-') digits.erase(0, 1);
std::reverse(digits.begin(), digits.end());
Normalise();
for (std::size_t I = 0; I < digits.size(); ++I)
{
if (!isdigit(digits[I]))
{
sign = '~';
digits = "0";
break;
}
}
}
void BigInteger::Normalise()
{
for (int I = digits.size() - 1; I >= 0; --I)
{
if (digits[I] != '0') break;
digits.erase(I, 1);
}
if (digits.empty())
{
digits = "0";
sign = '~';
}
}
bool BigInteger::operator < (const BigInteger &other) const
{
if (isNeutral() || other.isNeutral())
{
return isNeutral() ? other.isPositive() : isNegative();
}
if (sign != other.sign)
{
return isNegative();
}
if (digits.size() != other.digits.size())
{
return (digits.size() < other.digits.size() && isPositive()) || (digits.size() > other.digits.size() && isNegative());
}
for (int I = digits.size() - 1; I >= 0; --I)
{
if (toDigit(I) < other.toDigit(I))
return isPositive();
if (toDigit(I) > other.toDigit(I))
return isNegative();
}
return false;
}
bool BigInteger::operator > (const BigInteger &other) const
{
if (isNeutral() || other.isNeutral())
{
return isNeutral() ? other.isNegative() : isPositive();
}
if ((sign != other.sign) && !(isNeutral() || other.isNeutral()))
{
return isPositive();
}
if (digits.size() != other.digits.size())
{
return (digits.size() > other.digits.size() && isPositive()) || (digits.size() < other.digits.size() && isNegative());
}
for (int I = digits.size() - 1; I >= 0; --I)
{
if (toDigit(I) > other.toDigit(I))
return isPositive();
if (toDigit(I) < other.toDigit(I))
return isNegative();
}
return false;
}
bool BigInteger::operator <= (const BigInteger &other) const
{
return (*this < other) || (*this == other);
}
bool BigInteger::operator >= (const BigInteger &other) const
{
return (*this > other) || (*this == other);
}
bool BigInteger::operator == (const BigInteger &other) const
{
if (sign != other.sign || digits.size() != other.digits.size())
return false;
for (int I = digits.size() - 1; I >= 0; --I)
{
if (toDigit(I) != other.toDigit(I))
return false;
}
return true;
}
bool BigInteger::operator != (const BigInteger &other) const
{
return !(*this == other);
}
BigInteger& BigInteger::divide(const BigInteger &Divisor, BigInteger* Remainder)
{
if (Divisor.isNeutral())
{
throw std::overflow_error("Division By Zero Exception.");
}
char rem_sign = sign;
bool neg_res = sign != Divisor.sign;
if (!isNeutral()) sign = '+';
if (*this < Divisor)
{
if (Remainder)
{
Remainder->sign = this->sign;
Remainder->digits = this->digits;
}
sign = '~';
digits = "0";
return *this;
}
if (this == &Divisor)
{
if (Remainder)
{
Remainder->sign = this->sign;
Remainder->digits = this->digits;
}
sign = '+';
digits = "1";
return *this;
}
BigInteger Dvd(*this);
BigInteger Dvr(Divisor);
BigInteger Quotient("0");
Dvr.sign = '+';
std::size_t len = std::max(Dvd.digits.size(), Dvr.digits.size());
std::size_t diff = std::max(Dvd.digits.size(), Dvr.digits.size()) - std::min(Dvd.digits.size(), Dvr.digits.size());
std::size_t offset = len - diff - 1;
Dvd.digits.resize(len, '0');
Dvr.digits.resize(len, '0');
Quotient.digits.resize(len, '0');
memmove(&Dvr.digits[diff], &Dvr.digits[0], len - diff);
memset(&Dvr.digits[0], '0', diff);
while(offset < len)
{
while (Dvd >= Dvr)
{
int borrow = 0, total = 0;
for (std::size_t I = 0; I < len; ++I)
{
total = Dvd.toDigit(I) - Dvr.toDigit(I) - borrow;
borrow = 0;
if (total < 0)
{
borrow = 1;
total += 10;
}
Dvd.digits[I] = total + '0';
}
Quotient.digits[len - offset - 1]++;
}
if (Remainder && offset == len - 1)
{
Remainder->digits = Dvd.digits;
Remainder->sign = rem_sign;
Remainder->Normalise();
if (Remainder == this)
{
return *this;
}
}
memmove(&Dvr.digits[0], &Dvr.digits[1], len - 1);
memset(&Dvr.digits[len - 1], '0', 1);
++offset;
}
Quotient.sign = neg_res ? '-' : '+';
Quotient.Normalise();
this->sign = Quotient.sign;
this->digits = Quotient.digits;
return *this;
}
BigInteger& BigInteger::operator /= (const BigInteger &other)
{
return divide(other, nullptr);
}
BigInteger BigInteger::operator / (const BigInteger &other) const
{
return BigInteger(*this) /= other;
}
BigInteger BigInteger::Remainder(const BigInteger &other) const
{
BigInteger remainder;
BigInteger(*this).divide(other, &remainder);
return remainder;
}
int main()
{
BigInteger a{"-64772890123784224827"};
BigInteger b{"3"};
BigInteger result = a/b;
std::cout<<result.toString();
}
How can i store a big number in a variable and use a for loop?
I have a very big number 75472202764752234070123900087933251 and i need to loop from 0 to this number!
Is it even possible to do this? how much time will it take to end?
EDIT: i am trying to solve a hard problem by brute force. its a combination problem.the bruteforcing cases may reach 470C450.
so i guess i should use a different algorithm...
This might take
0.23 x 10^23 years if C++ processed 100,000 loops per second :|
http://www.wolframalpha.com/input/?i=75472202764752234070123900087933251%2F%28100000*1*3600*24*365%29
It looks that this number fits into 128 bit. So you could use a modern system and a modern compiler that implements such numbers. This would e.g be the case for a 64bit linux system with gcc as a compiler. This has something like __uint128_t that you could use.
Obviously you can't use such a variable as a for-loop variable, others have give you the calculations. But you could use it to store some of your calculations.
Well, you would need an implementation that can handle at least a subset of the initialization, boolean, and arithmetic functions on very large integers. Something like: https://mattmccutchen.net/bigint/.
For something that would give a bit better performance than a general large integer math library, you could use specialized operations specifically to allow use of a large integer as a counter. For an example of this, see dewtell's updated answer to this question.
As for it being possible for you to loop from 0 to that number: well, yes, it is possible to write the code for it with one of the above solutions, but I think the answer is no, you personally will not be able to do it because you will not be alive to see it finish.
[edit: Yes, I would definitely recommend you find a different algorithm. :D]
If you need to loop a certain number of times, and that number is greater than 2^64, just use while(1) because your computer will break before it counts up to 2^64 anyway.
There's no need for a complete bignum package - if all you need is a loop counter, here's a simple byte counter that uses an array of bytes as a counter. It stops when the byte array wraps around to all zeros again. If you wanted to count to some other value than 2^(bytesUsed*CHAR_BITS), you could just compute the two's complement value of the negative of the number of iterations you wanted, and let it count up to 0, keeping in mind that bytes[0] is the low-order byte (or use the positive value and count down instead of up).
#include <stdio.h>
#define MAXBYTES 20
/* Simple byte counter - note it uses argc as # of bytes to use for convenience */
int main(int argc, char **argv) {
unsigned char bytes[MAXBYTES];
const int bytesUsed = argc < MAXBYTES? argc : MAXBYTES;
int i;
unsigned long counter = (unsigned long)-1; /* to give loop something to do */
for (i = 0; i < bytesUsed; i++) bytes[i] = 0; /* Initialize bytes */
do {
for (i = 0; i < bytesUsed && !++bytes[i]; i++) ; /* NULL BODY - this is the byte counter */
counter++;
} while (i < bytesUsed);
printf("With %d bytes used, final counter value = %lu\n", bytesUsed, counter);
}
Run times for the first 4 values (under Cygwin, on a Lenovo T61):
$ time ./bytecounter
With 1 bytes used, final counter value = 255
real 0m0.078s
user 0m0.031s
sys 0m0.046s
$ time ./bytecounter a
With 2 bytes used, final counter value = 65535
real 0m0.063s
user 0m0.031s
sys 0m0.031s
$ time ./bytecounter a a
With 3 bytes used, final counter value = 16777215
real 0m0.125s
user 0m0.015s
sys 0m0.046s
$ time ./bytecounter a a a
With 4 bytes used, final counter value = 4294967295
real 0m6.578s
user 0m0.015s
sys 0m0.047s
At this rate, five bytes should take around half an hour, and six bytes should take the better part of a week. Of course the counter value will be inaccurate for those - it's mostly just there to verify the number of iterations for the smaller byte values and give the loop something to do.
Edit: And here's the time for five bytes, around half an hour as I predicted:
$ time ./bytecounter a a a a
With 5 bytes used, final counter value = 4294967295
real 27m22.184s
user 0m0.015s
sys 0m0.062s
Ok, here's code to take an arbitrary decimal number passed as the first arg and count down from it to zero. I set it up to allow the counter to use different size elements (just change the typedef for COUNTER_BASE), but it turns out that bytes are actually somewhat faster than either short or long on my system.
#include <stdio.h>
#include <limits.h> // defines CHAR_BIT
#include <ctype.h>
#include <vector>
using std::vector;
typedef unsigned char COUNTER_BASE;
typedef vector<COUNTER_BASE> COUNTER;
typedef vector<unsigned char> BYTEVEC;
const unsigned long byteMask = (~0ul) << CHAR_BIT;
const size_t MAXBYTES=20;
void mult10(BYTEVEC &val) {
// Multiply value by 10
unsigned int carry = 0;
int i;
for (i = 0; i < val.size(); i++) {
unsigned long value = val[i]*10ul+carry;
carry = (value & byteMask) >> CHAR_BIT;
val[i] = value & ~byteMask;
}
if (carry > 0) val.push_back(carry);
}
void addDigit(BYTEVEC &val, const char digit) {
// Add digit to the number in BYTEVEC.
unsigned int carry = digit - '0'; // Assumes ASCII char set
int i;
for (i = 0; i < val.size() && carry; i++) {
unsigned long value = static_cast<unsigned long>(val[i])+carry;
carry = (value & byteMask) >> CHAR_BIT;
val[i] = value & ~byteMask;
}
if (carry > 0) val.push_back(carry);
}
BYTEVEC Cstr2Bytevec(const char *str) {
// Turn a C-style string into a BYTEVEC. Only the digits in str apply,
// so that one can use commas, underscores, or other non-digits to separate
// digit groups.
BYTEVEC result;
result.reserve(MAXBYTES);
result[0]=0;
unsigned char *res=&result[0]; // For debugging
while (*str) {
if (isdigit(static_cast<int>(*str))) {
mult10(result);
addDigit(result, *str);
}
str++;
}
return result;
}
void packCounter(COUNTER &ctr, const BYTEVEC &val) {
// Pack the bytes from val into the (possibly larger) datatype of COUNTER
int i;
ctr.erase(ctr.begin(), ctr.end());
COUNTER_BASE value = 0;
for (i = 0; i < val.size(); i++) {
int pos = i%sizeof(COUNTER_BASE); // position of this byte in the value
if (i > 0 && pos == 0) {
ctr.push_back(value);
value = val[i];
} else {
value |= static_cast<COUNTER_BASE>(val[i]) << pos*CHAR_BIT;
}
}
ctr.push_back(value);
}
inline bool decrementAndTest(COUNTER &ctr) {
// decrement value in ctr and return true if old value was not all zeros
int i;
for (i = 0; i < ctr.size() && !(ctr[i]--); i++) ; // EMPTY BODY
return i < ctr.size();
}
inline bool decrementAndTest2(COUNTER_BASE *ctr, const size_t size) {
// decrement value in ctr and return true if old value was not all zeros
int i;
for (i = 0; i < size && !(ctr[i]--); i++) ; // EMPTY BODY
return i < size;
}
/* Vector counter - uses first arg (if supplied) as the count */
int main(int argc, const char *argv[]) {
BYTEVEC limit = Cstr2Bytevec(argc > 1? argv[1] : "0");
COUNTER ctr;
packCounter(ctr, limit);
COUNTER_BASE *ctr_vals = ctr.size() > 0 ? &ctr[0] : NULL;
size_t ctr_size = ctr.size();
unsigned long ul_counter = 0ul; /* to give loop something to do */
while(decrementAndTest2(ctr_vals, ctr_size)) {
ul_counter++;
};
printf("With %d bytes used, final ul_counter value = %lu\n", limit.size(), ul_counter);
return 0;
}
Examples of use:
$ time ./bigcounter 5
With 1 bytes used, final ul_counter value = 5
real 0m0.094s
user 0m0.031s
sys 0m0.047s
$ time ./bigcounter 5,000
With 2 bytes used, final ul_counter value = 5000
real 0m0.062s
user 0m0.015s
sys 0m0.062s
$ time ./bigcounter 5,000,000
With 3 bytes used, final ul_counter value = 5000000
real 0m0.093s
user 0m0.015s
sys 0m0.046s
$ time ./bigcounter 1,000,000,000
With 4 bytes used, final ul_counter value = 1000000000
real 0m2.688s
user 0m0.015s
sys 0m0.015s
$ time ./bigcounter 2,000,000,000
With 4 bytes used, final ul_counter value = 2000000000
real 0m5.125s
user 0m0.015s
sys 0m0.046s
$ time ./bigcounter 3,000,000,000
With 4 bytes used, final ul_counter value = 3000000000
real 0m7.485s
user 0m0.031s
sys 0m0.047s
$ time ./bigcounter 4,000,000,000
With 4 bytes used, final ul_counter value = 4000000000
real 0m9.875s
user 0m0.015s
sys 0m0.046s
$ time ./bigcounter 5,000,000,000
With 5 bytes used, final ul_counter value = 705032704
real 0m12.594s
user 0m0.046s
sys 0m0.015s
$ time ./bigcounter 6,000,000,000
With 5 bytes used, final ul_counter value = 1705032704
real 0m14.813s
user 0m0.015s
sys 0m0.062s
Unwrapping the counter vector into C-style data structures (i.e., using decrementAndTest2 instead of decrementAndTest) sped things up by around 20-25%, but the code is still about twice as slow as my previous C program for similar-sized examples (around 4 billion). This is with MS Visual C++ 6.0 as the compiler in release mode, optimizing for speed, on a 2GHz dual-core system, for both programs. Inlining the decrementAndTest2 function definitely makes a big difference (around 12 sec. vs. 30 for the 5 billion loop), but I'll have to see whether physically inlining the code as I did in the C program can get similar performance.
the variable in main function can Store even 100 factorial
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <stack>
#include <queue>
#include <deque>
#include <limits>
#include <cmath>
#include <numeric>
#include <set>
using namespace std;
//template for BIGINIT
// base and base_digits must be consistent
const int base = 10;
const int base_digits = 1;
struct bigint {
vector<int> a;
int sign;
bigint() :
sign(1) {
}
bigint(long long v) {
*this = v;
}
bigint(const string &s) {
read(s);
}
void operator=(const bigint &v) {
sign = v.sign;
a = v.a;
}
void operator=(long long v) {
sign = 1;
if (v < 0)
sign = -1, v = -v;
for (; v > 0; v = v / base)
a.push_back(v % base);
}
bigint operator+(const bigint &v) const {
if (sign == v.sign) {
bigint res = v;
for (int i = 0, carry = 0; i < (int) max(a.size(), v.a.size()) || carry; ++i) {
if (i == (int) res.a.size())
res.a.push_back(0);
res.a[i] += carry + (i < (int) a.size() ? a[i] : 0);
carry = res.a[i] >= base;
if (carry)
res.a[i] -= base;
}
return res;
}
return *this - (-v);
}
bigint operator-(const bigint &v) const {
if (sign == v.sign) {
if (abs() >= v.abs()) {
bigint res = *this;
for (int i = 0, carry = 0; i < (int) v.a.size() || carry; ++i) {
res.a[i] -= carry + (i < (int) v.a.size() ? v.a[i] : 0);
carry = res.a[i] < 0;
if (carry)
res.a[i] += base;
}
res.trim();
return res;
}
return -(v - *this);
}
return *this + (-v);
}
void operator*=(int v) {
if (v < 0)
sign = -sign, v = -v;
for (int i = 0, carry = 0; i < (int) a.size() || carry; ++i) {
if (i == (int) a.size())
a.push_back(0);
long long cur = a[i] * (long long) v + carry;
carry = (int) (cur / base);
a[i] = (int) (cur % base);
//asm("divl %%ecx" : "=a"(carry), "=d"(a[i]) : "A"(cur), "c"(base));
}
trim();
}
bigint operator*(int v) const {
bigint res = *this;
res *= v;
return res;
}
friend pair<bigint, bigint> divmod(const bigint &a1, const bigint &b1) {
int norm = base / (b1.a.back() + 1);
bigint a = a1.abs() * norm;
bigint b = b1.abs() * norm;
bigint q, r;
q.a.resize(a.a.size());
for (int i = a.a.size() - 1; i >= 0; i--) {
r *= base;
r += a.a[i];
int s1 = r.a.size() <= b.a.size() ? 0 : r.a[b.a.size()];
int s2 = r.a.size() <= b.a.size() - 1 ? 0 : r.a[b.a.size() - 1];
int d = ((long long) base * s1 + s2) / b.a.back();
r -= b * d;
while (r < 0)
r += b, --d;
q.a[i] = d;
}
q.sign = a1.sign * b1.sign;
r.sign = a1.sign;
q.trim();
r.trim();
return make_pair(q, r / norm);
}
bigint operator/(const bigint &v) const {
return divmod(*this, v).first;
}
bigint operator%(const bigint &v) const {
return divmod(*this, v).second;
}
void operator/=(int v) {
if (v < 0)
sign = -sign, v = -v;
for (int i = (int) a.size() - 1, rem = 0; i >= 0; --i) {
long long cur = a[i] + rem * (long long) base;
a[i] = (int) (cur / v);
rem = (int) (cur % v);
}
trim();
}
bigint operator/(int v) const {
bigint res = *this;
res /= v;
return res;
}
int operator%(int v) const {
if (v < 0)
v = -v;
int m = 0;
for (int i = a.size() - 1; i >= 0; --i)
m = (a[i] + m * (long long) base) % v;
return m * sign;
}
void operator+=(const bigint &v) {
*this = *this + v;
}
void operator-=(const bigint &v) {
*this = *this - v;
}
void operator*=(const bigint &v) {
*this = *this * v;
}
void operator/=(const bigint &v) {
*this = *this / v;
}
bool operator<(const bigint &v) const {
if (sign != v.sign)
return sign < v.sign;
if (a.size() != v.a.size())
return a.size() * sign < v.a.size() * v.sign;
for (int i = a.size() - 1; i >= 0; i--)
if (a[i] != v.a[i])
return a[i] * sign < v.a[i] * sign;
return false;
}
bool operator>(const bigint &v) const {
return v < *this;
}
bool operator<=(const bigint &v) const {
return !(v < *this);
}
bool operator>=(const bigint &v) const {
return !(*this < v);
}
bool operator==(const bigint &v) const {
return !(*this < v) && !(v < *this);
}
bool operator!=(const bigint &v) const {
return *this < v || v < *this;
}
void trim() {
while (!a.empty() && !a.back())
a.pop_back();
if (a.empty())
sign = 1;
}
bool isZero() const {
return a.empty() || (a.size() == 1 && !a[0]);
}
bigint operator-() const {
bigint res = *this;
res.sign = -sign;
return res;
}
bigint abs() const {
bigint res = *this;
res.sign *= res.sign;
return res;
}
long long longValue() const {
long long res = 0;
for (int i = a.size() - 1; i >= 0; i--)
res = res * base + a[i];
return res * sign;
}
friend bigint gcd(const bigint &a, const bigint &b) {
return b.isZero() ? a : gcd(b, a % b);
}
friend bigint lcm(const bigint &a, const bigint &b) {
return a / gcd(a, b) * b;
}
void read(const string &s) {
sign = 1;
a.clear();
int pos = 0;
while (pos < (int) s.size() && (s[pos] == '-' || s[pos] == '+')) {
if (s[pos] == '-')
sign = -sign;
++pos;
}
for (int i = s.size() - 1; i >= pos; i -= base_digits) {
int x = 0;
for (int j = max(pos, i - base_digits + 1); j <= i; j++)
x = x * 10 + s[j] - '0';
a.push_back(x);
}
trim();
}
friend istream& operator>>(istream &stream, bigint &v) {
string s;
stream >> s;
v.read(s);
return stream;
}
friend ostream& operator<<(ostream &stream, const bigint &v) {
if (v.sign == -1)
stream << '-';
stream << (v.a.empty() ? 0 : v.a.back());
for (int i = (int) v.a.size() - 2; i >= 0; --i)
stream << setw(base_digits) << setfill('0') << v.a[i];
return stream;
}
static vector<int> convert_base(const vector<int> &a, int old_digits, int new_digits) {
vector<long long> p(max(old_digits, new_digits) + 1);
p[0] = 1;
for (int i = 1; i < (int) p.size(); i++)
p[i] = p[i - 1] * 10;
vector<int> res;
long long cur = 0;
int cur_digits = 0;
for (int i = 0; i < (int) a.size(); i++) {
cur += a[i] * p[cur_digits];
cur_digits += old_digits;
while (cur_digits >= new_digits) {
res.push_back(int(cur % p[new_digits]));
cur /= p[new_digits];
cur_digits -= new_digits;
}
}
res.push_back((int) cur);
while (!res.empty() && !res.back())
res.pop_back();
return res;
}
typedef vector<long long> vll;
static vll karatsubaMultiply(const vll &a, const vll &b) {
int n = a.size();
vll res(n + n);
if (n <= 32) {
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
res[i + j] += a[i] * b[j];
return res;
}
int k = n >> 1;
vll a1(a.begin(), a.begin() + k);
vll a2(a.begin() + k, a.end());
vll b1(b.begin(), b.begin() + k);
vll b2(b.begin() + k, b.end());
vll a1b1 = karatsubaMultiply(a1, b1);
vll a2b2 = karatsubaMultiply(a2, b2);
for (int i = 0; i < k; i++)
a2[i] += a1[i];
for (int i = 0; i < k; i++)
b2[i] += b1[i];
vll r = karatsubaMultiply(a2, b2);
for (int i = 0; i < (int) a1b1.size(); i++)
r[i] -= a1b1[i];
for (int i = 0; i < (int) a2b2.size(); i++)
r[i] -= a2b2[i];
for (int i = 0; i < (int) r.size(); i++)
res[i + k] += r[i];
for (int i = 0; i < (int) a1b1.size(); i++)
res[i] += a1b1[i];
for (int i = 0; i < (int) a2b2.size(); i++)
res[i + n] += a2b2[i];
return res;
}
bigint operator*(const bigint &v) const {
vector<int> a6 = convert_base(this->a, base_digits, 6);
vector<int> b6 = convert_base(v.a, base_digits, 6);
vll a(a6.begin(), a6.end());
vll b(b6.begin(), b6.end());
while (a.size() < b.size())
a.push_back(0);
while (b.size() < a.size())
b.push_back(0);
while (a.size() & (a.size() - 1))
a.push_back(0), b.push_back(0);
vll c = karatsubaMultiply(a, b);
bigint res;
res.sign = sign * v.sign;
for (int i = 0, carry = 0; i < (int) c.size(); i++) {
long long cur = c[i] + carry;
res.a.push_back((int) (cur % 1000000));
carry = (int) (cur / 1000000);
}
res.a = convert_base(res.a, 6, base_digits);
res.trim();
return res;
}
};
//use : bigint var;
//template for biginit over
int main()
{
bigint var=10909000890789;
cout<<var;
return 0;
}