Here I've got a bigint calculator that uses a safearray class(not shown) to store large numbers and do arithmetic operations on them. I've got add and subtract working but when I try multiplication it compiles and runs but nothing happens. Could someone help me fix this? Thanks
int size = 100;
class bigint
{
SafeArray<int> *arr;
public:
char sign;
bigint() //initializes to zero
{
arr = new SafeArray<int>;
for(int i =0;i < size; i++)
arr->set(i,0);
}
void print() //prints numbers without zeroes in front
{
bool start_num=false;
for(int i = 0;i <arr->get_size() ;i++)
{
if(arr->get(i)!=0 && start_num==false )
{start_num=true;
cout << arr->get(i);}
else if(start_num==true)
cout<<arr->get(i);
}
cout<<endl;
}
void assign(const bigint &A) //
{
for(int i=0;i<arr->get_size();i++)
{ //Ways to initialize stuff
arr->set(i,A.arr->get(i));
}
}
void assign(int num) //
{
for(int i = arr->get_size()- 1; i >= 0; i--)
{
arr->set(i,num%10);
num /=10;
}
}
void assign(string num) //
{
long len = num.length();
int j=arr->get_size()-1;
for(long i=len-1;i>=0;i--)
{
arr->set(j,num[i]-48);
j--;
}
}
void add_pos(const bigint &A) //add big ints
{
int carry=0;
for(int i=size-1;i>=0;i--)
{
int result = arr->get(i)+A.arr->get(i)+carry;
arr->set(i,result%10);
carry=result/10;
}
}
void multiply(bigint &A)
{
bigint temp;
for(int i=0;i<size;i +=1)
{
temp.arr->set(i,arr->get(i));
arr->set(i,0);
}
int i1, i2;
for(i2=0; i2<size; i2++)
{
int borrow =0;
for(i1=0;i1+i2<size;i1++)
{
int total=temp.arr->get(i1)*A.arr->get(i2);
int totalsum=total+arr->get(i1+i2)+borrow;
arr->set(i1+i2,totalsum%10);
borrow = totalsum/10;
}
}
};
int main()
{
bigint a, b, c;
a.assign("2543281");
b.assign("3434");
a.mulitply(b);
a.print();
return 0;
}
The result of multiplication of two bigint numbers of size = 100 certainly needs more than 100 digits, perhaps 200?
For minimal modification, you may pass size as constructor argument to bigint. Ideally, bigint may use a vector so that the digit array can grow dynamically in a convenient and flexible way.
class bigint {
std::vector<int8_t> digits_; // each digit must be in 0-9 range
...
These were lil complicated so I came up with this:
InfInt InfInt::operator*(const InfInt& a) const{
InfInt final = 0;
std::string result;
InfInt* temp;
int carry;
int current;
//fast mult algorithm. the same we were taught in elementary.
for(long i=length() - 1;i >= 0; i--){
carry = 0;
result = "";
for (long j=a.length() - 1; j >= 0; j--){
current = (value[i] - '0') * (a.value[j] - '0') + carry;
result = (char)(current % 10 + '0') + result;
carry = current / 10;
}
if (carry > 0)
result = (char)(carry + '0') + result;
temp = new InfInt(result);
final += *new InfInt(temp->alignLeft(length() - i - 1));
}
final.setSign(sign ^ a.sign);
return final;
}
Hope it helps
Related
So, what I basically need is to calculate value of an exponential function (2^n)*(2^(n-1)-1) using c++, where n is a unsigned int type user input. Since n can be assigned any value in unsigned int range, I cannot simply calculate function value and assign it to some unsigned int variable (because resulting number will clearly be out of said range). Therefore, it seems reasonable to me to somehow get my desired function value number by number and write each number as a array element. The only struggle is to realise this method.
Any ideas (both using proposed method or any other one) would be much appreciated.
edit:
Right now I have the following code:
outdated
As expected, it will only work with small values of n
Edit 2: as one of the commentators suggested, I've done some binary numbers by hand. It was pretty fruitful, but I still need sime assistance. Now i have the following code, which will correctly output binary value of said function:
outdated
The only thing left is to convert this value to decimal and hexadecimal. I am not experienced at working with string class, so advice would be appreciated.
Edit 3: Thanks everyone for help. I've completed my program and converted it co C (not willingly, because my professor told me to do so). For anyone interested, the current version of code looks like that:
#include <stdio.h>
#include <stdlib.h>
void binary(unsigned int);
void hex(unsigned int);
void decimal(unsigned int);
int *calculatepower(unsigned int, unsigned int);
void addition(int*, int*, int);
int main(int argc, char** argv){
if (argc != 2){
printf("wrong number of arguments \n");
return -2;
}
unsigned int n = atoi(argv[1]);
printf("exponent - %d \n", n);
binary(n);
hex(n);
decimal(n);
return 0;
}
void binary(unsigned int n){
int i;
printf("binary - ");
for (i=n-1; i>0; i--)
printf("1");
for (i=n; i>0; i--)
printf("0");
printf("\n");
}
void hex(unsigned int nn){
int ones = nn-1;
int zeroes = nn;
int hexzeroes=0, hexfs=0, i;
char switchf, switchzero;
while (zeroes > 3){
hexzeroes+=1;
zeroes-=4;
}
switch (zeroes){
case 0:
break;
case 1:
switchzero='E';
ones-=3;
break;
case 2:
switchzero='C';
ones-=2;
break;
case 3:
switchzero='8';
ones-=1;
break;
default:
break;
}
while (ones>3){
hexfs+=1;
ones-=4;
}
switch (ones){
case 0:
switchf='\0';
break;
case 1:
switchf='1';
break;
case 2:
switchf='3';
break;
case 3:
switchf='7';
break;
default:
break;
}
printf("hexadecimal - %c", switchf);
for (i=0; i<hexfs; i++)
printf("F");
if (zeroes !=0) printf("%c", switchzero);
for (i=0; i<hexzeroes; i++)
printf("0");
printf("\n");
}
void decimal(unsigned int nn){
unsigned int n=nn;
int *str,*powerstr, i, flag=0;
// decimal = 2^n+...+2^((2*n)-1)
unsigned int size = (2*n)/3 + 2;
str = (int*)calloc(size, sizeof(*str));
if(str==NULL)
{
printf("unable to allocate memory");
exit(0);
}
for (i=0; i<size; i++)
{
str[i] = 0;
}
for (n;n<2*nn-1;n++){
powerstr = calculatepower( n, size);
addition(str,powerstr,size);
}
printf("decimal - ");
for (i=0;i<size;i++) {
if ((*(str+i)==0) && (flag==0)){
continue;
}
printf("%d", *(str+i));
flag+=1;
}
}
int *calculatepower(unsigned int n, unsigned int size){
int i, j, buf=0, *powerstr;
powerstr = (int*)calloc(size, sizeof(*powerstr));
for (i=0; i<size; i++)
{
powerstr[i] = 0;
}
powerstr[size-1]=1;
for(j=0;j<n;j++) {
for (i=size-1; i > -1; i--) {
powerstr[i] = powerstr[i] * 2;
if (buf!=0) {
powerstr[i] += 1;
buf=0;
}
if (powerstr[i] > 9) {
buf = 1;
powerstr[i]%=10;
}
}
}
return powerstr;
}
void addition(int *str, int *powerstr, int size){
int i, buf=0;
for (i=size-1; i > -1; i--) {
str[i] = powerstr[i] + str[i];
if (buf!=0) {
str[i] += 1;
buf=0;
}
if (str[i] > 9) {
buf = 1;
str[i]%=10;
}
}
}
Unfortunately, I do not have enough time to polish it. The current biggest problem is not freeing allocated memory and I will fix it later, but I won't update queastion anymore. Thanks again everyone for your answers and comments.
For 16 bit ints it's doable and produces about 40k decimal chars. For 32 bit ints, not so much as it's about 10^20 decimal chars which is beyond anything possible. Even outputting a million chars per second would take longer than the lifetime of the universe.
Here's code for 16 bit ints. Runs in about 3 seconds for n = 65535 not including output time. It has performance improvements by accumulating base 10 sums and normalizing occasionally to prevent overflow.
#include <iostream>
#include <vector>
#include <string>
#include <cstdint>
using std::cout;
using std::vector;
using std::string;
struct BigDecPower2 {
static constexpr uint32_t Normalize_Max{ 26 }; // int8:3, int16:10, int32:26
vector<uint32_t> v;
uint32_t top;
uint32_t normalize_count;
BigDecPower2(uint32_t n) : v(n), top(0), normalize_count(0) {};
void normalize()
{
normalize_count = 0;
for (uint32_t i = 0;; i++)
{
v[i + 1] += v[i] / 10u;
v[i] = v[i] % 10u;
if (i >= top && v[i + 1] == 0)
{
top = i;
return;
}
}
}
void times2() {
for (uint32_t i = 0; i <= top; i++)
v[i] *= 2;
if ((++normalize_count) > Normalize_Max)
normalize();
}
};
void add(BigDecPower2& v1, const BigDecPower2& v2)
{
uint32_t max_top = v1.top > v2.top ? v1.top : v2.top;
for (uint32_t i = 0; i <= max_top; i++)
v1.v[i] += v2.v[i];
if (++v1.normalize_count < v2.normalize_count)
v1.normalize_count = v2.normalize_count;
if (v1.normalize_count > v1.Normalize_Max)
v1.normalize();
}
void print_base(unsigned int n, int number_base)
{
int64_t ones = n-1;
int64_t zeros = n;
if (number_base ==2)
{
while (ones-- > 0)
cout << '1';
while (zeros-- > 0)
cout << '0';
}
else if (number_base == 16) {
int resid = (ones + zeros) % 4;
if (resid == 0)
resid = 4;
cout << "~137F"[resid];
ones -= resid;
while ((ones -= 4) > 0)
cout << 'F';
cout << "8CEF"[ones + 3];
zeros /= 4;
while (zeros--)
cout << '0';
}
else if (number_base == 10)
{
BigDecPower2 v_accum(40000u);
BigDecPower2 v_pwr(40000u); v_pwr.v[0] = 1;
for (uint32_t i = 0; i < n - 1; i++)
{
add(v_accum, v_pwr);
v_pwr.times2();
}
for (uint32_t i = 0; i < n; i++)
v_accum.times2();
v_accum.normalize();
for (uint32_t i = v_accum.top; i != -1; i--)
cout << static_cast<char>(v_accum.v[i] + '0');
}
cout << '\n';
}
int main()
{
// calcs in about 3 seconds, outputs about 40k decimal chars
// print_base(0xffff, 10);
// Demo
for (int i = 1; i < 10; i++)
{
print_base(i, 2);
print_base(i, 16);
print_base(i, 10);
cout << '\n';
}
}
You can use unsigned long or unsigned long long (or uintX_t where X is the maximum supported size on your platform) if unsigned int cannot hold your output. If that's still not enough for your use case, then either implement your own big integer class, or use an existing library (recommended if you can afford it). There are a couple of them out there. For example, GNU Multiple Precision Arithmetic Library (GMP) and bigint-library. See this list for more.
In case you decided to go on your own and implement your own class, this might give you some clues on how to start. (Note that, for efficiency matters, number theory algorithms may be applied. It is not an easy task to come with a good implementation).
template<typename T = unsigned, int Base = 10> class Bigint {
std::vector<T> digits;
bool sign; // For e.g. true for + or 0, false for -
public:
Bigint() : digits(), sign(true) { }
Bigint(int x)
{
// Insert digits of x into digits vector
// Don't forget the sign
}
// Do the same with other types: short, long, unsigned, etc.
Bigint(const char *x)
{
// You need to parse x. Bad formatting is to be handled (tip: use exceptions)
}
// Provide an std::string version
Bigint(const Bigint& bi) : digits(bi.digits), sign(bi.sign) {}
Bigint& operator=(const Bigint& bi)
{
// Copy...
return *this;
}
// You also have to implement operators
Bigint& operator+(const Bigint& bi)
{
// Logic...
return *this;
}
// Other operators: -, /, %, bitwise, etc.
// Tip: you can use a helper class to be used by both / and % since they share a similar logic (for avoiding redundant code).
Bigint power(const Bigint& bi) // Provide other signatures: int, string, etc.
{
// Logic...
}
};
Please help me to solve the query that this code runs infinitely at a particular line.
It does not give any output as at the end of the code I write the code to print the vector. Even after I assign any value to vector "result" manually still it is not giving any output. why is it so?
#include<bits/stdc++.h>
using namespace std;
bool authorize(int strValue, int value, int M)
{
long int newValue = (strValue - (value * 131) % M);
if (newValue >= 48 && newValue <= 57)
return true;
if (newValue > 65 && newValue <= 90)
return true;
if (newValue >= 97 && newValue <= 122)
return true;
return false;
}
int hashingfunct(string str, int M)
{
long int P, F, sum = 0;
int len = str.length();
for (int i = 0; i < len; i++)
{
P = pow(131, len - i - 1);
F = (int)str[i];
sum += (F * P) % M;
}
sum = sum % M;
return sum;
}
int main()
{
int n = 5;
string str1, str2;
vector<vector<string> > events;
for (int i = 0; i < n; i++) {
cin >> str1 >> str2;
vector<string > temp;
temp.push_back(str1);
temp.push_back(str2);
events.push_back(temp);
}
for (int i = 0; i < n; i++) {
cout << events[i][0] << events[i][1];
}
/*
INPUT FORMAT:
setpassword 1
setpassword 2
setpassword 3
authorize 49
authorize 50
*/
vector<int> result;
int j = 0;
long int m = pow(10, 9);
long int M = m + 7;
long int value, strValue;
for (int i = 0; i < events.size(); i++)
{
strValue = stoi(events[i][1]);
if (events[i][0] == "setPassword") {
value = hashingfunct(events[i][1], M);
}
else if (strValue == value)
result[j++] = 1;
else if (authorize(strValue, value, M))
result[j++] = 1;
else
result[j++] = 0;
}
for (int i = 0; i < result.size(); i++) {
cout << result[i];
}
}
Your program has complete Undefined Behaviour.
Let's get started with the first problem. In the following check code
long int value, strValue; // not initialised
for (int i = 0; i < events.size(); i++)
{
// ...
// here it should have been "setpassword" (i.e. all are small letters)
if (events[i][0] == "setPassword")
{
// if the check fails the `value` never get initialised!
value = hashingfunct(events[i][1], M);
}
// If the `value` not been initialised, check happens with any garbage value here!
else if (strValue == value)
// ...other code
}
You are checking whether the string is "setPassword" instead of "setpassword" (i.e. see in the events vector, all the strings are small letters).
If that goes wrong, the value will never get initialized, meaning it holds any garbage value and hence conducting this check else if (strValue == value) can cause any behaviour to your program (aka Undefined Behaviour).
Secondly, the vector<int> result; is empty at the beginning. Therefore accessing elements via std::vector::operator[] later
result[j++] = 1;
// ...
result[j++] = 1;
// ...
result[j++] = 0;
triggers the access out of bounds (UB). There you need just result.emplace_back(/*value*/); or result.push_back(/*value*/);, and no need of redutant variable j.
In short, you need
#include <iostream>
#include <vector>
#include <string>
// ..other functions
int main()
{
std::vector<std::vector<std::string> > events {
{"setpassword", "1"}, // can be also user input, like in your example
{"setpassword", "2"},
{"setpassword", "3"},
{"authorize", "49" },
{"authorize", "50" }
};
std::vector<int> result;
const long int M = pow(10, 9) + 7;
long int value{ 0 }, strValue{ 0 }; // default initialization
for (const std::vector<std::string> row: events) // better use range-based loop
{
strValue = std::stoi(row[1]);
if (row[0] == "setpassword") {
value = hashingfunct(row[1], M);
if (strValue == value)
result.emplace_back(1);
else if (authorize(strValue, value, M))
result.emplace_back(1);
}
else
result.emplace_back(0);
}
}
As a side note,
Please do not use using namespacestd;
Why should I not #include <bits/stdc++.h>?
Corrected code
#include<bits/stdc++.h>
using namespace std;
bool authorize(long int strValue,long int value,int M){
long int value1=value*131;
long int newValue=(strValue-(value1%M))%M;
if(newValue>=48 && newValue<=57)
return true;
if(newValue>=65 && newValue<=90)
return true;
if(newValue>=97 && newValue<=122)
return true;
return false;
}
int hashingfunct(string str,int M){
long int P,F,sum=0;
int len=str.length();
for(int i=0;i<len;i++){
P=pow(131,len-i-1);
F=(int)str[i];
sum+=(F*P)%M;
}
sum=sum%M;
return sum;
}
int main(){
int n=5;
string str1,str2;
vector<vector<string> > events;
for (int i=0;i<n;i++){
cin>>str1>>str2;
vector<string > temp;
temp.push_back(str1);
temp.push_back(str2);
events.push_back(temp);
}
/*
setPassword cAr1
authorize 223691457
authorize 303580761
setPassword d
authorize 100
*/
vector<int> result;
int j=0;
long int m=pow(10,9);
long int M=m+7;
long int value,strValue;
for(int i=0;i<events.size();i++){
if(events[i][0]=="setPassword"){
value=hashingfunct(events[i][1],M);
continue;
}
strValue=stoi(events[i][1]);
if(strValue==value)
result.push_back(1);
else if(authorize(strValue,value,M))
result.push_back(1);
else
result.push_back(0);
}
for(int i=0;i<result.size();i++){
cout<<result[i];
}
}
Here I have a bigint class that uses an array called SafeArray that I created in a different class(we couldnt use vectors) the set and get function calls are from the SafeArray class, get takes an int parameter for array position and set takes 2 int parameters(one for position and one for value) all methods in this class work fine except for my subtract and compare methods. What I really need to work is my subtraction method. Any help? Thanks
int size = 20; //just for testing, will increase later
class bigint
{
SafeArray<int> *arr;
public:
bigint()
{
arr = new SafeArray<int>;
for(int i =0;i < size; i++)
arr->set(i,0);
}
void print()
{
for(int i = 0;i <arr->get_size() ;i++)
{
cout << arr->get(i);
}
cout<<endl;
}
void assign(const bigint &A)
{
for(int i=0;i<arr->get_size();i++)
{
arr->set(i,A.arr->get(i));
}
}
void assign(int num)
{
for(int i = arr->get_size()- 1; i >= 0; i--)
{
arr->set(i,num%10);
num /=10;
}
}
void assign(string num)
{
long len = num.length();
int j=arr->get_size()-1;
for(long i=len-1;i>=0;i--)
{
arr->set(j,num[i]-48);
j--;
}
}
void add(const bigint &A)
{
int carry=0;
for(int i=size-1;i>=0;i--)
{
int result = arr->get(i)+A.arr->get(i)+carry;
arr->set(i,result%10);
carry=result/10;}
}
void subtract(const bigint &A) {
for(int i=0, borrow=0; i<size; ++i)
{ int result=((arr->get(i) - A.arr->get(i) + borrow));
if(borrow == result < 0) {
A.arr->set(i,result+=10);
} } }
void compare(const bigint & A)
{
//int comp;
//for(int i =0;i<size;i++)
if(arr->get(size-1)>A.arr->get(size-1))
cout<<0;
else
cout<<1;
}
};
int main()
{
bigint A,B,C,D;
A.assign(12345);
A.print();
cout<<endl;
C.assign("123456789000");
C.print();
cout<<endl;
B.add(C);
B.print();
//B.compare(A);
//B.subtract(A);
//B.print();
return 0;
}
I think it should look like this
void subtract(const bigint &A) {
int borrow = 0;
for(int i=size-1; i >= 0; --i)
{
int result=((arr->get(i) - A.arr->get(i) - borrow));
if(result < 0) {
arr->set(i, result + 10);
borrow = 1;
} else {
arr->set(i, result);
borrow = 0;
}
}
}
// equals A
bool equals(const bigint &A) {
for(int i=0; i < size; ++i) {
if(A.arr->get(i) != arr->get(i)) {
return false;
}
}
return true;
}
// less than A
bool lt(const bigint &A) {
for(int i=0; i < size; ++i) {
if(arr->get(i) != A.arr->get(i)) {
return arr->get(i) < A.arr->get(i);
}
}
}
I've got a bigint class that uses an array called SafeArray that I created in a different class. I couldn't use vectors. The set and get function calls are from the SafeArray class. Get takes an int parameter for array position and set takes 2 int parameters (one for position and one for value). All methods in this bigint class work fine (we don't have to account for negative integers) except my compare method needs work. I want it to be able to compare two bigints and if the (const bigint and &A) number is larger than the other (cout 1) if it is smaller (cout 2) if they are the same (cout 0). Any help with this method would be greatly appreciated. Thanks
int size = 35; //will get bigger, small now just for testing
class bigint
{
SafeArray<int> *arr;
public:
bigint() //initializes to zero
{
arr = new SafeArray<int>;
for(int i =0;i < size; i++)
arr->set(i,0);
}
void print() //prints numbers without zeroes in front
{
bool start_num=false;
for(int i = 0;i <arr->get_size() ;i++)
{
if(arr->get(i)!=0 && start_num==false )
{start_num=true;
cout << arr->get(i);}
else if(start_num==true)
cout<<arr->get(i);
}
cout<<endl;
}
void assign(const bigint &A) //
{
for(int i=0;i<arr->get_size();i++)
{ //Ways to initialize stuff
arr->set(i,A.arr->get(i));
}
}
void assign(int num) //
{
for(int i = arr->get_size()- 1; i >= 0; i--)
{
arr->set(i,num%10);
num /=10;
}
}
void assign(string num) //
{
long len = num.length();
int j=arr->get_size()-1;
for(long i=len-1;i>=0;i--)
{
arr->set(j,num[i]-48);
j--;
}
}
void add(const bigint &A) //add big ints
{
int carry=0;
for(int i=size-1;i>=0;i--)
{
int result = arr->get(i)+A.arr->get(i)+carry;
arr->set(i,result%10);
carry=result/10;
}
}
void subtract(const bigint &A) //subtract big ints
{
int borrow = 0;
for(int i=size-1; i >= 0; --i)
{
int result=((arr->get(i) - A.arr->get(i) - borrow));
if(result < 0)
{
arr->set(i, result + 10);
borrow = 1;
}
else
{
arr->set(i, result);
borrow = 0;
}
}
}
//int compare(const bigint &A) //compare big ints
// {
//
// for(int i<size;i>0;i--)
// {
// if(A.arr->get(i) > arr->get(i))
// {
// return 1;
// }
// else if(A.arr->get(i) < arr->get(i))
// {
// return -1;
// }
// else
// {
// return 0;
// }
// }
//
// }
};
int main()
{
bigint a, b, c;
a.assign("12345678"); //for testing
b.assign("12345678");
//a.compare(b);
a.print();
c.assign(24691357); // 696969 is small enough to be an int.
a.add(b); // a += b;
a.subtract(c); // a -= b;
a.print();
return 0;
}
The logical problem with comparison is that you're returning two numbers as equal at the first digit that is equal.
You need instead to keep comparing next digit in that case and return 0 only if all of them are equal.
So far I've got an add, subtract and print function as well as a constructor that initializes to zero the array. For some reason the operations(+ and -) made alot of sense to me(i think) so I kind of got ahead of my self and am not too sure how to initialize a big integer, could I get some help with a function such as
void assign(const bigint & A) or something like that? Also if there is something already wrong with my code please tell me. Thanks
const int size=30; //just to make things easier, will change to something big later
class bigint
{
int digits[size];
public:
// initializes to zero
bigint()
{
for (int i = 0; i < size; i++)
digits[i] = 0;
}
// prints a big int
void print()
{
bigint B;
for (int i = size - 1; i >= 0; i--)
{
int dig = B.digits[i];
if (dig != 0)
std::cout << dig;
}
}
// subtracts a bigint(B) from another(A)
void subtract(bigint & A, bigint & B)
{
for (int i = 0, borrow = 0; i < size; i++)
{
if (borrow = ((A.digits[i] -= B.digits[i] + borrow) < 0))
{
A.digits[i] += 10;
}
}
}
// adds a bigint(A) to another(B)
void add(bigint & A, bigint & B)
{
for (int i = 0, carry = 0; i < size; i++)
{
if (carry = ((A.digits[i] += B.digits[i] + carry) < 9))
{
A.digits[i] -= 10;
}
}
}
};