Dynamic BigBinaryString implmentation in C++ - c++

I am writing a BigBinaryString class in C++ which abstractly holds the large binary string and can perform operations like xor, and, left shift and right shift.
I have stored the binary string internally as a vector of unsigned longs, so each element in vector consumes 64-bits from the bitstring.
I have decided to use have four types of constructors:
BigBinaryString(const string bitstring) //for directly converting the bitstring to internal repr.
BigBinaryString() //initialize the binary string to 0.
BigBinaryString(const size_t num) //hold the binary for corresponding unsigned long.
BigBinaryString(const vector<size_t> vec) //Directly pass the internal repr to the constructor for it to copy.
So far I have implemented and, xor, equality and left shift operators.
However, I feel the left shift operator has a very high time complexity in which the way I have implemented it.
So, I need a few suggestions on how to speed up the left shift operator so that I can implement the right shift efficiently as well.
The code so far is as follows:
#define SIZE_UNSIGNED_LONG (sizeof(size_t) * 8)
class BigBinaryString {
private:
vector<size_t> num;
void reduce() {
while (*num.rbegin() == 0) {
num.pop_back();
}
if (num.size() == 0) {
num.push_back(0);
}
}
public:
BigBinaryString() { num.push_back(0); }
BigBinaryString(const size_t n) { num.push_back(n); }
BigBinaryString(const vector<size_t> vec) {
const size_t length = vec.size();
for (size_t i = 0; i < length; i++) {
num.push_back(vec.at(i));
}
reduce();
}
BigBinaryString operator&(const BigBinaryString& op) {
vector<size_t> vec;
size_t maxlen = max(num.size(), op.num.size());
size_t minlen = min(num.size(), op.num.size());
const size_t zero = 0;
for (size_t i = 0; i < minlen; i++) {
vec.push_back(num.at(i) & op.num.at(i));
}
return BigBinaryString(vec);
}
BigBinaryString(const string bitstring) {
string temp = bitstring;
size_t dec = 0;
while (temp.length() != 0) {
if (temp.length() > SIZE_UNSIGNED_LONG) {
dec = stoul(temp.substr(temp.length() - SIZE_UNSIGNED_LONG,
SIZE_UNSIGNED_LONG),
nullptr, 2);
temp = temp.substr(0, temp.length() - SIZE_UNSIGNED_LONG);
} else {
dec = stoul(temp, nullptr, 2);
temp = "";
}
num.push_back(dec);
}
reduce();
}
BigBinaryString operator^(const BigBinaryString& op) {
vector<size_t> vec;
size_t maxlen = max(num.size(), op.num.size());
size_t minlen = min(num.size(), op.num.size());
for (size_t i = 0; i < maxlen; i++) {
if (i < minlen) {
vec.push_back(num.at(i) ^ op.num.at(i));
} else if (maxlen == num.size()) {
vec.push_back(num.at(i));
} else if (maxlen == op.num.size()) {
vec.push_back(op.num.at(i));
}
}
return BigBinaryString(vec);
}
bool operator==(const BigBinaryString& op) {
if (num.size() != op.num.size()) {
return false;
}
size_t length = num.size();
for (size_t i = 0; i < length; i++) {
if (num.at(i) != op.num.at(i)) {
return false;
}
}
return true;
}
bool operator==(const size_t n) {
BigBinaryString op(n);
if (num.size() != op.num.size()) {
return false;
}
size_t length = num.size();
for (size_t i = 0; i < length; i++) {
if (num.at(i) != op.num.at(i)) {
return false;
}
}
return true;
}
bool operator!=(const BigBinaryString& op) { return not(*this == op); }
bool operator!=(const size_t op) { return not(*this == op); }
BigBinaryString operator<<(size_t shift) {
string bitstring = this->to_string();
bitstring.append(shift, '0');
return BigBinaryString(bitstring);
}
string to_string() {
string suffix = "";
string retval = "";
string prefix = "";
size_t n = 0;
for (auto i = num.rbegin(); i != num.rend(); i++) {
n = *i;
prefix.clear();
suffix.clear();
while (n != 0) {
suffix = (n % 2 == 0 ? "0" : "1") + suffix;
n /= 2;
}
if (i != num.rbegin()) {
prefix.append(SIZE_UNSIGNED_LONG - suffix.size(), '0');
}
prefix = prefix + suffix;
if (prefix.size() == SIZE_UNSIGNED_LONG) {
retval += prefix;
} else if (i == num.rbegin()) {
retval += prefix;
} else if (i != num.rbegin()) {
throw invalid_argument("prefix+suffix error");
}
}
return retval;
}
};
Any help will be appreciated!

Related

C++ program to count repeated words in a cstring

