I'm developing a class for large number arithmetic, it now knows how to do addition, handle cin and cout.
It, however has very limited and basic subtraction functionality, and does not know how to handle negative. But that can be easily resolved.
My question is this, how to do multiplication.
I will detail how it handle cin and cout here.
For cin, it will save integers to value[500], for example, 50 will be saved to value[498] and value[499]. BUT NOT value[0] and value[1]
For cout, it will scan for the first non-zero value from value[0] to value[499], and then output from that non-zero value to the end. Also, if it finds no non-zero value, it will output 0.
Here's my code:
#include <iostream>
using namespace std;
class largeNumber {
public:
int value[500];
largeNumber()
{
for ( int i = 0 ; i < 500 ; ++ i )
{
value[i] = 0;
}
}
//below are arithmetic operations
largeNumber operator+(const largeNumber &ln) const
{
largeNumber result;
for ( int i = 0 ; i < 500 ; ++ i )
{
result.value[i] = value[i] + ln.value[i];
}
for ( int i = 499 ; i >= 0 ; -- i )
{
if ( result.value[i] >= 10 )
{
result.value[i - 1] += ( result.value[i] / 10 );
result.value[i] %= 10;
}
}
return result;
}
largeNumber operator-(const largeNumber &ln) const
{
largeNumber result;
for ( int i = 0 ; i < 500 ; ++ i )
{
result.value[i] = value[i] - ln.value[i];
}
for ( int i = 499 ; i >= 0 ; -- i )
{
if ( result.value[i] < 0 )
{
--result.value[i - 1];
result.value[i] += 10;
}
}
return result;
}
largeNumber operator*(const largeNumber &ln) const
{
largeNumber result;
for ( int x = 499 ; x >= 0 ; -- x )
{
for ( int y = 499 ; y >= 0 ; -- y )
{
int dx = 499 - x;
int dy = 499 - y;
int dr = dx + dy;
int r = 499 - dr;
if ( r >= 0 && r <= 499 )
{
result.value[r] = value[x] * ln.value[y];
}
}
}
for ( int i = 499 ; i >= 0 ; -- i )
{
if ( result.value[i] >= 10 )
{
result.value[i - 1] += ( result.value[i] / 10 );
result.value[i] %= 10;
}
}
return result;
}
//below are cin, cout operators
friend ostream& operator<<(ostream& out, const largeNumber& ln)
{
bool valueFound = false;
for ( int i = 0 ; i < 500 ; ++ i )
{
if ( ln.value[i] != 0 )
{
valueFound = true;
}
if ( valueFound == true )
{
out << ln.value[i];
}
}
if ( valueFound == false )
{
out << "0";
}
return out;
}
friend istream& operator>>(istream& in, largeNumber& ln) // input
{
string str;
in >> str;
int length = str.length();
for ( int i = 500 - length ; i < 500 ; ++ i )
{
ln.value[i] = (str[length-(500-i)] - 48);
}
return in;
}
};
int main()
{
largeNumber a, b;
string op;
cin >> a >> op >> b;
cout << a * b;
return 0;
}
I've included my way to do multiplication, however it is flawed.
By the way, the number given by teacher promised that the result of multiplication will be a number less than 500 digit.
Lets start with simple multiplication(Long multiplication):
112 * 301
1 1 2
3 0 1
______________
1 1 2
0 0 0
3 3 6
_______________________
3 3 7 1 2
So, this needs N by N matrix as rows to be added with shifting-n-times.
Where are you doing this addition and where is shifting?
For your question, it would need 500 x 500 multiplications and 500 x 500 additions. O(N*N)
Pro: each digit-multiplication can be done in a single byte so you can change the structure of digits that your compiler can vectorize the code and multiply 16 to 32 digits at once(unrolls quite good).
Con: too many computing(nearly 25-40 iteration per 500 digits-num)
Note: GPU-powered calculus could give it roughly 40x more speed. Such as OpenCL or Cuda.
Related
I was solving a CodeChef problem which asked to calculate the factorial of input. The range of input is 100. Here's the problem's link.
https://www.codechef.com/problems/FCTRL2
So, there is one method to solve the factorial of 100 by using arrays because I used the 'Insertion sort' method but there's a time limit exceeded error. So
I came up with another method by using unsigned long long int datatype. I defined int unsigned long long int but it's not working. I'll be if you help fix it.
#include <bits/stdc++.h>
using namespace std;
#define int unsigned long long;
int main() {
int t,n;
cin>>t;
if(1<=t<=100){
while (t--) {
cin>>n;
if(1<=n<=100){
int fact=1;
for(int i=1;i<=n;i++){
fact*=i;
}
cout<<fact<<endl;
}
}
}
return 0;
}
Factorial of 100 is way too large for 64 bits, it will overflow regardless. The point is that you should implement your own big-number class, or use an existing implementation like the one in Boost.
Factorial of 100 has 158 digits!
100! is way too big for a 64 bit integer. It has 158 digits. You have to implement the BigInteger library. Hopefully, #LightOj Judge creator #Jane Alom Jan has a nice implementation that you can check. I am sharing his implementation, you can modify and test this for this problem.
#include <cstdio>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
struct Bigint {
// representations and structures
string a; // to store the digits
int sign; // sign = -1 for negative numbers, sign = 1 otherwise
// constructors
Bigint() {} // default constructor
Bigint( string b ) { (*this) = b; } // constructor for string
// some helpful methods
int size() { // returns number of digits
return a.size();
}
Bigint inverseSign() { // changes the sign
sign *= -1;
return (*this);
}
Bigint normalize( int newSign ) { // removes leading 0, fixes sign
for( int i = a.size() - 1; i > 0 && a[i] == '0'; i-- )
a.erase(a.begin() + i);
sign = ( a.size() == 1 && a[0] == '0' ) ? 1 : newSign;
return (*this);
}
// assignment operator
void operator = ( string b ) { // assigns a string to Bigint
a = b[0] == '-' ? b.substr(1) : b;
reverse( a.begin(), a.end() );
this->normalize( b[0] == '-' ? -1 : 1 );
}
// conditional operators
bool operator < ( const Bigint &b ) const { // less than operator
if( sign != b.sign ) return sign < b.sign;
if( a.size() != b.a.size() )
return sign == 1 ? a.size() < b.a.size() : a.size() > b.a.size();
for( int i = a.size() - 1; i >= 0; i-- ) if( a[i] != b.a[i] )
return sign == 1 ? a[i] < b.a[i] : a[i] > b.a[i];
return false;
}
bool operator == ( const Bigint &b ) const { // operator for equality
return a == b.a && sign == b.sign;
}
// mathematical operators
Bigint operator + ( Bigint b ) { // addition operator overloading
if( sign != b.sign ) return (*this) - b.inverseSign();
Bigint c;
for(int i = 0, carry = 0; i<a.size() || i<b.size() || carry; i++ ) {
carry+=(i<a.size() ? a[i]-48 : 0)+(i<b.a.size() ? b.a[i]-48 : 0);
c.a += (carry % 10 + 48);
carry /= 10;
}
return c.normalize(sign);
}
Bigint operator - ( Bigint b ) { // subtraction operator overloading
if( sign != b.sign ) return (*this) + b.inverseSign();
int s = sign; sign = b.sign = 1;
if( (*this) < b ) return ((b - (*this)).inverseSign()).normalize(-s);
Bigint c;
for( int i = 0, borrow = 0; i < a.size(); i++ ) {
borrow = a[i] - borrow - (i < b.size() ? b.a[i] : 48);
c.a += borrow >= 0 ? borrow + 48 : borrow + 58;
borrow = borrow >= 0 ? 0 : 1;
}
return c.normalize(s);
}
Bigint operator * ( Bigint b ) { // multiplication operator overloading
Bigint c("0");
for( int i = 0, k = a[i] - 48; i < a.size(); i++, k = a[i] - 48 ) {
while(k--) c = c + b; // ith digit is k, so, we add k times
b.a.insert(b.a.begin(), '0'); // multiplied by 10
}
return c.normalize(sign * b.sign);
}
Bigint operator / ( Bigint b ) { // division operator overloading
if( b.size() == 1 && b.a[0] == '0' ) b.a[0] /= ( b.a[0] - 48 );
Bigint c("0"), d;
for( int j = 0; j < a.size(); j++ ) d.a += "0";
int dSign = sign * b.sign; b.sign = 1;
for( int i = a.size() - 1; i >= 0; i-- ) {
c.a.insert( c.a.begin(), '0');
c = c + a.substr( i, 1 );
while( !( c < b ) ) c = c - b, d.a[i]++;
}
return d.normalize(dSign);
}
Bigint operator % ( Bigint b ) { // modulo operator overloading
if( b.size() == 1 && b.a[0] == '0' ) b.a[0] /= ( b.a[0] - 48 );
Bigint c("0");
b.sign = 1;
for( int i = a.size() - 1; i >= 0; i-- ) {
c.a.insert( c.a.begin(), '0');
c = c + a.substr( i, 1 );
while( !( c < b ) ) c = c - b;
}
return c.normalize(sign);
}
// output method
void print() {
if( sign == -1 ) putchar('-');
for( int i = a.size() - 1; i >= 0; i-- ) putchar(a[i]);
}
};
int main() {
Bigint a, b, c; // declared some Bigint variables
/////////////////////////
// taking Bigint input //
/////////////////////////
string input; // string to take input
cin >> input; // take the Big integer as string
a = input; // assign the string to Bigint a
cin >> input; // take the Big integer as string
b = input; // assign the string to Bigint b
//////////////////////////////////
// Using mathematical operators //
//////////////////////////////////
c = a + b; // adding a and b
c.print(); // printing the Bigint
puts(""); // newline
c = a - b; // subtracting b from a
c.print(); // printing the Bigint
puts(""); // newline
c = a * b; // multiplying a and b
c.print(); // printing the Bigint
puts(""); // newline
c = a / b; // dividing a by b
c.print(); // printing the Bigint
puts(""); // newline
c = a % b; // a modulo b
c.print(); // printing the Bigint
puts(""); // newline
/////////////////////////////////
// Using conditional operators //
/////////////////////////////////
if( a == b ) puts("equal"); // checking equality
else puts("not equal");
if( a < b ) puts("a is smaller than b"); // checking less than operator
return 0;
}
As the problem has a source limit of 2000 bytes so adding the hole BigInteger library will cross the source limit.
So only string multiplication can be done here.
A clean approach of multiplication is given below using C++
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
cin >> t;
while(t--){
vector<int> arr;
int n;
cin >> n;
arr.push_back(1);
int carry = 0;
for(int i = 2; i <= n; i++){
vector<int> t;
for(int j = arr.size() - 1; j >= 0; j--){
int r = arr[j] * i + carry;
carry = r / 10;
t.push_back(r % 10);
}
while(carry){
t.push_back(carry % 10);
carry /= 10;
}
reverse(t.begin(), t.end());
arr = t;
}
for(auto el : arr){
cout << el;
}
cout << endl;
}
return 0;
}
Input
2
10
100
Output
3628800
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Also adding an easy python implementation
test = int(input())
for i in range(0, test):
n = int(input())
res = 1
for j in range(2, n + 1):
res = res * j
print(res)
Already 3 days old question, but anyway.
The solution is a rather simple task. We can do it like we would do it on a piece of paper. We use a std::vector of digits to hold the number. Because the result will be already too big for an unsigned long long for 22!.
The answer will be exact. Also the code is short and compact.
With such an approach the calculation is simple. I do not even know what to explain further.
Please be careful with the runtime. It will be extremely long for big numbers. If speed is an issue, then use the original BigInt header only lib.
Please see the code:
#include <iostream>
#include <vector>
int main()
{
std::cout << "Calculate n! Enter n (max 10000): ";
if (unsigned int input{}; (std::cin >> input) && (input <= 10000)) {
// Here we store the resulting number as single digits
std::vector<unsigned int> result(3000, 0); // Magic number. Is big enough for 100000!
result.back() = 1; // Start calculation with 1 (from right to left)
// Multiply up to the given input value
for (unsigned int count = 2; count <= input; count++)
{
unsigned int sum{}, remainder{};
unsigned int i = result.size() - 1; // Calculate from right to left
while (i > 0)
{
// Simple multiplication like on a piece of paper
sum = result[i] * count + remainder;
result[i--] = sum % 10;
remainder = sum / 10;
}
}
// Show output. Supporess leading zeroes
bool showZeros{ false };
for (const unsigned int i : result) {
if ((i != 0) || showZeros) {
std::cout << i;
showZeros = true;
}
}
}
else std::cerr << "\nError: Wrong input.";
}
Developed and tested with Microsoft Visual Studio Community 2019, Version 16.8.2.
Additionally compiled and tested with clang11.0 and gcc10.2
Language: C++17
I have a matrix like this:
1 0 0 2
0 1 2 0
0 5 3 0
1 0 0 2
I store them in a
vector<int>v
From
v[0][0] - v[n][n] + v[0][n] - v[n][0]
Here is how i try to read the matrix
ostream& operator<<(ostream& s, const Xmatrix& a)
{
unsigned int matrixSize;
s >> matrixSize;
a.reSize(matrixSize);
int x = 0;
for(unsigned int i = 0; i < matrixSize; ++i) {
s >> a(i,i);
}
for(unsigned int i = matrixSize - 1; i > matrixSize + 1; --i) {
if(x == matrixSize / 2){
x = x + 2;
s >> a(x,i);
}
else{
s >> a(x,i);
x++;
}
}
return s;
}
And here is how i try to do the multiplication
Xmatrix operator*(const Xmatrix& a ,const Xmatrix& b)
{
if(a._v.size() != b._v.size()){
throw Xmatrix::DIFFERENT;
}
Xmatrix c(a._v.size());
int x = a._v.size();
int m = x/2;
for(unsigned int i = 0; i < c._v.size(); ++i){
//c._v[i] = a._v[i] * b._v[i];
c._v[i] = a._v[i] * b._v[i] + a._v[i] * b._v[x+i] + a._v[m] * b._v[x+i] + a._v[m] * b._v[i];
x--;
m++;
}
return c;
}
For some reason it doesn't work,it gives really stupid numbers
Did i store the elements and did the calc right?
I did this with classes
I had a problem from a website. Given a string s and st, I have to found all possible combination of st in s. For example,
s = "doomdogged"
st = "dg"
answer = 4
I can choose the d from 0 or 4, and g from 6 or 7. Which gives me 4 possible combinations.
Here's my code:
#include <iostream>
#include <vector>
using namespace std;
string s, st;
bool target[26];
vector<int> positions[26];
vector<vector<int>> possibleCombinations;
void DFS_Enumeration(int, vector<int>*);
int DFS_index_max = 0;
int main(int argc, char *argv[])
{
int answer = 0;
cin >> s; //Given a string s
cin >> st; //Given a string st
//Find all possible combination of st in s
for ( int i = 0 ; i < 26 ; ++ i )
target[i] = 0;
for ( int i = 0 ; i < st.length() ; ++ i )
target[st[i] - 97] = 1;
for ( int i = 0 ; i < 26 ; ++ i )
{
if ( target[i] == 0 ) continue;
for ( int j = 0 ; j < s.length() ; ++ j )
{
if ( s[j] == i + 97 ) positions[i].push_back(j);
}
}
DFS_index_max = st.length();
vector<int> trail(0);
DFS_Enumeration(0, &trail); //Here I got an runtime error
for ( vector<int> vi : possibleCombinations )
{
int currentMax = 0;
for ( int i = 0 ; i < vi.size() ; ++ i )
{
if ( vi[i] > currentMax )
{
if ( i == vi.size() - 1 ) ++ answer;
currentMax = vi[i];
continue;
}
else
break;
}
}
cout << answer;
}
void DFS_Enumeration(int index, vector<int>* trail)
{
if ( index == DFS_index_max )
{
possibleCombinations.push_back(*trail);
return;
}
for ( int i = 0 ; i < positions[st[index] - 97].size() ; ++ i )
{
trail -> push_back(positions[st[index] - 97][i]);
DFS_Enumeration(++index, trail);
trail -> pop_back();
}
return;
}
First I look for characters in st, and mark them as needed to found in my boolean array target.
Then, I use DFS to enumerate all possible combinations. For the above example of "doomdogged" and "dg", d exists in 0, 4, 9. And g exist in 6, 7. I will get 06, 07, 46, 47, 96, 97.
Lastly, I count those which make sense, and output the answer. For some reason, my code doesn't work and generate an runtime error concerning memory at the line I've marked.
DFS_Enumeration might increment index any number of times, so st[index] could likely be past the end of the string st.
I wrote a program to calculate (adding) 2 positive big integer using vector to store the numbers.
#include <cstdlib>
#include <cstdio> // sd sprintf()
#include <iostream>
#include <vector>// sd vector
typedef short TYPE;// alias
void input();
void makeArray();
void display(const std::vector<TYPE> Ar);
TYPE convertChar2T( char * ch);
void add();
static std::string num1;//store big integer as string
static std::string num2;
static std::vector<TYPE> Arr1;//store as vector
static std::vector<TYPE> Arr2;
static std::vector<TYPE> result;
int main(int argc, char** argv) {
input();
makeArray();
display(Arr1);
display(Arr2);
add();
display(result);
return 0;
}
//input 2 big integer number
void input(){
std::cout << "Enter 1st number : " ;
if (! std::getline(std::cin , num1) )
std::cerr << "Not OK\n";
std::cout << "Enter 2nd number : ";
if (! std::getline(std::cin , num2) )
std::cerr << "Not OK\n";
}
//grab into 2 arrays
void makeArray(){
for (std::size_t i = 0; i < num1.size(); i++){
char temp1[2] = { num1[i], '\0'}; //use array-of-char as it need '\0'
Arr1.push_back( convertChar2T(temp1) ); //push what is converted
}
for (std::size_t i = 0; i < num2.size(); i++){
char temp2[2] = { num2[i], '\0'};
Arr2.push_back( convertChar2T(temp2) );
}
}
//convert char -> TYPE by using sscanf()
TYPE convertChar2T( char * ch){
TYPE numb ;
sscanf( ch, "%d", &numb );//NGUOC LAI SPRINTF
return numb;
}
//display array
void display(const std::vector<TYPE> Ar){
for (std::size_t i = 0; i < Ar.size(); i++)
std::cout << Ar.at(i) << '\t';
std::cout << '\n';
}
void add(){
std::size_t i = Arr1.size(); // NEVER COMES TO ZERO ( 1 AT LEAST )
std::size_t j = Arr2.size();
//check original one and later one
//3 cases : 1 - original one , not yet processed
// 2 - original # one, not yet processed
// -1 - original # one or one, processed
//NOTE: at first only value 1 or 2 ( not process )
short check_one[2] = {
( i == 1 ) ? 1 : 2,
( j == 1 ) ? 1 : 2,
};
bool boost = 0;
bool Arr1_isgood = true;// whether count to 1 or not
bool Arr2_isgood = true;// good -> not yet 1
short temp_result = 0;//temporary result to push into vector
while ( Arr1_isgood || Arr2_isgood ){// while not all comes to 1
// i == j : 2 cases
// 1st: both 1 now - 3 cases
// 1.1 #1+not process original and processed
// 1.2 processed and #1+not processed
// 1.3 both 1 original + not processed
// 2nd: both # 1
if ( i == j ) {
if ( check_one[0] == 2 && check_one[1] == -1 ){//#1+not process original and processed
temp_result = Arr1[i-1] + boost;
check_one[0] == -1;
}
else if ( check_one[0] == -1 && check_one[1] == 2 ){//processed and #1+not processed
temp_result = Arr2[j-1] + boost;
check_one[1] = -1;
}
else//both 1 original + not processed OR both # 1
temp_result = Arr1[i-1] + Arr2[j-1] + boost;
//check result >= 10 or < 10
if ( temp_result >= 10 ){
temp_result = temp_result - 10 ;
boost = 1;
}
else
boost = 0;
//result.begin() return iterator at beginning
result.insert( result.begin() ,temp_result );
//update info
if ( i == j && i == 1){ // NOTE : NEU SD i==j==1 -> sai (vi luon true)
Arr1_isgood = Arr2_isgood = false;
continue;
}
else if ( i == j && i != 1){ // i == j # 1
i--;
j--;
}
}
if (i != j){
//check to set flag ( if one of two die )
if ( i == 1 && j > 1 )
Arr1_isgood = false;
else if ( i > 1 && j == 1 )
Arr2_isgood = false;
// i die && j live OR vice versa
if ( (!Arr1_isgood && Arr2_isgood) ||
(Arr1_isgood && !Arr2_isgood ) ){
if (!Arr1_isgood && Arr2_isgood ){ //1st case
if ( check_one[0] == 1 || check_one[0] == 2){//not yet processed as SET FLAG ABOVE first
temp_result = Arr1[i-1] + Arr2[j-1] + boost;
check_one[0] = -1 ;
}
else
temp_result = Arr2[j-1] + boost;
j--;
}
else if ( Arr1_isgood && !Arr2_isgood ){ //2nd case
if ( check_one[1] == 1 || check_one[1] == 2 ){//not yet processed as SET FLAG ABOVE first
temp_result = Arr1[i-1] + Arr2[j-1] + boost;
check_one[1] = -1 ;
}
else
temp_result = Arr1[i-1] + boost;
i--;
}
}
else {// both is good
temp_result = Arr1[i-1] + Arr2[j-1] + boost;
i--;
j--;
}
//check result >= 10 or < 10
if (temp_result >= 10) {
temp_result -= 10;
boost = 1;
} else
boost = 0;
result.insert( result.begin() ,temp_result );
}
}
//insert boost (if any exists)
if (boost == 1)
result.insert( result.begin(), boost);
}
I'm torn between the use of "Arr1_isgood" bool variable and the check_one variable, it seems that they can be combined into one variable ? I tried to do it and it takes a lot of time without correct result.
Can the digit be store in some kind of smaller data structure rather than "short" type ? as "short" takes more than needed bits.
Another thing is : it seems that std::size_t only reach up to 4 billion in size, as when size_t reach 1, I decreased it several times and it comes to 4 billion ? Isn't it?
I wonder if these codes somehow can be optimized more?
If you want to manipulate big integers, you should use a big-integer library, e.g. GMP.
In your machine has 32-bit ints, suppose you represent each number (unsigned) as an array of 31-bit signed ints, starting from the least significant.
Then maybe you could do something like this:
// do c = a + b
int a[n], b[n], c[n];
int carry = 0;
for (i = 0; i < n; i++){
// do the addition with carry
c[i] = a[i] + b[i] + carry;
// if the addition carried into the sign bit
carry = (c[i] < 0);
// detect it and remove it from the sum
if (carry){
c[i] &= 0x7fffffff;
}
}
Then you could figure out how to handle negatives.
I got a bit stuck with my algorithm and I need some help to solve my problem. I think an example would explain better my problem.
Assuming:
d = 4 (maximum number of allowed bits in a number, 2^4-1=15).
m_max = 1 (maximum number of allowed bits mismatches).
kappa = (maximum number of elements to find for a given d and m, where m in m_max)
The main idea is for a given number, x, to compute its complement number (in binary base) and all the possible combinations for up to m_max mismatches from x complement's number.
Now the program start to scan from i = 0 till 15.
for i = 0 and m = 0, kappa = \binom{d}{0} = 1 (this called a perfect match)
possible combinations in bits, is only 1111 (for 0: 0000).
for i = 0 and m = 1, kappa = \binom{d}{1} = 4 (one mismatch)
possible combinations in bits are: 1000, 0100, 0010 and 0001
My problem was to generalize it to general d and m. I wrote the following code:
#include <stdlib.h>
#include <iomanip>
#include <boost/math/special_functions/binomial.hpp>
#include <iostream>
#include <stdint.h>
#include <vector>
namespace vec {
typedef std::vector<unsigned int> uint_1d_vec_t;
}
int main( int argc, char* argv[] ) {
int counter, d, m;
unsigned num_combination, bits_mask, bit_mask, max_num_mismatch;
uint_1d_vec_t kappa;
d = 4;
m = 2;
bits_mask = 2^num_bits - 1;
for ( unsigned i = 0 ; i < num_elemets ; i++ ) {
counter = 0;
for ( unsigned m = 0 ; m < max_num_mismatch ; m++ ) {
// maximum number of allowed combinations
num_combination = boost::math::binomial_coefficient<double>( static_cast<unsigned>( d ), static_cast<unsigned>(m) );
kappa.push_back( num_combination );
for ( unsigned j = 0 ; j < kappa.at(m) ; j++ ) {
if ( m == 0 )
v[i][counter++] = i^bits_mask; // M_0
else {
bit_mask = 1 << ( num_bits - j );
v[i][counter++] = v[i][0] ^ bits_mask
}
}
}
}
return 0;
}
I got stuck in the line v[i][counter++] = v[i][0] ^ bits_mask since I was unable to generalize my algorithm to m_max>1, since I needed for m_max mismatches m_max loops and in my original problem, m is unknown until runtime.
i wrote a code that do what i want, but since i am newbie, it is a bit ugly.
i fixed m and d although this code would work fine for genral m and d.
the main idea is simple, assuming we would like to compute the complement of 0 up to two failure (d= 4,m=2), we will see that max number of possibilities is given by \sum_{i = 0)^2\binom{4}{i} = 11.
The complement to 0 (at 4 bits) is 15
With 1 bit possible mismatch (from 15): 7 11 13 14
with 2 bits possible mismatches (from 15): 3 5 6 9 10 12
i wanted that the output of this program will be a vector with the numbers 15 7 11 13 14 3 5 6 9 10 12 inside it.
i hope that this time i am more clear with presenting my question (although i also supplied the solution). I would appreachiate if someone could point out, in my code, ways to improve it and make it faster.
regards
#include <boost/math/special_functions/binomial.hpp>
#include <iostream>
#include <vector>
#define USE_VECTOR
namespace vec {
#if defined(USE_VECTOR) || !defined(USE_DEQUE)
typedef std::vector<unsigned int> uint_1d_vec_t;
typedef std::vector<uint_1d_vec_t> uint_2d_vec_t;
#else
typedef std::deque<unsigned int> uint_1d_vec_t;
typedef std::deque<uint_1d_vec_t> uint_2d_vec_t;
#endif
}
using namespace std;
void get_pointers_vec( vec::uint_2d_vec_t &v , unsigned num_elemets , unsigned max_num_unmatch , unsigned num_bits );
double get_kappa( int m , int d );
int main( ) {
unsigned int num_elements , m , num_bits;
num_elements = 16;
num_bits = 4; // 2^4 = 16
m = 2;
double kappa = 0;
for ( unsigned int i = 0 ; i <= m ; i++ )
kappa += get_kappa( num_bits , i );
vec::uint_2d_vec_t Pointer( num_elements , vec::uint_1d_vec_t (kappa ,0 ) );
get_pointers_vec( Pointer , num_elements , m , num_bits );
for ( unsigned int i = 0 ; i < num_elements ; i++ ) {
std::cout << setw(2) << i << ":";
for ( unsigned int j = 0 ; j < kappa ; j++ )
std::cout << setw(3) << Pointer[i][j];
std::cout << std::endl;
}
return EXIT_SUCCESS;
}
double get_kappa( int n , int k ) {
double kappa = boost::math::binomial_coefficient<double>( static_cast<unsigned>( n ), static_cast<unsigned>(k) );
return kappa;
}
void get_pointers_vec( vec::uint_2d_vec_t &v , unsigned num_elemets , unsigned max_num_unmatch , unsigned num_bits ) {
int counter;
unsigned num_combination, ref_index, bits_mask, bit_mask;
vec::uint_1d_vec_t kappa;
bits_mask = pow( 2 , num_bits ) - 1;
for ( unsigned i = 0 ; i < num_elemets ; i++ ) {
counter = 0;
kappa.clear();
ref_index = 0;
for ( unsigned m = 0 ; m <= max_num_unmatch ; m++ ) {
num_combination = get_kappa( num_bits , m ); // maximum number of allowed combinations
kappa.push_back( num_combination );
if ( m == 0 ) {
v[i][counter++] = i^bits_mask; // M_0
}
else if ( num_bits == kappa.at(m) ) {
for ( unsigned k = m ; k <= num_bits ; k++ ) {
bit_mask = 1 << ( num_bits - k );
v[i][counter++] = v[i][ref_index] ^ bit_mask;
}
}
else {
// Find first element's index
ref_index += kappa.at( m - 2 );
for( unsigned j = 0 ; j < ( kappa.at(m - 1) - 1 ) ; j++ ) {
for ( unsigned k = m + j ; k <= num_bits ; k++ ) {
bit_mask = 1 << ( num_bits - k );
v[i][counter++] = v[i][ref_index] ^ bit_mask;
}
ref_index++;
}
}
}
}
}