Overloaded division operator for HugeInt [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Division with really big numbers
I need to overload the / operator to work on two HugeInt objects which are defined simply as an array of 30 shorts. This is homework, btw, but I have been wracking my brain for days on this problem.
I have overloaded the * operator already:
HugeInt HugeInt::operator*(const HugeInt &op2){
HugeInt temp;
short placeProducts[hugeIntSize + 1][hugeIntSize] = {0};
short product;
int carry = 0;
int k, leftSize, rightSize, numOfSumRows;
leftSize = getDigitLength();
rightSize = op2.getDigitLength();
if(leftSize <= rightSize) {
numOfSumRows = leftSize;
for(int i = (hugeIntSize - 1), k = 0; k < numOfSumRows; i--, k++) {
for(int j = (hugeIntSize - 1); j >= k; j--) {
product = integer[i] * op2.integer[j] + carry;
if (product > 9) {
carry = product / 10;
product %= 10;
} else {
carry = 0;
}
placeProducts[k][j - k] = product;
}
}
} else {
numOfSumRows = rightSize;
for(int i = (hugeIntSize - 1), k = 0; k < numOfSumRows; i--, k++) {
for(int j = (hugeIntSize - 1); j >= k; j--) {
product = integer[j] * op2.integer[i] + carry;
if (product > 9) {
carry = product / 10;
product %= 10;
} else {
carry = 0;
}
placeProducts[k][j - k] = product;
}
}
}
sumProductsArray(placeProducts, numOfSumRows);
for(int i = 0; i < hugeIntSize; i++)
{
temp.integer[i] = placeProducts[hugeIntSize][i];
}
return temp;}
But how do I overload the / op? My main problem isn't with the C++ code or syntax, but with my algorithm to divide. When I multiply I am able to do it digit by digit. I store each product (aka 1's digit of bottom times every digit above, then 10's digit time every num above using my carry algorithm) in my 2d array. Every time I get new product it is offset to the left by n + 1, which "multiplies" it by the required power of 10. Then I just sum up all the columns.
I can't for the life of me figure out how to code the long division method. Since I'm dealing with two arrays it has to be digit by digit, and I suspect it might be as easy as reversing the multiplication algorithm. Nested loops and subtraction? I would need a variable for the quotient and reminder? Is there a better method? I just need to be pointed in the right direction.

In computational division of integers, there are a few interesting results:
numerator < denominator implies quotient = 0
numerator == denominator implies quotient = 1
numerator > denominator, long division would be needed to determine quotient.
The first two conditions can be satisfied with a for loop. You could overload the less-than and equals relational operator to encapsulate this behavior.
For the long division, you will need your multiplication operator as well as overloaded less-than and subtraction operators, and an append digit member function to perform the operation.
It's brute force, but should get the job done.

Related

How to multiply strings without overflow by c++?

I tried to solve Multiply Strings by c++ by this approach, but I cannot avoid integer overflow by change type from int to long long int or double. Python won't overflow, so my code works like below.
Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string.
Python works:
class Solution:
def multiply(self, num1: str, num2: str) -> str:
n = len(num1) # assume n >= m
m = len(num2)
if n < m:
num1, num2 = num2, num1
n, m = m, n
product = 0
for i in range(1, m + 1):
multiplier = int(num2[m - i]) # current character of num2
sum_ = 0
for j in range(0, n): # multiply num1 by multiplier
multiplicand = int(num1[n - j - 1])
num = multiplicand * (10 ** j) * multiplier
sum_ += num
product += sum_ * (10 ** (i - 1))
return str(product)
C++ failed:
string multiply(string num1, string num2) {
int n = num1.size();
int m = num2.size();
if (n < m) {
std::swap(num1, num2);
std::swap(n, m);
}
long long int product = 0;
for (int i = 1; i <= m; ++i) {
int multiChar = num2[m - i] - '0';
long long int sum = 0;
for (int j = 0; j < n ; ++j) {
int charCand = num1[n - j - 1] - '0';
long long int num = charCand * ((pow(10, j))) * multiChar;
sum += num;
}
product += sum * ((pow(10, i - 1)));
}
return std::to_string(product);
}
As far as I have tested, some cases are OK, but overflow seems unavoidable if the number is too big. Is there any way to fix my code?
Testcase:
"12323247989"
"98549324321"
runtime error: 1.05355e+20 is outside the range of representable values of type 'long long' (solution.cpp)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:28:17
Expected:
"1214447762756072040469"
You are not on the right way. Imagine how you would do that by hand:
abc*def
-------
xxxx
xxxx0
xxxx00
-------
You just add single digits as well, don't you? Only those of same significance – possibly considering some carry.
You might rather reproduce the same in code, too. Producing overflow that way is much less likely (I assume that after multiplying single digits summing up the results in a single integer – recommending an unsigned type for – is acceptable; if not, you'd have to build up a std::string again). The sign you calculate independently, just as you'd do by hand as well.
One difference to multiplication by hand we'll have, though: By hand you would create rather large intermediate numbers by multiplying one number with each digit
of the other number. That would require to store these intermediate numbers as strings again, e. g. in a vector. More efficient, though, is identifying those digit pairs of which the multiplication results in the same significance.
These will be 0|0 -> 0; 0|1, 1|0 -> 1; 0|2, 1|1, 2|0 -> 2, and so on. You produce these pairs by:
for(size_t i = 0, max = std::max(num1.length(), num2.length); i < max; ++i)
{
for(size_t j = 0; j < i; ++j)
{
if(j < num1.length() && i - j < num2.length())
{
// iterate backwards for easy carry handling
size_t idx1 = num1.length() - j;
size_t idx2 = num2.length() - (i - j);
// multiply characters at num1[idx1] and num2[idx2] and add result to sum
}
}
// add carry
// calculate last digit and a p p e n d to a result string
// update carry
}
// append '-' sign, if result is negative
std::reverse(result.begin(), result.end());
Building up the string in reverse order is more efficient, as you do not need to move the subsequent characters all the time. (Untested code, if you find a bug, please fix it yourself).
The loops are in my preferred variant; if you feel better with another, feel free to change; just be aware that with signed types you can produce endless loops if you try e. g. for(unsigned i = n; n >= 0; --i /* overflows to UINT_MAX */).
Side note: You should accept the input strings by reference (std::string const& num1, std::string const& num2), that avoids the needless copies arising by accepting by value.

C++ - Code Optimization

I have a problem:
You are given a sequence, in the form of a string with characters ‘0’, ‘1’, and ‘?’ only. Suppose there are k ‘?’s. Then there are 2^k ways to replace each ‘?’ by a ‘0’ or a ‘1’, giving 2^k different 0-1 sequences (0-1 sequences are sequences with only zeroes and ones).
For each 0-1 sequence, define its number of inversions as the minimum number of adjacent swaps required to sort the sequence in non-decreasing order. In this problem, the sequence is sorted in non-decreasing order precisely when all the zeroes occur before all the ones. For example, the sequence 11010 has 5 inversions. We can sort it by the following moves: 11010 →→ 11001 →→ 10101 →→ 01101 →→ 01011 →→ 00111.
Find the sum of the number of inversions of the 2^k sequences, modulo 1000000007 (10^9+7).
For example:
Input: ??01
-> Output: 5
Input: ?0?
-> Output: 3
Here's my code:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <math.h>
using namespace std;
void ProcessSequences(char *input)
{
int c = 0;
/* Count the number of '?' in input sequence
* 1??0 -> 2
*/
for(int i=0;i<strlen(input);i++)
{
if(*(input+i) == '?')
{
c++;
}
}
/* Get all possible combination of '?'
* 1??0
* -> ??
* -> 00, 01, 10, 11
*/
int seqLength = pow(2,c);
// Initialize 2D array of integer
int **sequencelist, **allSequences;
sequencelist = new int*[seqLength];
allSequences = new int*[seqLength];
for(int i=0; i<seqLength; i++){
sequencelist[i] = new int[c];
allSequences[i] = new int[500000];
}
//end initialize
for(int count = 0; count < seqLength; count++)
{
int n = 0;
for(int offset = c-1; offset >= 0; offset--)
{
sequencelist[count][n] = ((count & (1 << offset)) >> offset);
// cout << sequencelist[count][n];
n++;
}
// cout << std::endl;
}
/* Change '?' in former sequence into all possible bits
* 1??0
* ?? -> 00, 01, 10, 11
* -> 1000, 1010, 1100, 1110
*/
for(int d = 0; d<seqLength; d++)
{
int seqCount = 0;
for(int e = 0; e<strlen(input); e++)
{
if(*(input+e) == '1')
{
allSequences[d][e] = 1;
}
else if(*(input+e) == '0')
{
allSequences[d][e] = 0;
}
else
{
allSequences[d][e] = sequencelist[d][seqCount];
seqCount++;
}
}
}
/*
* Sort each sequences to increasing mode
*
*/
// cout<<endl;
int totalNum[seqLength];
for(int i=0; i<seqLength; i++){
int num = 0;
for(int j=0; j<strlen(input); j++){
if(j==strlen(input)-1){
break;
}
if(allSequences[i][j] > allSequences[i][j+1]){
int temp = allSequences[i][j];
allSequences[i][j] = allSequences[i][j+1];
allSequences[i][j+1] = temp;
num++;
j = -1;
}//endif
}//endfor
totalNum[i] = num;
}//endfor
/*
* Sum of all Num of Inversions
*/
int sum = 0;
for(int i=0;i<seqLength;i++){
sum = sum + totalNum[i];
}
// cout<<"Output: "<<endl;
int out = sum%1000000007;
cout<< out <<endl;
} //end of ProcessSequences method
int main()
{
// Get Input
char seq[500000];
// cout << "Input: "<<endl;
cin >> seq;
char *p = &seq[0];
ProcessSequences(p);
return 0;
}
the results were right for small size input, but for bigger size input I got time CPU time limit > 1 second. I also got exceeded memory size. How to make it faster and optimal memory use? What algorithm should I use and what better data structure should I use?, Thank you.
Dynamic programming is the way to go. Imagine You are adding the last character to all sequences.
If it is 1 then You get XXXXXX1. Number of swaps is obviously the same as it was for every sequence so far.
If it is 0 then You need to know number of ones already in every sequence. Number of swaps would increase by the amount of ones for every sequence.
If it is ? You just add two previous cases together
You need to calculate how many sequences are there. For every length and for every number of ones (number of ones in the sequence can not be greater than length of the sequence, naturally). You start with length 1, which is trivial, and continue with longer. You can get really big numbers, so You should calculate modulo 1000000007 all the time. The program is not in C++, but should be easy to rewrite (array should be initialized to 0, int is 32bit, long in 64bit).
long Mod(long x)
{
return x % 1000000007;
}
long Calc(string s)
{
int len = s.Length;
long[,] nums = new long[len + 1, len + 1];
long sum = 0;
nums[0, 0] = 1;
for (int i = 0; i < len; ++i)
{
if(s[i] == '?')
{
sum = Mod(sum * 2);
}
for (int j = 0; j <= i; ++j)
{
if (s[i] == '0' || s[i] == '?')
{
nums[i + 1, j] = Mod(nums[i + 1, j] + nums[i, j]);
sum = Mod(sum + j * nums[i, j]);
}
if (s[i] == '1' || s[i] == '?')
{
nums[i + 1, j + 1] = nums[i, j];
}
}
}
return sum;
}
Optimalization
The code above is written to be as clear as possible and to show dynamic programming approach. You do not actually need array [len+1, len+1]. You calculate column i+1 from column i and never go back, so two columns are enough - old and new. If You dig more into it, You find out that row j of new column depends only on row j and j-1 of the old column. So You can go with one column if You actualize the values in the right direction (and do not overwrite values You would need).
The code above uses 64bit integers. You really need that only in j * nums[i, j]. The nums array contain numbers less than 1000000007 and 32bit integer is enough. Even 2*1000000007 can fit into 32bit signed int, we can make use of it.
We can optimize the code by nesting loop into conditions instead of conditions in the loop. Maybe it is even more natural approach, the only downside is repeating the code.
The % operator is, as every dividing, quite expensive. j * nums[i, j] is typically far smaller that capacity of 64bit integer, so we do not have to do modulo in every step. Just watch the actual value and apply when needed. The Mod(nums[i + 1, j] + nums[i, j]) can also be optimized, as nums[i + 1, j] + nums[i, j] would always be smaller than 2*1000000007.
And finally the optimized code. I switched to C++, I realized there are differences what int and long means, so rather make it clear:
long CalcOpt(string s)
{
long len = s.length();
vector<long> nums(len + 1);
long long sum = 0;
nums[0] = 1;
const long mod = 1000000007;
for (long i = 0; i < len; ++i)
{
if (s[i] == '1')
{
for (long j = i + 1; j > 0; --j)
{
nums[j] = nums[j - 1];
}
nums[0] = 0;
}
else if (s[i] == '0')
{
for (long j = 1; j <= i; ++j)
{
sum += (long long)j * nums[j];
if (sum > std::numeric_limits<long long>::max() / 2) { sum %= mod; }
}
}
else
{
sum *= 2;
if (sum > std::numeric_limits<long long>::max() / 2) { sum %= mod; }
for (long j = i + 1; j > 0; --j)
{
sum += (long long)j * nums[j];
if (sum > std::numeric_limits<long long>::max() / 2) { sum %= mod; }
long add = nums[j] + nums[j - 1];
if (add >= mod) { add -= mod; }
nums[j] = add;
}
}
}
return (long)(sum % mod);
}
Simplification
Time limit still exceeded? There is probably better way to do it. You can either
get back to the beginning and find out mathematically different way to calculate the result
or simplify actual solution using math
I went the second way. What we are doing in the loop is in fact convolution of two sequences, for example:
0, 0, 0, 1, 4, 6, 4, 1, 0, 0,... and 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,...
0*0 + 0*1 + 0*2 + 1*3 + 4*4 + 6*5 + 4*6 + 1*7 + 0*8...= 80
The first sequence is symmetric and the second is linear. It this case, the sum of convolution can be calculated from sum of the first sequence which is = 16 (numSum) and number from second sequence corresponding to the center of the first sequence, which is 5 (numMult). numSum*numMult = 16*5 = 80. We replace the whole loop with one multiplication if we are able to update those numbers in each step, which fortulately seems the case.
If s[i] == '0' then numSum does not change and numMult does not change.
If s[i] == '1' then numSum does not change, only numMult increments by 1, as we shift the whole sequence by one position.
If s[i] == '?' we add original and shiftet sequence together. numSum is multiplied by 2 and numMult increments by 0.5.
The 0.5 means a bit problem, as it is not the whole number. But we know, that the result would be whole number. Fortunately in modular arithmetics in this case exists inversion of two (=1/2) as a whole number. It is h = (mod+1)/2. As a reminder, inversion of 2 is such a number, that h*2=1 modulo mod. Implementation wisely it is easier to multiply numMult by 2 and divide numSum by 2, but it is just a detail, we would need 0.5 anyway. The code:
long CalcOptSimpl(string s)
{
long len = s.length();
long long sum = 0;
const long mod = 1000000007;
long numSum = (mod + 1) / 2;
long long numMult = 0;
for (long i = 0; i < len; ++i)
{
if (s[i] == '1')
{
numMult += 2;
}
else if (s[i] == '0')
{
sum += numSum * numMult;
if (sum > std::numeric_limits<long long>::max() / 4) { sum %= mod; }
}
else
{
sum = sum * 2 + numSum * numMult;
if (sum > std::numeric_limits<long long>::max() / 4) { sum %= mod; }
numSum = (numSum * 2) % mod;
numMult++;
}
}
return (long)(sum % mod);
}
I am pretty sure there exists some simple way to get this code, yet I am still unable to see it. But sometimes path is the goal :-)
If a sequence has N zeros with indexes zero[0], zero[1], ... zero[N - 1], the number of inversions for it would be (zero[0] + zero[1] + ... + zero[N - 1]) - (N - 1) * N / 2. (you should be able to prove it)
For example, 11010 has two zeros with indexes 2 and 4, so the number of inversions would be 2 + 4 - 1 * 2 / 2 = 5.
For all 2^k sequences, you can calculate the sum of two parts separately and then add them up.
1) The first part is zero[0] + zero[1] + ... + zero[N - 1]. Each 0 in the the given sequence contributes index * 2^k and each ? contributes index * 2^(k-1)
2) The second part is (N - 1) * N / 2. You can calculate this using a dynamic programming (maybe you should google and learn this first). In short, use f[i][j] to present the number of sequence with j zeros using the first i characters of the given sequence.