I've been working on a C++ program, I've made the logic but I'm unable to execute it. The question is:
Task: Write a program, using functions only, with the following features.
Program reads paragraph(s) from the file and stores in a string.
Then program counts the occurrence of each word in the paragraph(s) and stores all words with their number of occurrences.
If that word has appeared more than one time in whole string, it should store the word only once along its total occurrences.
The output described in above (in part 3) must be stored in a new file.
Sample input:
is the is and the is and the and is and only that is
Sample output:
is 5
the 3
and 4
only 1
that 1
I'll cut short to Occurrence program that I've written,
My logic is to store token into character array and then compare that array with main character array and do the increment:
void occurances() {
char* string = getInputFromFile();
char separators[] = ",.\n\t ";
char* token;
char* nextToken;
char* temp[100];
token = strtok_s(string, separators, &nextToken);
cout << temp;
int counter = 0;
int i = 0;
while ((token != NULL)) {
temp[i] = token;
i++;
for (int i = 0; i < strlen(string); i++) {
for (int j = 0; j < 100; j++) {
if ((strcmp(token, *temp)) == 0) {
counter++;
}
}
cout << temp << " : " << counter << endl;
}
if (token != NULL) {
token = strtok_s(NULL, separators, &nextToken);
}
}
}
This code is preposterous I know that, But please anyone be kind enough to give me a clue, actually I'm new to C++ . Thank you
If you store token into array this array should grow dynamically because the number of tokens is not known at the beginning. And according to the task description, you cannot use C++ standard containers, so, it is necessary to implement dynamic array manually, for example:
#include <iostream>
std::size_t increase_capacity_value(std::size_t capacity) {
if (capacity == 0) {
return 1;
}
else if (capacity < (SIZE_MAX / 2)) {
return capacity * 2;
}
return SIZE_MAX;
}
bool increase_array_capacity(char**& tokens_array, std::size_t*& tokens_count, std::size_t& capacity) {
const std::size_t new_capacity = increase_capacity_value(capacity);
if (new_capacity <= capacity) {
return false;
}
const std::size_t tokens_array_byte_size = new_capacity * sizeof(char*);
char** const new_tokens_array = static_cast<char**>(std::realloc(tokens_array, tokens_array_byte_size));
if (new_tokens_array == nullptr) {
return false;
}
tokens_array = new_tokens_array;
const std::size_t tokens_count_byte_size = new_capacity * sizeof(std::size_t);
std::size_t* const new_tokens_count = static_cast<std::size_t*>(std::realloc(tokens_count, tokens_count_byte_size));
if (new_tokens_count == nullptr) {
return false;
}
tokens_count = new_tokens_count;
capacity = new_capacity;
return true;
}
bool add_token(char* token, char**& tokens_array, std::size_t*& tokens_count, std::size_t& array_size, std::size_t& array_capacity) {
if (array_size == array_capacity) {
if (!increase_array_capacity(tokens_array, tokens_count, array_capacity)) {
return false;
}
}
tokens_array[array_size] = token;
tokens_count[array_size] = 1;
++array_size;
return true;
}
std::size_t* get_token_count_storage(char* token, char** tokens_array, std::size_t* tokens_count, std::size_t array_size) {
for (std::size_t i = 0; i < array_size; ++i) {
if (std::strcmp(token, tokens_array[i]) == 0) {
return tokens_count + i;
}
}
return nullptr;
}
bool process_token(char* token, char**& tokens_array, std::size_t*& tokens_count, std::size_t& array_size, std::size_t& array_capacity) {
std::size_t* token_count_ptr = get_token_count_storage(token, tokens_array, tokens_count, array_size);
if (token_count_ptr == nullptr) {
if (!add_token(token, tokens_array, tokens_count, array_size, array_capacity)) {
return false;
}
}
else {
++(*token_count_ptr);
}
return true;
}
int main() {
char string[] = "is the is and the is and the and is and only that is";
char separators[] = ",.\n\t ";
std::size_t token_array_capacity = 0;
std::size_t token_array_size = 0;
char** tokens_array = nullptr;
std::size_t* tokens_count = nullptr;
char* current_token = std::strtok(string, separators);
while (current_token != nullptr) {
if (!process_token(current_token, tokens_array, tokens_count, token_array_size, token_array_capacity)) {
break;
}
current_token = std::strtok(nullptr, separators);
}
// print the report only if all tokens were processed
if (current_token == nullptr) {
for (std::size_t i = 0; i < token_array_size; ++i) {
std::cout << tokens_array[i] << " : " << tokens_count[i] << std::endl;
}
}
std::free(tokens_array);
std::free(tokens_count);
}
godbolt.org
okay what if i want to store any token once, in an array and then replace it with new word while deleting duplicates in character array
It is also possible solution. But in general case, it is also necessary to allocate the memory dynamically for the current token. Because the lengths of tokens are also not known at the beginning:
void replace_chars(char* str, const char* chars_to_replace) {
while (str && *str != '\0') {
str = std::strpbrk(str, chars_to_replace);
if (str == nullptr) {
break;
}
const std::size_t number_of_delimiters = std::strspn(str, chars_to_replace);
for (std::size_t i = 0; i < number_of_delimiters; ++i) {
str[i] = '\0';
}
str += number_of_delimiters;
}
}
bool keep_token(char*& token_storage, const char* new_token) {
if (new_token == nullptr) {
return false;
}
const std::size_t current_token_len = token_storage ? std::strlen(token_storage) : 0;
const std::size_t requried_token_len = std::strlen(new_token);
if (token_storage == nullptr || current_token_len < requried_token_len) {
token_storage =
static_cast<char*>(std::realloc(token_storage, (requried_token_len + 1) * sizeof(char)));
if (token_storage == nullptr) {
return false;
}
}
std::strcpy(token_storage, new_token);
return true;
}
std::size_t count_tokens_and_replace(char* str, std::size_t str_len, const char* token) {
std::size_t number_of_tokens = 0;
std::size_t i = 0;
while (i < str_len) {
while (str[i] == '\0') ++i;
if (std::strcmp(str + i, token) == 0) {
replace_chars(str + i, token);
++number_of_tokens;
}
i += std::strlen(str + i);
}
return number_of_tokens;
}
int main() {
char string[] = "is the is and the is and the and is and only that is";
char separators[] = ",.\n\t ";
const std::size_t string_len = std::strlen(string);
replace_chars(string, separators);
std::size_t i = 0;
char* token = nullptr;
while (true) {
while (i < string_len && string[i] == '\0') ++i;
if (i == string_len || !keep_token(token, string + i)) break;
std::cout << token << " : " << count_tokens_and_replace(string + i, string_len - i, token) << std::endl;
}
std::free(token);
}
godbolt.org
But if it is known that the token length cannot be greater than N, it is possible to use the static array of chars to keep the current token. And it will allow to remove dynamic memory allocation from the code.

