I have the following problem : I have a hex number (datatype : std::uint64_t) in C++, and the hex number contains all the digits from 1 to a given n. The question is now to rotate the first k digits of the hex number, for example :
hex = 0x436512, k = 3 --> 0x634512
I have already tried splitting the hex number into two parts, e.g
std::uint64_t left = hex >> ((n - k) * 4);
std::uint64_t right = ((1UL << ((n - k) * 4)) - 1) & hex;
and then rotating left and merging left and right together. Is there a possibility to do this in-place and by only using bit-manipulation and/or mathematical operators?
As a baseline you can use this which is basically converting to digits and back.
#include <cstdio>
#include <cstdint>
#include <array>
uint64_t rotate( uint64_t value, int k ) {
// decompose
std::array<uint8_t,16> digits;
int numdigits = 0;
while ( value > 0 ) {
digits[numdigits] = value % 16;
value = value / 16;
numdigits += 1;
}
if ( k>numdigits ) return 0;
// revert digits
int p1 = numdigits - 1;
int p2 = numdigits - k;
for ( ; p1>p2; p1--,p2++ ) {
uint8_t tmp = digits[p1];
digits[p1] = digits[p2];
digits[p2] = tmp;
}
// reconstruct
for ( int j=0; j<numdigits; ++j ) {
value = (value*16) + digits[numdigits-1-j];
}
return value;
}
int main() {
uint64_t value = 0x123ffffff;
for ( int j=0; j<8; ++j ) {
value = value >> 4;
printf( "%lx %lx\n", value, rotate(value,3) );
}
}
Godbolt: https://godbolt.org/z/77qWEo9vE
It produces:
Program stdout
123fffff 321fffff
123ffff 321ffff
123fff 321fff
123ff 321ff
123f 321f
123 321
12 0
1 0
You actually do not need to decompose the entire number, you can strictly decompose only the left digits.
#include <cstdio>
#include <cstdint>
#include <array>
uint64_t rotate( uint64_t value, int k ) {
// sanity check
if ( value == 0 ) return 0;
// fast find number of digits
int numdigits = (63-__builtin_clzl(value))/4 + 1;
if ( k>numdigits ) return 0;
// Decompose left and right
int rightbits = 4*(numdigits-k);
uint64_t left = value >> rightbits;
uint64_t right = rightbits==0 ? 0 : value & (uint64_t(-1)>>(64-rightbits));
// decompose left
uint64_t rot = 0;
for ( int j=0; j<k; ++j ) {
uint64_t digit = left % 16;
left = left / 16;
rot = (rot*16) + digit;
}
// rejoin
return right | (rot<<rightbits);
}
int main() {
uint64_t value = 0x123ffffff;
for ( int j=0; j<8; ++j ) {
value = value >> 4;
printf( "%lx %lx\n", value, rotate(value,3) );
}
}
Produces the same output.
Godbolt: https://godbolt.org/z/P3z6W8b3M
Running under Google benchmark:
#include <benchmark/benchmark.h>
#include <vector>
#include <iostream>
uint64_t rotate1(uint64_t value, int k);
uint64_t rotate2(uint64_t value, int k);
struct RotateTrivial {
uint64_t operator()(uint64_t value, int k) {
return rotate1(value, k);
}
};
struct RotateLeftOnly {
uint64_t operator()(uint64_t value, int k) {
return rotate2(value, k);
}
};
template <typename Fn>
static void Benchmark(benchmark::State& state) {
Fn fn;
for (auto _ : state) {
uint64_t value = uint64_t(-1);
for (int j = 0; j < 16; ++j) {
for (int k = 1; k < j; ++k) {
uint64_t result = fn(value, k);
benchmark::DoNotOptimize(result);
}
value = value >> 4;
}
}
}
BENCHMARK(Benchmark<RotateTrivial>);
BENCHMARK(Benchmark<RotateLeftOnly>);
BENCHMARK_MAIN();
Produces on an AMD Threadripper 3960x 3.5GHz
--------------------------------------------------------------------
Benchmark Time CPU Iterations
--------------------------------------------------------------------
Benchmark<RotateTrivial> 619 ns 619 ns 1158174
Benchmark<RotateLeftOnly> 320 ns 320 ns 2222098
Each iteration has 105 calls so it's about 6.3 ns/call or 20 cycles for the trivial version and 3.1ns/call or 10 cycles for the optimized version.
Related
Given an array A of n integers and given queries in the form of range [l , r] and a value x, find the minimum of A[i] XOR x where l <= i <= r and x will be different for different queries.
I tried solving this problem using segment trees but I am not sure what type of information I should store in them as x will be different for different queries.
0 < number of queries <= 1e4
0 < n <= 1e4
To solve this I used a std::vector as basis (not an array, or std::array), just for flexibility.
#include <algorithm>
#include <stdexcept>
#include <vector>
int get_xored_max(const std::vector<int>& values, const size_t l, const size_t r, const int xor_value)
{
// check bounds of l and r
if ((l >= values.size()) || (r >= values.size()))
{
throw std::invalid_argument("index out of bounds");
}
// todo check l < r
// create left & right iterators to create a smaller vector
// only containing the subset we're interested in.
auto left = values.begin() + l;
auto right = values.begin() + r + 1;
std::vector<int> range{ left, right };
// xor all the values in the subset
for (auto& v : range)
{
v ^= xor_value;
}
// use the standard library function for finding the iterator to the maximum
// then use the * to dereference the iterator and get the value
auto max_value = *std::max_element(range.begin(), range.end());
return max_value;
}
int main()
{
std::vector<int> values{ 1,3,5,4,2,4,7,9 };
auto max_value = get_xored_max(values, 0u, 7u, 3);
return 0;
}
Approach - Trie + Offline Processing
Time Complexity - O(N32)
Space Complexity - O(N32)
Edit:
This Approach will fail. I guess, we have to use square root decomposition instead of two pointers approach.
I have solved this problem using Trie for finding minimum xor in a range of [l,r]. I solved queries by offline processing by sorting them.
Input format:
the first line has n (no. of elements) and q (no. of queries). the second line has all n elements of the array. each subsequent line has a query and each query has 3 inputs l, r and x.
Example -
Input -
3 3
2 1 2
1 2 3
1 3 2
2 3 5
First, convert all 3 queries into queries sorted by l and r.
converted queries -
1 2 3
1 3 2
2 3 5
Key here is processing over sorted queries using two pointers approach.
#include <bits/stdc++.h>
using namespace std;
const int N = (int)2e4 + 77;
int n, q, l, r, x;
int a[N], ans[N];
vector<pair<pair<int, int>, pair<int, int>>> queries;
// Trie Implementation starts
struct node
{
int nxt[2], cnt;
void newnode()
{
memset(nxt, 0, sizeof(nxt));
cnt = 0;
}
} trie[N * 32];
int tot = 1;
void update(int x, int v)
{
int p = 1;
for (int i = 31; i >= 0; i--)
{
int id = x >> i & 1;
if (!trie[p].nxt[id])
{
trie[++tot].newnode();
trie[p].nxt[id] = tot;
}
p = trie[p].nxt[id];
trie[p].cnt += v;
}
}
int minXor(int x)
{
int res = 0, p = 1;
for (int i = 31; i >= 0; i--)
{
int id = x >> i & 1;
if (trie[p].nxt[id] and trie[trie[p].nxt[id]].cnt)
p = trie[p].nxt[id];
else
{
p = trie[p].nxt[id ^ 1];
res |= 1 << i;
}
}
return res;
}
// Trie Implementation ends
int main()
{
cin >> n >> q;
for (int i = 1; i <= n; i += 1)
{
cin >> a[i];
}
for (int i = 1; i <= q; i += 1)
{
cin >> l >> r >> x;
queries.push_back({{l, r}, {x, i}});
}
sort(queries.begin(), queries.end());
int left = 1, right = 1;
for (int i = 0; i < q; i += 1)
{
int l = queries[i].first.first;
int r = queries[i].first.second;
int x = queries[i].second.first;
int index = queries[i].second.second;
while (left < l)
{
update(a[left], -1);
left += 1;
}
while (right <= r)
{
update(a[right], 1);
right += 1;
}
ans[index] = minXor(x);
}
for (int i = 1; i <= q; i += 1)
{
cout << ans[i] << " \n";
}
return 0;
}
Edit: with O(number of bits) code
Use a binary tree to store the values of A, look here : Minimum XOR for queries
What you need to change is adding to each node the range of indexes for A corresponding to the values in the leafs.
# minimal xor in a range
nbits=16 # Number of bits for numbers
asize=5000 # Array size
ntest=50 # Number of random test
from random import randrange
# Insert element a iindex iin the tree (increasing i only)
def tinsert(a,i,T):
for b in range(nbits-1,-1,-1):
v=((a>>b)&1)
T[v+2].append(i)
if T[v]==[]:T[v]=[[],[],[],[]]
T=T[v]
# Buildtree : builds a tree based on array V
def build(V):
T=[[],[],[],[]] # Init tree
for i,a in enumerate(V): tinsert(a,i,T)
return(T)
# Binary search : is T intersec [a,b] non empty ?
def binfind(T,a,b):
s,e,om=0,len(T)-1,-1
while True:
m=(s+e)>>1
v=T[m]
if v<a:
s=m
if m==om: return(a<=T[e]<=b)
elif v>b:
e=m
if m==om: return(a<=T[s]<=b)
else: return(True) # a<=T(m)<=b
om=m
# Look for the min xor in a give range index
def minx(x,s,e,T):
if s<0 or s>=(len(T[2])+len(T[3])) or e<s: return
r=0
for b in range(nbits-1,-1,-1):
v=((x>>b)&1)
if T[v+2]==[] or not binfind(T[v+2],s,e): # not nr with b set to v ?
v=1-v
T=T[v]
r=(r<<1)|v
return(r)
# Tests the code on random arrays
max=(1<<nbits)-1
for i in range(ntest):
A=[randrange(0,max) for i in range(asize)]
T=build(A)
x,s=randrange(0,max),randrange(0,asize-1)
e=randrange(s,asize)
if min(v^x for v in A[s:e+1])!=x^minx(x,s,e,T):
print('error')
I was able to solve this using segment tree and tries as suggested by #David Eisenstat
Below is an implementation in c++.
I constructed a trie for each segment in the segment tree. And finding the minimum xor is just traversing and matching the corresponding trie using each bit of the query value (here)
#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = a; i < b; i++)
using namespace std;
const int bits = 7;
struct trie {
trie *children[2];
bool end;
};
trie *getNode(void)
{
trie *node = new trie();
node->end = false;
node->children[0] = NULL;
node->children[1] = NULL;
return node;
}
trie *merge(trie *l, trie *r)
{
trie *node = getNode();
// Binary 0:
if (l->children[0] && r->children[0])
node->children[0] = merge(l->children[0], r->children[0]);
else if (!r->children[0])
node->children[0] = l->children[0];
else if (!l->children[0])
node->children[0] = r->children[0];
// Binary 1:
if (l->children[1] && r->children[1])
node->children[1] = merge(l->children[1], r->children[1]);
else if (!r->children[1])
node->children[1] = l->children[1];
else if (!l->children[1])
node->children[1] = r->children[1];
return node;
}
void insert(trie *root, int num)
{
int mask = 1 << bits;
int bin;
rep(i, 0, bits + 1)
{
bin = ((num & mask) >> (bits - i));
if (!root->children[bin]) root->children[bin] = getNode();
root = root->children[bin];
mask = mask >> 1;
}
root->end = true;
}
struct _segTree {
int n, height, size;
vector<trie *> tree;
_segTree(int _n)
{
n = _n;
height = (int)ceil(log2(n));
size = (int)(2 * pow(2, height) - 1);
tree.resize(size);
}
trie *construct(vector<int> A, int start, int end, int idx)
{
if (start == end) {
tree[idx] = getNode();
insert(tree[idx], A[start]);
return tree[idx];
}
int mid = start + (end - start) / 2;
tree[idx] = merge(construct(A, start, mid, 2 * idx + 1),
construct(A, mid + 1, end, 2 * idx + 2));
return tree[idx];
}
int findMin(int num, trie *root)
{
int mask = 1 << bits;
int bin;
int rnum = 0;
int res = 0;
rep(i, 0, bits + 1)
{
bin = ((num & mask) >> (bits - i));
if (!root->children[bin]) {
bin = 1 - bin;
if (!root->children[bin]) return res ^ num;
}
rnum |= (bin << (bits - i));
root = root->children[bin];
if (root->end) res = rnum;
mask = mask >> 1;
}
return res ^ num;
}
int Query(int X, int start, int end, int qstart, int qend, int idx)
{
if (qstart <= start && qend >= end) return findMin(X, tree[idx]);
if (qstart > end || qend < start) return INT_MAX;
int mid = start + (end - start) / 2;
return min(Query(X, start, mid, qstart, qend, 2 * idx + 1),
Query(X, mid + 1, end, qstart, qend, 2 * idx + 2));
}
};
int main()
{
int n, q;
vector<int> A;
vector<int> L;
vector<int> R;
vector<int> X;
cin >> n;
A.resize(n, 0);
rep(i, 0, n) cin >> A[i];
cin >> q;
L.resize(q);
R.resize(q);
X.resize(q);
rep(i, 0, q) cin >> L[i] >> R[i] >> X[i];
//---------------------code--------------------//
_segTree segTree(n);
segTree.construct(A, 0, n - 1, 0);
rep(i, 0, q)
{
cout << segTree.Query(X[i], 0, n - 1, L[i], R[i], 0) << " ";
}
return 0;
}
Time complexity : O((2n - 1)*k + qklogn)
Space complexity : O((2n - 1)*2k)
k -> number of bits
I created the following for multiplying two big integers stored with base 1,000,000,000 as a vector<int32_t>:
#include <iostream>
#include <vector>
#include <cmath>
#include <limits>
#include <algorithm>
template<typename T>
constexpr T power_of_10(T n)
{
return n < 0 ? 0 : n == 0 ? 1 : (n == 1 ? 10 : 10 * power_of_10(n - 1));
}
template<typename T>
constexpr T base_value = power_of_10<T>(std::numeric_limits<T>::digits10);
template<typename T>
constexpr T max_value = base_value<T> - 1;
class BigInt {
private:
static constexpr const std::uint32_t base = base_value<std::uint32_t>;
static constexpr const std::uint32_t max_digits = std::numeric_limits<std::uint32_t>::digits10;
std::vector<std::uint64_t> digits;
public:
BigInt(const char* value) : BigInt(std::string(value))
{
}
BigInt(const std::string& value)
{
constexpr const int stride = std::numeric_limits<std::uint32_t>::digits10;
const std::size_t size = value.size() / stride;
for (std::size_t i = 0; i < size; ++i)
{
auto it = value.begin();
auto jt = value.begin();
std::advance(it, i * stride);
std::advance(jt, (i * stride) + stride);
digits.push_back(std::stoull(std::string(it, jt)));
}
if (value.size() % stride)
{
auto remainder = std::string(value.begin() + size * stride, value.end());
digits.push_back(std::stoull(remainder));
}
std::reverse(digits.begin(), digits.end());
}
BigInt& multiply(const BigInt& other)
{
std::vector<std::uint64_t> product = std::vector<std::uint64_t>(digits.size() + other.digits.size(), 0);
for (std::size_t i = 0; i < other.digits.size(); ++i)
{
std::uint64_t carry = 0, total = 0;
for (std::size_t j = 0; j < digits.size(); ++j)
{
total = product.at(i + j) + (other.digits[i] * digits[j]) + carry;
carry = total / base;
total %= base;
product.at(i + j) = total;
}
if (carry)
{
product[i + digits.size()] = carry;
}
}
digits = product;
return *this;
}
std::string to_string() {
std::string result = std::to_string(digits[digits.size() - 1]);
//
// for (std::int64_t i = digits.size() - 2; i >= 0; --i)
// {
// std::string group = std::to_string(digits[i]);
// while (group.size() < max_digits) {
// group = '0' + group;
// }
// result += group;
// }
for (std::int64_t i = digits.size() - 2; i >= 0; --i)
{
std::uint64_t value = digits[i];
std::uint32_t divisor = base;
while(divisor)
{
if (divisor != base)
{
result += (value / divisor) + '0';
}
value %= divisor;
divisor /= 10;
}
}
return result;
}
};
int main(int argc, const char * argv[])
{
BigInt a = "5000000000";
BigInt b = "5000000000";
std::cout<<a.multiply(b).to_string()<<"\n";
std::cout<<"25000000000000000000"<<"\n";
return 0;
}
When I print the result of the multiplication, I am getting 5,000,000,000 * 5,000,000,000 = 250,000,000,000,000,000,000,000,000,000,000,000 which has way too many zeroes!
It should have 18 zeroes, but mine has 34.
I believe my multiplication algorithm is correct and my to_string is incorrect because 500 * 500 prints correctly as 25,000.
Any ideas what is wrong?
The problem comes from this line:
product[digits.size() + 1] = static_cast<T>(carry);
The index digits.size() + 1 is incorrect. It should be digits.size() + j.
I am given a nxn grid with filled with 1 or 0. I want to count the number of subgrids where the corner tiles are all 1s. My solution goes through all pairs of rows and counts the number of matching 1s then it uses the formula numOf1s * (numOf1s-1)/2 and adds to the result. However, when I submit my solution on https://cses.fi/problemset/task/2137, there is no output on inputs with n = 3000 (probably caused by some error). What could the error be?
int main()
{
int n; cin>> n;
vector<bitset<3000>> grid(n);
for(int i=0;i<n;i++){
cin >> grid[i];
}
long result = 0;
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
int count = (grid[i]&grid[j]).count();
result += (count*(count-1))/2;
}
}
cout << result;
}
This solution will cause a time limit exceeded. bitset::count() is O(n) in worst case. The total complexity of your code is O(n^3). In the worst-case the number of operations would be 3000^3 > 10^10 which is too large.
I'm not sure this solution is the best you can come up with, but it is based on the original solution, with a homebrew alternative for the bitset. This allows me to work with 64 bits blocks, and using a fast popcnt(). An hardware version would be even better, as it would be to work with AVX registers, but this should be more portable and it works on cses.fi. Basically instead of generating a long intersection bitset and later count the number of ones, the function count_common() makes a piece of the intersection and immediately uses it just to count the ones.
The stream extractor could be probably improved, saving some more time.
#include <iostream>
#include <array>
#include <cstdint>
#include <climits>
uint64_t popcnt(uint64_t v) {
v = v - ((v >> 1) & (uint64_t)~(uint64_t)0 / 3);
v = (v & (uint64_t)~(uint64_t)0 / 15 * 3) + ((v >> 2) & (uint64_t)~(uint64_t)0 / 15 * 3);
v = (v + (v >> 4)) & (uint64_t)~(uint64_t)0 / 255 * 15;
uint64_t c = (uint64_t)(v * ((uint64_t)~(uint64_t)0 / 255)) >> (sizeof(uint64_t) - 1) * CHAR_BIT;
return c;
}
struct line {
uint64_t cells_[47] = { 0 }; // 3000/64 = 47
uint64_t& operator[](int pos) { return cells_[pos]; }
const uint64_t& operator[](int pos) const { return cells_[pos]; }
};
uint64_t count_common(const line& a, const line& b) {
uint64_t u = 0;
for (int i = 0; i < 47; ++i) {
u += popcnt(a[i] & b[i]);
}
return u;
}
std::istream& operator>>(std::istream& is, line& ln) {
is >> std::ws;
int pos = 0;
uint64_t val = 0;
while (true) {
char ch = is.get();
if (is && ch == '\n') {
break;
}
if (ch == '1') {
val |= 1LL << (63 - pos % 64);
}
if ((pos + 1) % 64 == 0) {
ln[pos / 64] = val;
val = 0;
}
++pos;
}
if (pos % 64 != 0) {
ln[pos / 64] = val;
}
return is;
}
struct grid {
int n_;
std::array<line, 3000> data_;
line& operator[](int r) {
return data_[r];
}
};
std::istream& operator>>(std::istream& is, grid& g) {
is >> g.n_;
for (int r = 0; r < g.n_; ++r) {
is >> g[r];
}
return is;
}
int main()
{
grid g;
std::cin >> g;
uint64_t count = 0;
for (int r1 = 0; r1 < g.n_; ++r1) {
for (int r2 = r1 + 1; r2 < g.n_; ++r2) {
uint64_t n = count_common(g[r1], g[r2]);
count += n * (n - 1) / 2;
}
}
std::cout << count << '\n';
return 0;
}
My Code is:
#include <iostream>
#include <utility>
#include <algorithm>
//#include <iomanip>
#include <cstdio>
//using namespace std;
inline int overlap(std::pair<int,int> classes[],int size)
{
std::sort(classes,classes+size);
int count=0,count1=0,count2=0;
int tempi,tempk=1;
for(unsigned int i=0;i<(size-1);++i)
{
tempi = classes[i].second;
for(register unsigned int j=i+1;j<size;++j)
{
if(!(classes[i].first<classes[j].second && classes[i].second>classes[j].first))
{ if(count1 ==1)
{
count2++;
}
if(classes[i].second == tempi)
{
tempk =j;
count1 = 1;
}
////cout<<"\n"<<"Non-Overlapping Class:\t";
////cout<<classes[i].first<<"\t"<<classes[i].second<<"\t"<<classes[j].first<<"\t"<<classes[j].second<<"\n";
classes[i].second = classes[j].second;
count++;
if(count1==1 && j ==(size-1))
{
j= tempk;
classes[i].second = tempi;
count1= 0;
if(count2 !=0)
{
count = (count + ((count2)-1));
}
count2 =0;
}
}
else
{
if(j ==(size-1))
{
if(count>0)
{
j= tempk;
classes[i].second = tempi;
count1= 0;
if(count2 !=0)
{
count = (count + ((count2)-1));
}
count2 =0;
}
}
}
}
}
count = count + size;
return count;
}
inline int fastRead_int(int &x) {
register int c = getchar_unlocked();
x = 0;
int neg = 0;
for(; ((c<48 || c>57) && c != '-'); c = getchar_unlocked());
if(c=='-') {
neg = 1;
c = getchar_unlocked();
}
for(; c>47 && c<58 ; c = getchar_unlocked()) {
x = (x<<1) + (x<<3) + c - 48;
}
if(neg)
x = -x;
return x;
}
int main()
{
int N;
////cout<<"Please Enter Number Of Classes:";
clock_t begin,end;
float time_interval;
begin = clock();
while(fastRead_int(N))
{
switch(N)
{
case -1 : end = clock();
time_interval = float(end - begin)/CLOCKS_PER_SEC;
printf("Execution Time = %f",time_interval);
return 0;
default :
unsigned int subsets;
unsigned int No = N;
std::pair<int,int> classes[N];
while(No--)
{
////cout<<"Please Enter Class"<<(i+1)<<"Start Time and End Time:";
int S, E;
fastRead_int(S);
fastRead_int(E);
classes[N-(No+1)] = std::make_pair(S,E);
}
subsets = overlap(classes,N);
////cout<<"\n"<<"Total Number Of Non-Overlapping Classes is:";
printf("%08d",subsets);
printf("\n");
break;
}
}
}
and Input and output of my program:
Input:
5
1 3
3 5
5 7
2 4
4 6
3
500000000 1000000000
1 5
1 5
1
999999999 1000000000
-1
Output:
Success time: 0 memory: 3148 signal:0
00000012
00000005
00000001
Execution Time = 0.000036
I tried to calculate by having clocks at start of main and end of main and found out the time.But it said only some 0.000036 secs.But when I tried to post the same code in Online Judge(SPOJ).My program got 'Time Limit Exceeded' Error. Time Limit for the above program in SPOJ is 2.365 secs.Could somebody help me figure out this?
I consider that your question is about the overlap function.
In it, you have
A sort call: O(n×ln(n))
two for loops:
the first is roughly 0..Size
the second (nested in the first) is roughly i..Size
The inside of the second loop is called Size(Size+1) / 2 (reverse sum of the N first integer) times with no breaks.
So your algorithm is O(n²) where n is the size.
I have a decimal string like this (length < 5000):
std::string decimalString = "555";
Is there a standard way to convert this string to binary representation? Like this:
std::string binaryString = "1000101011";
Update.
This post helps me.
As the number is very large, you can use a big integer library (boost, maybe?), or write the necessary functions yourself.
If you decide to implement the functions yourself, one way is to implement the old pencil-and-paper long division method in your code, where you'll need to divide the decimal number repeatedly by 2 and accumulate the remainders in another string. May be a little cumbersome, but division by 2 should not be so hard.
Since 10 is not a power of two (or the other way round), you're out of luck. You will have to implement arithmetics in base-10. You need the following two operations:
Integer division by 2
Checking the remainder after division by 2
Both can be computed by the same algorithm.
Alternatively, you can use one of the various big integer libraries for C++, such as GNU MP or Boost.Multiprecision.
I tried to do it.. I don't think my answer is right but here is the IDEA behind what I was trying to do..
Lets say we have 2 decimals:
100 and 200..
To concatenate these, we can use the formula:
a * CalcPower(b) + b where CalcPower is defined below..
Knowing this, I tried to split the very long decimal string into chunks of 4. I convert each string to binary and store them in a vector..
Finally, I go through each string and apply the formula above to concatenate each binary string into one massive one..
I didn't get it working but here is the code.. maybe someone else see where I went wrong.. BinaryAdd, BinaryMulDec, CalcPower works perfectly fine.. the problem is actually in ToBinary
#include <iostream>
#include <bitset>
#include <limits>
#include <algorithm>
std::string BinaryAdd(std::string First, std::string Second)
{
int Carry = 0;
std::string Result;
while(Second.size() > First.size())
First.insert(0, "0");
while(First.size() > Second.size())
Second.insert(0, "0");
for (int I = First.size() - 1; I >= 0; --I)
{
int FirstBit = First[I] - 0x30;
int SecondBit = Second[I] - 0x30;
Result += static_cast<char>((FirstBit ^ SecondBit ^ Carry) + 0x30);
Carry = (FirstBit & SecondBit) | (SecondBit & Carry) | (FirstBit & Carry);
}
if (Carry)
Result += 0x31;
std::reverse(Result.begin(), Result.end());
return Result;
}
std::string BinaryMulDec(std::string value, int amount)
{
if (amount == 0)
{
for (auto &s : value)
{
s = 0x30;
}
return value;
}
std::string result = value;
for (int I = 0; I < amount - 1; ++I)
result = BinaryAdd(result, value);
return result;
}
std::int64_t CalcPowers(std::int64_t value)
{
std::int64_t t = 1;
while(t < value)
t *= 10;
return t;
}
std::string ToBinary(const std::string &value)
{
std::vector<std::string> sets;
std::vector<int> multipliers;
int Len = 0;
int Rem = value.size() % 4;
for (auto it = value.end(), jt = value.end(); it != value.begin() - 1; --it)
{
if (Len++ == 4)
{
std::string t = std::string(it, jt);
sets.push_back(std::bitset<16>(std::stoull(t)).to_string());
multipliers.push_back(CalcPowers(std::stoull(t)));
jt = it;
Len = 1;
}
}
if (Rem != 0 && Rem != value.size())
{
sets.push_back(std::bitset<16>(std::stoull(std::string(value.begin(), value.begin() + Rem))).to_string());
}
auto formula = [](std::string a, std::string b, int mul) -> std::string
{
return BinaryAdd(BinaryMulDec(a, mul), b);
};
std::reverse(sets.begin(), sets.end());
std::reverse(multipliers.begin(), multipliers.end());
std::string result = sets[0];
for (std::size_t i = 1; i < sets.size(); ++i)
{
result = formula(result, sets[i], multipliers[i]);
}
return result;
}
void ConcatenateDecimals(std::int64_t* arr, int size)
{
auto formula = [](std::int64_t a, std::int64_t b) -> std::int64_t
{
return (a * CalcPowers(b)) + b;
};
std::int64_t val = arr[0];
for (int i = 1; i < size; ++i)
{
val = formula(val, arr[i]);
}
std::cout<<val;
}
int main()
{
std::string decimal = "64497387062899840145";
//6449738706289984014 = 0101100110000010000100110010111001100010100000001000001000001110
/*
std::int64_t arr[] = {644, 9738, 7062, 8998, 4014};
ConcatenateDecimals(arr, 5);*/
std::cout<<ToBinary(decimal);
return 0;
}
I found my old code that solve sport programming task:
ai -> aj
2 <= i,j <= 36; 0 <= a <= 10^1000
time limit: 1sec
Execution time was ~0,039 in worst case. Multiplication, addition and division algorithms is very fast because of using 10^9 as numeration system, but implementation can be optimized very well I think.
source link
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#define sz(x) (int((x).size()))
typedef vector<int> vi;
typedef long long llong;
int DigToNumber(char c) {
if( c <= '9' && c >= '0' )
return c-'0';
return c-'A'+10;
}
char NumberToDig(int n) {
if( n < 10 )
return '0'+n;
return n-10+'A';
}
const int base = 1000*1000*1000;
void mulint(vi& a, int b) { //a*= b
for(int i = 0, carry = 0; i < sz(a) || carry; i++) {
if( i == sz(a) )
a.push_back(0);
llong cur = carry + a[i] * 1LL * b;
a[i] = int(cur%base);
carry = int(cur/base);
}
while( sz(a) > 1 && a.back() == 0 )
a.pop_back();
}
int divint(vi& a, int d) { // carry = a%d; a /= d; return carry;
int carry = 0;
for(int i = sz(a)-1; i >= 0; i--) {
llong cur = a[i] + carry * 1LL * base;
a[i] = int(cur/d);
carry = int(cur%d);
}
while( sz(a) > 1 && a.back() == 0 )
a.pop_back();
return carry;
}
void add(vi& a, vi& b) { // a += b
for(int i = 0, c = 0, l = max(sz(a),sz(b)); i < l || c; i++) {
if( i == sz(a) )
a.push_back(0);
a[i] += ((i<sz(b))?b[i]:0) + c;
c = a[i] >= base;
if( c ) a[i] -= base;
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int from, to; cin >> from >> to;
string s; cin >> s;
vi res(1,0); vi m(1,1); vi tmp;
for(int i = sz(s)-1; i >= 0; i--) {
tmp.assign(m.begin(), m.end());
mulint(tmp,DigToNumber(s[i]));
add(res,tmp); mulint(m,from);
}
vi ans;
while( sz(res) > 1 || res.back() != 0 )
ans.push_back(divint(res,to));
if( sz(ans) == 0 )
ans.push_back(0);
for(int i = sz(ans)-1; i >= 0; i--)
cout << NumberToDig(ans[i]);
cout << "\n";
return 0;
}
How "from -> to" works for string "s":
accumulate Big Number (vector< int >) "res" with s[i]*from^(|s|-i-1), i = |s|-1..0
compute digits by dividing "res" by "to" until res > 0 and save them to another vector
send it to output digit-by-digit (you can use ostringstream instead)
PS I've noted that nickname of thread starter is Denis. And I think this link may be useful too.