Finding Sum of Square of Digits Beginner Bug C++

So, I started learning C++ recently. This code is trying to add the sum of the squares of each numbers digits. For example: 243: 2*2 + 4*4 + 3*3 = 29.
int sumOfSquareDigits(int n) //BUG WITH INPUT OF 10, 100, 1000, etc.
{
int digits = findDigits(n);
int number;
int remainder;
int *allDigits = new int[digits];
for (int i = 0; i < digits; i++) { //assigns digits to array
if (i + 1 == digits){ //sees if there is a ones value left
allDigits[i] = n;
}
else {
remainder = (n % findPower10(digits - (i + 1)));
number = ((n - remainder) / findPower10(digits - (i + 1)));
allDigits[i] = number; //records leftmost digit
n = n - (allDigits[i] * findPower10(digits - (i + 1))); //gets rid of leftmost number and starts over
}
}
int result = 0;
for (int i = 0; i < digits; i++) { //finds sum of squared digits
result = result + (allDigits[i] * allDigits[i]);
}
delete [] allDigits;
return result;
}
int findDigits(int n) //finds out how many digits the number has
{
int digits = 0;
int test;
do {
digits++;
test = findPower10(digits);
} while (n > test);
return digits;
}
int findPower10(int n) { //function for calculating powers of 10
int result = 1;
for (int i = 0; i < n; i++)
result = result * 10;
return result;
}
And after running the code, I've figured out that it (barely) mostly works. I've found that whenever a user inputs a value of 10, 100, 1000, etc. it always returns a value of 100. I'd like to solve this only using the iostream header.
Sorry if my code isn't too readable or organized! It would also be helpful if there are any shortcuts to my super long code, thanks!
The problem is in the findDigits function. For the values 10, 100, 1000 etc, it calculates the number of the digits minus one. This happens because of the comparison in the loop, you are stopping when n is less or equal to test, but in these cases n is equal test and you should run the next iteration.
So, you should change the line 33:
} while (n > test);
to:
} while (n >= test);
Now, it should work just fine. But it will not work for negative numbers (I don't know this is required, but the solution bellow works for that case too).
I came up with a much simpler solution:
int sumOfSquareDigits(int n)
{
// Variable to mantain the total sum of the squares
int sum = 0;
// This loop will change n until it is zero
while (n != 0) {
/// The current digit we will calculate the square is the rightmost digit,
// so we just get its value using the mod operator
int current = n % 10;
// Add its square to the sum
sum += current*current;
// You divide n by 10, this 'removes' one digit of n
n = n / 10;
}
return sum;
}
I found the problem challenging managed to reduce your code to the following lines:
long long sumOfSquareDigits(long long i) {
long long sum(0L);
do {
long long r = i % 10;
sum += (r * r);
} while(i /= 10);
return sum;
}
Haven't test it thoroughly but I think it works OK.

BigInt Multiplication w/ int arrays

I'm making a BigInt class in C++ as an exercise. I'm currently working on the multiplication functionality. My BigInt's are represented as a fixed length (that is very big) int[], with each entry being a digit of the number entered.
So, BigInt = 324, will result in [0,0,0,..,3,2,4].
I'm currently trying to multiply using this code:
// multiplication
BigInt BigInt::operator*(BigInt const& other) const {
BigInt a = *this;
BigInt b = other;
cout << a << b << endl;
BigInt product = 0;
for(int i = 0; i < arraySize; i++){
int carry = 0;
for(int j = 0; j < arraySize; j++){
product.digits[arraySize - (j + i)] += (carry + (a.digits[j] * b.digits[i]));
carry = (product.digits[arraySize - (j + i)] / 10);
product.digits[arraySize - (j + i)] = (product.digits[arraySize - (j + i)] % 10);
}
product.digits[arraySize - i] += carry;
}
return product;
}
My answer keeps returning 0. For example, 2 * 2 = 0.
It is not sure that this will fix your program, but you have Undefined Behavior because of this:
product.digits[arraySize - (j + i)]
This index arraySize - (j + i) becomes negative when i + j > arraySize, which will obviously occur in your loop.
Basically, when multiplying two numbers with n digits, the result may be as wide as 2n digits. Since you encode all your numbers on fixed length arraySize, you have to take measures to avoid out of bound.
A simple test if(i+j) <= arraySize could do, or by changing the second loop:
for(int j = 0; j < arraySize - i; j++)
Alternatively, it would be better to use std::vector as the internal representation of your BigInt. It can be sized dynamically to fit your result beforehand.
It is not completely sure that this will fix completely your code, but it has to be fixed, before proceeding with the debugging. It will be easier after removing the UB. Here I approve #Dúthomhas's note that your indexing through the arrays seems obviously irregular... You go from right to left with the result, while from left to right with the inputs...

I want to access a member variable of an object [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
When making a class how would I differentiate the two different class variables. I want to add elements in two vectors together and get a new vector with the sum of the two different numbers. In the code below when making an instance of a class I have access to it's vector but what about the one in parameters? number_blocks being the vector variable in the class BigInt
BigInt BigInt::add(const BigInt& number){
int flag = 0;
int carry = 0;
int sum = 0;
const int LIMIT = 9;
int size = number.length();
for(int i = 0; i < size; i++){
sum = number_blocks[i]// + number_blocks_number[i];
if(flag == 1){
sum = sum + carry;
flag = 0;
}
if(sum > LIMIT){
carry = sum / 10;
sum = sum % 10;
flag = 1;
}
number_blocks.push_back(sum);
}
return BigInt();
}
The same way you do number.length()
number.number_blocks[i]
BTW: you have to push the carry at the end (if nonzero).
Note: please ask specific questions. "I want to access a member variable of an object". show a one liner example. nobody cares about the rest.
Issues that I see with your implementation of BigInt::add:
You are returning an default instance of BigInt in the line:
return BigInt();
It makes sense to me that you would return a BigInt that is the result of adding two BigInts.
You are not taking into account the BigInts of varying length. For example, adding 187 with 85.
You are ignoring the last carry. If you add 9 and 9, you need to carry the 1.
The logic for computing the sum and the carry can be simplified to:
sum = this->number_blocks[i] + number.number_blocks[i] + carry;
carry = sum / 10;
sum = sum % 10;
You don't the variables flag and LIMIT.
Here's an implementation that addresses those issues.
BigInt BigInt::add(const BigInt& number){
int carry = 0;
int sum = 0;
// Compute the minimum number of digits from both the numbers.
size_t size1 = this->length();
size_t size2 = number.length();
size_t size = size1 < size2 ? size1 : size2;
BigInt ret;
// Process the digits that are in both the the first number and the
// second number.
for(size_t i = 0; i < size; i++)
{
sum = this->number_blocks[i] + number.number_blocks[i] + carry;
carry = sum / 10;
sum = sum % 10;
ret.number_blocks.push_back(sum);
}
// If the first number has more digits than the second, deal with the
// remaining digits from the first number.
if ( size1 > size )
{
for(size_t i = size; i < size1; i++)
{
sum = this->number_blocks[i] + carry;
carry = sum / 10;
sum = sum % 10;
ret.number_blocks.push_back(sum);
}
}
// If the second number has more digits than the first, deal with the
// remaining digits from the second number.
else if ( size2 > size )
{
for(size_t i = size; i < size2; i++)
{
sum = number.number_blocks[i] + carry;
carry = sum / 10;
sum = sum % 10;
ret.number_blocks.push_back(sum);
}
}
// Deal with the last carry.
if ( carry > 0 )
{
ret.number_blocks.push_back(carry);
}
return ret;
}