How to convert this JavaScript code to C++

Problem is to return any one combination from given array that sums up to the target. I'm new to C++. How can I complete the function howSum() below? I can't return null here since the return type is vector. Also I'm having trouble passing the vectors.
JavaScript:
const howSum = (targetSum, numbers) => {
if (targetSum === 0) return [];
if (targetSum < 0) return null;
for (let num of numbers) {
const remainder = targetSum - num;
const remainderResult = howSum(remainder, numbers);
if (remainderResult !== null)
{
return [...remainderResult, num];
}
}
return null;
};
C++:
vector<int> howSum(int targetSum, vector<int> numbers)
{
if(targetSum == 0) return {};
if(targetSum < 0) return; //can't return null here in C++
for (int i = 0; i < numbers.size(); i++)
{
int remainder = targetSum - numbers[i];
vector<int> remainderResult = howSum(remainder, numbers);
if(pass)
{
pass
}
}
}
You can use C++17 std::optional and return std::nullopt when it does not contain value.
#include <optional>
#include <vector>
std::optional<std::vector<int>>
howSum(int targetSum, const std::vector<int>& numbers) {
if (targetSum == 0)
return std::vector<int>{};
if (targetSum < 0)
return std::nullopt;
for (auto numer : numbers) {
const auto remainder = targetSum - numer;
auto remainderResult = howSum(remainder, numbers);
if (remainderResult) {
remainderResult->push_back(targetSum);
return remainderResult;
}
}
return std::nullopt;
}
Let your function return a bool to indicate if the vector result (returned as an out param) is valid or not. It's likely going to be more efficient to pass the array (vector) as an out param reference than as a return value anyway. (Although modern compilers can do some amazing optimizations these days.)
bool howSum(int targetSum, const std::vector<int>& numbers, std::vector<int>& result)
{
result.clear();
if (targetSum == 0) {
return true;
}
if (targetSum < 0) {
return false;
}
for (int num : numbers) {
const int remainder = targetSum - num;
bool recursion_result = howSum(remainder, numbers, result);
if (recursion_result) {
result.push_back(num);
return true;
}
}
return false;
}

Big integer multiplication with Karatsuba crashes with Segementation Fault because of Stack Overflow

So I'm developing a class "bignum" to operate with integers of any size. The thing is I made two different functions to multiply bignums. One is the standard multiplication and the other one is based on the karatsuba algorithm. I've got a small program to run tests on my implementation so that I can tell whether its working or not. So far with the Standard multiplication everything runs perfectly, but when I switch to the Karatsuba multiplication once the inputs start to be very long my program crashes with Segmentation Fault because of a Stack Overflow. However, it seems not to be a matter of how big the entry is as there are inputs far bigger that are calculated correctly, though some of them do crash. I appreciate if anyone can take a look and give me some clue on how to continue. This is what valgrind tells me with one of the failing inputs:
Stack overflow in thread #1: can't grow stack to 0x1ffe801000
Here I'm posting the minimal reproducible example. I took out as much code as I could.
The main:
#include "bignum.h"
int main()
{
bignum result;
while(cin >> result)
cout << result << endl;
return 0;
}
The class bignum.cc:
#include "bignum.h"
bignum abs(const bignum &n)
{
bignum c = n;
c.sign = 0;
return c;
}
void remove_zeros(bignum &n)
{
if(n == 0)
n = 0;
else if(n.digits[0] == 0 && n.size > 1)
{
size_t zeros = 1;
while(n.digits[zeros] == 0)
zeros++;
n.size -= zeros;
short_t *aux = new short_t[n.size];
for(size_t i = 0; i < n.size; i++)
aux[i] = n.digits[i + zeros];
delete[] n.digits;
n.digits = new short_t[n.size];
for(size_t i = 0; i < n.size; i++)
n.digits[i] = aux[i];
delete[] aux;
}
}
bool size_even(const bignum &n)
{
if(n.size % 2 || n.size == 1)
return false;
return true;
}
bignum sum(const bignum &a, const bignum &b, const short_t &s)
{
size_t size = 0;
size_t aux_a = 0;
size_t aux_b = 0;
if(a.size >= b.size)
{
size = a.size + 1;
aux_a = a.size - b.size;
}
else
{
size = b.size + 1;
aux_b = b.size - a.size;
}
bignum c(size);
c.sign = s;
for(size_t i = c.size - 1; i < c.size; i--)
{
if(i - aux_b - 1 < a.size)
c.digits[i] += a.digits[i - aux_b - 1];
if(i - aux_a - 1 < b.size)
c.digits[i] += b.digits[i - aux_a - 1];
if(c.digits[i] > 9)
{
c.digits[i] -= 10;
c.digits[i - 1]++;
}
}
remove_zeros(c);
return c;
}
bignum subtraction(const bignum &a, const bignum &b)
{
short_t bigger = 0;
short_t count = 0;
size_t size = 0;
size_t diff = 0;
short aux = 0;
size = max(a.size, b.size);
diff = size - min(a.size, b.size);
bignum c(size);
if(abs(a) == abs(b))
return c = 0;
else if(abs(b) > abs(a))
bigger++;
if(bigger && b.sign && !a.sign)
c.sign = 1;
else if(!bigger && a.sign && !b.sign)
c.sign = 1;
else if(bigger && !b.sign && !a.sign)
c.sign = 1;
else if(!bigger && a.sign && b.sign)
c.sign = 1;
for(size_t i = size - 1; i < size; i--)
{
if(bigger)
{
if(i - diff < a.size)
aux = b.digits[i] - a.digits[i - diff];
else
aux = b.digits[i];
}
else
{
if(i - diff < b.size)
aux = a.digits[i] - b.digits[i - diff];
else
aux = a.digits[i];
}
if(count)
{
aux--;
count--;
}
if(aux < 0)
{
aux += 10;
count++;
}
c.digits[i] = aux;
}
remove_zeros(c);
if(c == 0)
c.sign = 0;
return c;
}
bignum reduce(const bignum &n, const size_t &from, const size_t &to)
{
if(to <= from)
{
bignum c = 0;
return c;
}
else
{
bignum c(to - from);
for(size_t i = 0; i < c.size; i++)
{
if(from + i < to)
c.digits[i] = n.digits[from + i];
}
// En caso de que haya agarrado solo ceros
if(c.digits[0] == 0 && c.size != 1)
{
for(size_t i = 0; i < c.size; i++)
if(c.digits[i] != 0)
return c;
return c = 0;
}
return c;
}
}
bignum enlarge(const bignum &n, const size_t &zeros)
{
bignum c(n.size + zeros);
if(!zeros)
c = n;
else
{
for(size_t i = 0; i < n.size; i++)
c.digits[i] = n.digits[i];
}
return c;
}
void add_zeros(bignum &n, const ssize_t &zeros)
{
if(zeros > 0)
{
short_t *aux = new short_t[n.size];
for(size_t i = 0; i < n.size; i++)
aux[i] = n.digits[i];
delete[] n.digits;
n.digits = new short_t[n.size += zeros];
for(size_t i = 0; i < n.size; i++)
{
if(i < n.size - zeros)
n.digits[i] = aux[i];
else
n.digits[i] = 0;
}
delete[] aux;
}
else if(zeros < 0)
{
short_t *aux = new short_t[n.size + zeros];
for(size_t i = 0; i < n.size + zeros; i++)
aux[i] = n.digits[i];
delete[] n.digits;
n.digits = new short_t[n.size += zeros];
for(size_t i = 0; i < n.size; i++)
n.digits[i] = aux[i];
delete[] aux;
}
}
bignum karatsuba(const bignum &a, const bignum &b)
{
bignum a_ = abs(a);
bignum b_ = abs(b);
bignum c;
// Casos base
if(a_ == 0 || b_ == 0)
return c = 0;
if(a_.size < 2 || b_.size < 2)
{
c = mult_rec(a_, b_);
if(a.sign != b.sign)
c.sign = 1;
return c;
}
size_t diff = max(a_.size, b_.size) - min(a_.size, b_.size);
if(!diff)
{
if(!size_even(a_.size) && !size_even(b_.size))
{
add_zeros(a_, 1);
add_zeros(b_, 1);
diff += 2;
}
}
else if(a_.size > b_.size)
{
if(!size_even(a_.size))
{
add_zeros(a_, 1);
add_zeros(b_, diff + 1);
diff += 2;
}
else
add_zeros(b_, diff);
}
else if(b_.size > a_.size)
{
if(!size_even(b_.size))
{
add_zeros(b_, 1);
add_zeros(a_, diff + 1);
diff += 2;
}
else
add_zeros(a_, diff);
}
size_t n = a_.size;
size_t m = n / 2;
bignum x = karatsuba(reduce(a_, 0, m), reduce(b_, 0, m));
bignum y = karatsuba(reduce(a_, m, a_.size), reduce(b_, m, b_.size));
bignum z = karatsuba(reduce(a_, 0, m) + reduce(a_, m, a_.size),
reduce(b_, 0, m) + reduce(b_, m, b_.size)) - x - y;
add_zeros(x, n);
add_zeros(z, m);
c = x + y + z;
if(diff)
add_zeros(c, -diff);
if(a.sign != b.sign)
c.sign = 1;
return c;
}
bignum mult_rec(const bignum &a, const bignum &b)
{
bignum c;
if(a == 0 || b == 0)
return c = 0;
if(a == 1)
return c = b;
if(b == 1)
return c = a;
return c = mult_rec(a, b - 1) + a;
}
bignum division(const bignum &a, const bignum &b, bignum &remainder)
{
bignum c;
if(a == 0 || b > a)
return c = 0;
bignum aux = a - b;
c = 1;
while(1)
{
aux = aux - b;
if(aux.sign)
{
remainder = aux + b;
break;
}
c = c + 1;
}
remove_zeros(c);
return c;
}
bignum division_rec(const bignum &a, const bignum &b)
{
bignum remainder = 0;
if(a.size < (b.size + 2))
return division(a, b, remainder);
return division_rec(reduce(a, b.size + 1, a.size) + (enlarge(remainder, a.size - b.size - 1)), b)
+ enlarge(division(reduce(a, 0, b.size + 1), b,remainder), a.size - b.size - 1);
}
bignum::bignum()
{
digits = NULL;
size = 0;
sign = 0;
}
bignum::bignum(const size_t &s)
{
if(s <= 0)
{
digits = NULL;
size = 0;
sign = 0;
}
digits = new short_t[s];
size = s;
sign = 0;
for (size_t i = 0; i < size; i++)
digits[i] = 0;
}
bignum::bignum(const string &str, short_t s = 0)
{
string aux;
size = str.size();
digits = new short_t[size];
for(size_t i = 0; i < size; i++)
{
aux = str[i];
digits[i] = (short_t)stoi(aux);
}
sign = s;
}
bignum::bignum(const bignum &n)
{
if(!n.digits)
{
digits = NULL;
size = 0;
sign = 0;
}
else
{
digits = new short_t[n.size];
size = n.size;
sign = n.sign;
for(size_t i = 0; i < size; i++)
digits[i] = n.digits[i];
}
}
bignum::bignum(const int &n)
{
if(n < 0)
sign = 1;
else
sign = 0;
string str = to_string(n);
string aux;
size = str.size()-sign;
digits = new short_t[size];
for(size_t i = 0; i < size; i++)
{
aux = str[i + sign];
digits[i] = (short_t)stoi(aux);
}
}
bignum& bignum::operator = (const bignum &right)
{
if(&right != this)
{
delete[] digits;
if(!right.digits)
{
digits = NULL;
size = 0;
sign = 0;
}
else
{
digits = new short_t[right.size];
size = right.size;
sign = right.sign;
for(size_t i = 0; i < size; i++)
digits[i] = right.digits[i];
}
}
return *this;
}
bignum& bignum::operator = (const int &right)
{
bignum aux(to_string(right));
return *this = aux;
}
bignum::~bignum() {delete[] digits;}
bignum operator + (const bignum &a, const bignum &b)
{
if(!a.sign && !b.sign)
return sum(a, b, 0);
if(!a.sign && b.sign)
return subtraction(a, b);
if(a.sign && !b.sign)
return subtraction(a, b);
return sum(a, b, 1);
}
bignum operator + (const bignum &a, const int &n)
{
return a + bignum(to_string(n));
}
bignum operator - (const bignum &a, const bignum &b)
{
if(!a.sign && !b.sign)
return subtraction(a, b);
if(!a.sign && b.sign)
return sum(a, b, 0);
if(a.sign && !b.sign)
return sum(a, b, 1);
return subtraction(a, b);
}
bignum operator - (const bignum &a, const int &n)
{
return a - bignum(to_string(n));
}
bignum operator * (const bignum &a, const bignum &b)
{
return karatsuba(a, b);
}
bignum operator / (const bignum &a, const bignum &b)
{
bignum c;
if(b == 0)
return c;
if(a == 0 || abs(b) > abs(a))
return c = 0;
if(abs(a) == abs(b))
{
if(a.sign != b.sign)
return c = -1;
return c = 1;
}
if(abs(b) == 1)
{
c = abs(a);
if(a.sign != b.sign)
c.sign = 1;
return c;
}
c = division_rec(abs(a), abs(b));
if(a.sign != b.sign)
c.sign = 1;
return c;
}
ostream& operator << (ostream &os, bignum &n)
{
if(n.digits == NULL)
return os;
if(n.sign && n != 0)
os << "-";
for (size_t i = 0; i < n.size; i++)
os << n.digits[i];
delete[] n.digits;
n.digits = NULL;
return os;
}
istream& operator >> (istream &is, bignum &result)
{
stack<char> operations;
queue<string> output;
string input;
getline(is, input);
if(input.empty())
return is;
for(size_t i = 0; i < input.size(); i++)
{
if(isblank(input[i])){}
else if(isdigit(input[i]))
{
size_t pos = i++;
size_t len = 1;
while(isdigit(input[i]))
{
len++;
i++;
}
i--;
output.push(input.substr(pos, len));
}
else if(input[i] == '-')
{
size_t j = i;
while(j != 0 && isblank(input[--j])){}
if(isdigit(input[j]) || input[j] == ')')
{
if(!operations.empty())
{
while(operations.top() == '-' || operations.top() == '+' || operations.top() == '*' || operations.top() == '/')
output.push(string{operations.pull()});
}
operations.push(input[i]);
}
else
output.push(string{"s"});
}
else if(input[i] == '+')
{
size_t j = i;
while(j != 0 && isblank(input[--j])){}
if(isdigit(input[j]) || input[j] == ')')
{
if(!operations.empty())
{
while(operations.top() == '-' || operations.top() == '+' || operations.top() == '*' || operations.top() == '/')
output.push(string{operations.pull()});
}
operations.push(input[i]);
}
}
else if(input[i] == '*' || input[i] == '/')
{
if(!operations.empty())
{
while(operations.top() == '*' || operations.top() == '/')
output.push(string{operations.pull()});
}
operations.push(input[i]);
}
else if(input[i] == '(')
operations.push(input[i]);
else if(input[i] == ')')
{
if(operations.empty())
{
cout << "Syntax Error" << endl;
return is;
}
while(!operations.empty() && operations.top() != '(')
output.push(string{operations.pull()});
if(!operations.empty())
operations.pull();
else
{
cout << "Syntax Error" << endl;
return is;
}
}
}
if(!operations.empty())
{
if(operations.top() == '(' && output.empty())
{
cout << "Syntax Error" << endl;
return is;
}
else
{
if(output.empty())
{
cout << "Syntax Error" << endl;
return is;
}
else
{
while(!operations.empty())
output.push(string{operations.pull()});
}
}
}
string aux;
short_t sign = 0;
stack<bignum> numbers;
while(!output.empty())
{
aux = output.pull();
if(isdigit(aux[0]))
{
numbers.push(bignum(aux, sign));
if(sign)
sign--;
}
else if(aux[0] == 's')
sign++;
else if(numbers.length() < 2)
{
cout << "Syntax Error" << endl;
return is;
}
else if(aux[0] == '+')
{
result = numbers.pull();
result = numbers.pull() + result;
numbers.push(result);
}
else if(aux[0] == '-')
{
result = numbers.pull();
result = numbers.pull() - result;
numbers.push(result);
}
else if(aux[0] == '*')
{
result = numbers.pull();
bignum auxiliar = numbers.pull();
//result = numbers.pull() * result;
result = auxiliar * result;
numbers.push(result);
}
else if(aux[0] == '/')
{
result = numbers.pull();
result = numbers.pull() / result;
numbers.push(result);
}
}
if(!numbers.empty())
result = numbers.pull();
else
{
cout << "Syntax Error" << endl;
return is;
}
return is;
}
bool operator == (const bignum &a, const bignum &b)
{
if(a.size != b.size)
{
for(size_t i = 0; i < a.size; i++)
{
if(a.digits[i] != 0)
return false;
}
for(size_t i = 0; i < b.size; i++)
{
if(b.digits[i] != 0)
return false;
}
return true;
}
if(a.sign != b.sign)
return false;
for (size_t i = 0; i < a.size; i++)
{
if (a.digits[i] != b.digits[i])
return false;
}
return true;
}
bool operator == (const bignum &a, const int &b)
{
bignum c(to_string(b));
if(a == c)
return true;
return false;
}
bool operator != (const bignum &a, const bignum &b)
{
if(a == b)
return false;
return true;
}
bool operator != (const bignum &a, const int &n)
{
bignum c(to_string(n));
if(a != c)
return true;
return false;
}
bool operator > (const bignum &a, const bignum &b)
{
if(a.size < b.size)
return false;
if(a.size > b.size)
return true;
if(!a.sign && b.sign)
return true;
if(a.sign && !b.sign)
return false;
if(a == b)
return false;
for (size_t i = 0; i < a.size; i++)
{
if (a.digits[i] > b.digits[i])
return true;
else if(a.digits[i] < b.digits[i])
return false;
}
return false;
}
bool operator < (const bignum &a, const bignum &b)
{
if(a > b)
return false;
if(a == b)
return false;
return true;
}
The bignum.h:
#include <iostream>
#include <cstring>
#include <string>
#include "queue.h"
#include "stack.h"
using namespace std;
class bignum
{
private:
short_t *digits;
short_t sign;
size_t size;
friend bignum abs(const bignum &);
friend void remove_zeros(bignum &);
friend void add_zeros(bignum &, const ssize_t &);
friend bool size_even(const bignum &);
friend bignum reduce(const bignum &, const size_t &, const size_t &);
friend bignum enlarge(const bignum &, const size_t &);
friend bignum sum(const bignum &, const bignum &, const short_t &);
friend bignum subtraction(const bignum &, const bignum &);
friend bignum karatsuba(const bignum &, const bignum &);
friend bignum mult_rec(const bignum &, const bignum &);
friend bignum division(const bignum &, const bignum &, bignum &);
friend bignum division_rec(const bignum &, const bignum &);
public:
bignum();
bignum(const size_t &);
bignum(const string &, short_t);
bignum(const bignum &);
bignum(const int &);
bignum& operator = (const bignum &);
bignum& operator = (const int &);
~bignum();
friend bignum operator+(const bignum &, const bignum &);
friend bignum operator+(const bignum &, const int &);
friend bignum operator-(const bignum &, const bignum &);
friend bignum operator-(const bignum &, const int &);
friend bignum operator*(const bignum &, const bignum &);
friend bignum operator/(const bignum &, const bignum &);
friend ostream& operator<<(ostream &, bignum &);
friend istream& operator>>(istream &, bignum &);
friend bool operator==(const bignum &, const bignum &);
friend bool operator==(const bignum &, const int &);
friend bool operator!=(const bignum &, const bignum &);
friend bool operator!=(const bignum &, const int &);
friend bool operator<(const bignum &, const bignum &);
friend bool operator>(const bignum &, const bignum &);
};
The makefile:
all: calc
calc: mre.o bignum.o
g++ -std=c++11 -Wall -pedantic -g3 mre.o bignum.o -o calc
mre.o: mre.cc bignum.h
g++ -std=c++11 -Wall -pedantic -g3 -c mre.cc
bignum.o: bignum.cc bignum.h stack.h queue.h debug.h
g++ -std=c++11 -Wall -pedantic -g3 -c bignum.cc
clean:
$(RM) calc *.o
Some other librarires I used, queue.h:
#ifndef _QUEUE_H_
#define _QUEUE_H_
#include <cstdlib>
#include <iostream>
#include "debug.h"
#include "stack.h"
using namespace std;
typedef unsigned short short_t;
template <typename T>
class queue
{
public:
queue();
queue(const queue &);
queue &operator=(const queue &);
~queue();
T pull();
void pull(T &);
void push(const T &);
bool empty() const;
size_t length() const;
private:
stack<T> egress_;
stack<T> ingress_;
};
template <typename T>
queue<T>::queue() {}
template<typename T>
queue<T>::queue(const queue &q)
: egress_(q.egress_),
ingress_(q.ingress_)
{
}
template<typename T>
queue<T> &queue<T>::operator=(const queue<T> &rhs)
{
if (this != &rhs) {
egress_ = rhs.egress_;
ingress_ = rhs.ingress_;
}
return *this;
}
template<typename T>
queue<T>::~queue(){}
template<typename T>
T queue<T>::pull()
{
if (egress_.empty()) {
while (ingress_.empty() == false)
egress_.push(ingress_.pull());
}
return egress_.pull();
}
template<typename T>
void queue<T>::pull(T &top)
{
return this->pull();
}
template<typename T>
void queue<T>::push(const T &item)
{
ingress_.push(item);
}
template<typename T>
bool queue<T>::empty() const
{
return egress_.empty() && ingress_.empty() ? true : false;
}
template<typename T>
size_t queue<T>::length() const
{
return egress_.length() + ingress_.length();
}
#endif
stack.h:
#ifndef _STACK_H_
#define _STACK_H_
#include <iostream>
#include <cstdlib>
#include "debug.h"
using namespace std;
template <typename T>
class stack
{
public:
stack();
stack(size_t);
stack(const stack &);
stack &operator=(const stack &);
~stack();
T pull();
T top();
void pull(T &);
void push(const T &);
bool empty() const;
size_t length() const;
private:
void expand();
void contract();
size_t tos_;
size_t len_;
T *ptr_;
};
template<typename T>
stack<T>::stack()
: tos_(0),
len_(0),
ptr_(0)
{
}
template<typename T>
stack<T>::stack(size_t len)
: tos_(0),
len_(0),
ptr_(0)
{
ptr_ = new T[len_ = len];
}
template<typename T>
stack<T>::stack(const stack &st)
: tos_(0),
len_(0),
ptr_(0)
{
ptr_ = new T[len_ = st.tos_];
for (tos_ = 0; tos_ < st.tos_; ++tos_)
ptr_[tos_] = st.ptr_[tos_];
ASSERT(tos_ <= len_);
ASSERT(tos_ == st.tos_);
}
template<typename T>
stack<T> & stack<T>::operator=(const stack<T> &rhs)
{
if (this != &rhs) {
if (rhs.tos_ > len_) {
delete[] ptr_, len_ = 0;
ptr_ = new T[len_ = rhs.tos_];
}
for (tos_ = 0; tos_ < rhs.tos_; ++tos_)
ptr_[tos_] = rhs.ptr_[tos_];
}
ASSERT(tos_ <= len_);
ASSERT(tos_ == rhs.tos_);
return *this;
}
template<typename T>
stack<T>::~stack()
{
delete[] ptr_;
}
template<typename T>
T stack<T>::pull()
{
ASSERT(tos_ != 0);
ASSERT(tos_ <= len_);
ASSERT(ptr_ != NULL);
return ptr_[--tos_];
}
template<typename T>
void stack<T>::pull(T &top)
{
top = this->pull();
}
template<typename T>
T stack<T>::top()
{
if(tos_ > 0)
return ptr_[tos_ -1];
return 0;
}
template<typename T>
void stack<T>::push(const T &top)
{
if (tos_ >= len_)
expand();
ptr_[tos_++] = top;
}
template<typename T>
bool stack<T>::empty() const
{
return tos_ == 0 ? true : false;
}
template<typename T>
size_t stack<T>::length() const
{
return tos_;
}
template<typename T>
void stack<T>::expand()
{
size_t len;
size_t tos;
T *ptr = 0;
if (len_ != 0)
len = len_ << 1;
else
len = 1;
ptr = new T[len];
for (tos = 0; tos < tos_; ++tos)
ptr[tos] = ptr_[tos];
delete[] ptr_;
tos_ = tos;
len_ = len;
ptr_ = ptr;
ASSERT(tos_ < len_);
ASSERT(ptr_ != NULL);
}
template<typename T>
void stack<T>::contract()
{
std::abort();
}
#endif
debug.h:
#ifndef _DEBUG_H_
#define _DEBUG_H_
#ifdef DEBUG
#include <cstdlib>
#include <iostream>
#define ASSERT(expr) \
do { \
if (!(expr)) { \
std::cerr << "assertion " \
<< (#expr) \
<< " failed :-\\ {" \
<< __FUNCTION__ \
<< "() " \
<< __FILE__ \
<< ":" \
<< __LINE__ \
<< "}" \
<< std::endl; \
std::abort(); \
} \
} while (0)
#else
#define ASSERT(expr) do {} while (0)
#endif
#endif
Last but not least, the input that breaks the program:
((((4)-(5)(((((3+9-(4)(-1))-((4)-1-(-4)0))-((6+5(0)+(-5))((-4)-(-7)(-7)(-8))))+((((8)(0)(0)+3)+((-3)+68+(6)))-0+(-3)))((1(-8)(-6)-(-6))((((-2)(-4)-2(-5))+(-2)(4))-(((3)-(5)-(-4)+(-1))(2)+(-5))))))((((6)-(4)(3)-(9))+(((((-4)(-2)0-(-6))1+(-7))-(1+(-3)(-7)(-9)))-((((-3)-8+1-(-8))(0+(8)+(0)+(-4)))1+7)))+1(3)))((-3)+(4)((((3+0+(-3)+(-1))(((-1)(-2)+((0)-(-3)+(8)+(-7)))+(((-3)+(3)+(6)-8)+(1)(6))))-(-4)8)(((8)-(-8)(((0)+(-9)+((3)+(0)(9)(-1)))-((4-(-9)02)-((-6)(-8)-(-7)(4)))))-(((((6)+7+(-3)5)((9)+(1)-3*(5)))-(((-2)-(-1)-4-0)+((8)-6-(-3)(-3))))+0-(5))))))-(((((((((8)(7)-(2)-(-9))+((9)(-8)(4)-0))-(((5)+(4)(4)+(3))((8)(-1)+6+8)))-((((-1)-(-9)+(9)(0))-(0-(-2)+(-2)+(-3)))+(0)0))+(-7)+(2))(((1-(-4)-(((2)-(-7)-(-9)(-3))-(-7)(4)))+(((5+(4)-1+(-2))+((4)-(-7)+(-6)-5))-((-2)+6+(0)+(-4))))+((((8+(-5)-(1)+(0))-((4)+(-2)(-6)-0))((-9)(6)-((-4)3+(-7)+0)))+((((-8)+(-9)-(-5)0)((-7)(5)-(2)-(-5)))-4+(-6)))))+((-9)+(-8)+(2)(-4)))-((((((-2)-(0)+(-1)(-4))((((-1)(7)-1(-1))+(-3)(4))(8)-5))-((-7)(-9)-(((5(2)(-4)-2)(2*(-8)(0)-8))+(((5)+(-3)(-4)(-9))((-2)-(-2)-2+(-9))))))+7+(4))+((-9)+5-(3+0+(((((-1)+(-2)(8)(-9))-((-5)-(-4)-(-3)-3))(((-7)+(-1)+(-3)+(-3))0(3)))-((((0)(7)-(8)-(0))(6+(-9)-0+(4)))-(5)(6)))))))

runtime error: addition of unsigned offset to 0x7ffeba23a6e0

Here is my code, I wrote it on leetcode platform
const int N1 = 100+1;
const int N2 = 10e4+1;
class Solution {
public:
bool cache[N1][N2];
bool isSubsequence(string s, string t) {
int n1 = s.size();
int n2 = t.size();
for(int i=0; i<=n1; i++) {
for(int j=0; j<=n2; j++) {
if(i == 0)
cache[i][j] = true;
if(j == 0)
cache[i][j] = false;
if(s[i-1] == t[j-1])
cache[i][j] = cache[i-1][j-1];
else
cache[i][j] = cache[i][j-1];
}
}
return cache[n1][n2];
}
};
It gives following error, I don't know why. Please help.
error image
We don't have to cache anything for solving this problem, we can totally do that in constant memory.
This'd pass by looping through t with just one if statement:
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
std::cout.tie(NULL);
return 0;
}();
// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <string>
using ValueType = std::uint_fast16_t;
static const struct Solution {
static const bool isSubsequence(
const std::string source,
const std::string target
) {
const ValueType s_len = std::size(source);
const ValueType t_len = std::size(target);
ValueType s_index = 0;
for (ValueType t_index = 0; t_index < t_len && s_index < s_len; ++t_index) {
if (target[t_index] == source[s_index]) {
++s_index;
}
}
return s_index == s_len;
}
};
I solved this issue. Error was because of array index out of bounds.
Here is the edit part:
if(i == 0)
cache[i][j] = true;
else if(j == 0)
cache[i][j] = false;
else if(s[i-1] == t[j-1])
cache[i][j] = cache[i-1][j-1];
else
cache[i][j] = cache[i][j-1];
};

Creating custom std::streambuf

I am defining a custom std::streambuf class for use in file I/O. In this class, I am overloading the functions open, close, is_open, xsgetn, xsputn, overflow, underflow, and uflow. I then insert this buffer into an std::ifstream as follows (the same scenario holds for std::ofstream):
std::ifstream temp;
Filebuffer *buffer = new Filebuffer();
buffer->open(fileName.c_str(), std::ios_base::in | std::ios_base::binary);
temp.basic_ios<char>::rdbuf(buffer);
The implementation for Filebuffer (my custom class) is as follows:
std::streamsize
Filebuffer::xsputn(const char *s, std::streamsize n)
{
std::streamsize result = 0;
if(file && n)
{
for(;;)
{
size_t buffer_use = this->epptr() - this->pptr();
if(buffer_use > 0)
{
if(static_cast<int>(buffer_use) > n)
{
buffer_use = n;
}
std::char_traits<char>::copy(this->pptr(), s, buffer_use);
this->pbump(buffer_use);
result += buffer_use;
n -= buffer_use;
if(n == 0)
{
break;
}
s += buffer_use;
}
this->overflow(static_cast<int>(*s));
}
}
return result;
}
std::streamsize
Filebuffer::xsgetn(char *s, std::streamsize n)
{
std::streamsize result = 0;
if(file && n)
{
int ch; do
{
size_t buffer_use = this->egptr() - this->gptr();
if(buffer_use > 0)
{
if(static_cast<int>(buffer_use) > n)
{
buffer_use = n;
}
std::char_traits<char>::copy(s, this->gptr(), buffer_use);
this->gbump(buffer_use);
result += buffer_use;
n -= buffer_use;
if(n == 0)
{
break;
}
s += buffer_use;
}
ch = this->underflow();
} while(!(ch == std::char_traits<char>::eof()));
}
return result;
}
int
Filebuffer::underflow()
{
if(file)
{
nullify_put_area(); //clears write buffer
if(!buffer) //allocated in open()
{
int value = ungetc(fgetc(file), file);
if(value == EOF)
{
return std::char_traits<char>::eof();
}
return value;
}
char *begin = buffer;
char *end = buffer + bufferSize - 1; //bufferSize set to 4 KB
char *next = end;
if(this->gptr() < this->egptr())
{
size_t buffer_use = this->egptr() - this->gptr();
memmove(begin, next, buffer_use);
begin += buffer_use;
}
setg(begin, begin, begin);
size_t m = (bufferSize - 1 - (begin - this->eback()));
if(m > 0)
{
size_t status = fread(begin, 1, m, file);
if(status == 0)
{
return std::char_traits<char>::eof();
}
setg(this->eback(), this->gptr(), begin + status);
}
return static_cast<int>(*this->gptr());
}
return std::char_traits<char>::eof();
}
int
Filebuffer::uflow()
{
if(!file)
{
return std::char_traits<char>::eof();
}
int ch = underflow();
if(ch != std::char_traits<char>::eof())
{
if(buffer)
{
this->gbump(1);
}
else
{
fgetc(file);
}
}
return ch;
}
int
Filebuffer::overflow(int c)
{
if(!file)
{
return std::char_traits<char>::eof();
}
const char *begin = this->pbase();
char *next = this->pptr();
if(buffer)
{
setp(buffer, buffer + bufferSize - 1);
}
nullify_get_area(); //clears read buffer
char temp;
if(c == std::char_traits<char>::eof())
{
c = std::char_traits<char>::not_eof(std::char_traits<char>::eof());
}
else
{
if(!next)
{
begin = next = &temp;
}
assert(next == &temp || buffer <= next);
assert(next == &temp || next < buffer + bufferSize);
*next++ = static_cast<char>(c);
}
if(begin != next)
{
if(begin == &temp)
{
fputc(temp, file);
return c;
}
size_t n = next - begin;
size_t status = fwrite(begin, 1, n, file);
if(status != n)
{
return std::char_traits<char>::eof();
}
return c;
}
return std::char_traits<char>::eof();
}
Unfortunately, whenever I use (e.g.) temp >> readVar;, it does not use any of my overloaded functions - the call stack shows that the STL original implementations were called - and instead, simply reads in garbage. Per this question, I need to define overflow for ofstream (and presumably, underflow for ifstream), which I have done. Am I defining xsputn and xsgetn correctly? Why are my overloaded functions not being called?
It appears that trying to do this with std::ifstream will not work, and I need to change it std::istream. Once I make this change, the overloaded functions are called and everything works properly.