In this code I am calculating the number of unique Binary Search Trees using catlan numbers.
The answer remains correct until input value n=13 from n>=14 the answer turns out to be less by one. Eg. for n=14 my answer is 2674439 while the actual answer is 2674440.
Here is the code.
#include "stdafx.h"
#include "iostream"
using namespace std;
class Solution {
public:
double arr[20000] = {};
double fact(int n) {
if (n == 1 || n == 0)
return 1;
if (arr[n] != 0)
return arr[n];
return arr[n] = ceil(n*fact(n - 1));
}
int numTrees(int n) {
int res = fact(2 * n) / ((fact(n + 1))*fact(n));
return res;
}
};
int main()
{
Solution s;
cout << s.numTrees(14)<<endl;
return 0;
}
One of your intermediate values, 28! requires 98 bits of precision.
A double has 52-53 bits of precision.
The surprising part isn't that there is an error at 14, but rather that there wasn't an error before 14. This is because some effort was taken with double to reduce cumulative error, and you basically got lucky.
In this case, we are doing lots of math with multiplication, and next to none with addition. Working with prime powers is a good move:
struct product {
std::map<std::size_t, std::ptrdiff_t> powers;
product& operator*=( product const& rhs ) {
for (auto&& e:rhs.powers)
powers[e.first] += e.second;
return tidy(*this);
}
product& operator/=( product const& rhs ) {
for (auto&& e:rhs.powers)
powers[e.first] -= e.second;
return tidy(*this);
}
friend product operator*( product lhs, product const& rhs ) {
lhs *= rhs;
return lhs;
}
friend product operator/( product lhs, product const& rhs ) {
lhs /= rhs;
return lhs;
}
// 1/x overload:
friend product operator~( product p ) {
for (auto& e:p.powers)
e.second = -e.second;
return p;
}
product() = default;
product(product const&) = default;
product(product &&) = default;
product& operator=(product const&) = default;
product& operator=(product &&) = default;
product( std::size_t in ); // TODO
bool is_integral() const {
for (auto& e:powers)
if (e.second < 0) return false;
return true;
}
template<class Scalar=std::size_t>
Scalar numerator() const {
Scalar r = 1;
for( auto& e: powers )
for (std::ptrdiff_t i = 0; i < e.second; ++i)
r *= e.first;
return r;
}
template<class Scalar=std::size_t>
Scalar denominator() const {
Scalar r = 1;
for( auto& e: powers )
for (std::ptrdiff_t i = 0; i > e.second; --i)
r *= e.first;
return r;
}
friend product& tidy(product& p) {
for (auto it = p.powers.begin(); it != p.powers.end();) {
if (!it->second)
it = p.powers.erase(it);
else
++it;
}
return p;
}
};
Here is a little factorial engine:
struct factorial_t {
std::vector<product> values;
factorial_t():values(2) {}
product const& operator()( std::size_t in ) {
if (values.size() > in) {
return values[in];
}
values.push_back( (*this)(in-1)*product{in} );
return values.back();
}
};
factorial_t factorial;
which is perfectly precise up to ridiculous values.
numTrees then becomes:
template<class Scalar=std::size_t>
Scalar numTrees(std::size_t n) {
auto res = factorial(2 * n) / ((factorial(n + 1))*factorial(n));
return res.numerator<Scalar>();
}
what is remaining to do is write code that prime factors a std::size_t.
struct factor_t {
std::vector<std::size_t> primes;
factor_t():primes{2,3,5,7,11,13,17} {}
bool make_primes( std::size_t up_to ) {
if ((primes.back()+2) > up_to)
return false;
bool added_prime = false;
for (std::size_t x = primes.back()+2; x < up_to; x += 2) {
bool found = false;
for (auto p:primes)
{
if (p*p > x) break;
if (x%p) continue;
found = true;
break;
}
if (found)
primes.push_back(x);
added_prime = added_prime || found;
}
return added_prime;
}
product operator()( std::size_t in ) {
product r;
for (auto&& prime:primes)
{
while (!(in%prime)) {
r.powers[prime]++;
in /= prime;
}
}
// are there more primes to apply?
if (make_primes(std::sqrt(in)))
{
r *= (*this)(in);
}
else if (in != 1)
{
// in is a prime
r.powers[in]++;
}
return r;
}
};
factor_t factor;
product::product( std::size_t in ):
product(factor(in))
{}
and bob is your uncle.
(amusingly, the product code I wrote "works" accidentally with a 0, as it factor mistakes 0 for a prime, and a product with a positive 0 factor has a .numerator() of 0. If you divide, you end up with a 0 in the denominator, and if they cancel I pretend it never happens. However, in general, don't feed the product class a 0.)
The problem is this function:
int numTrees(int n) {
int res = fact(2 * n) / ((fact(n + 1))*fact(n));
return res;
}
Basically, by converting the double values to int you are losing some precision, and therefore cant come to the correct value. If you change it to double, the problem disappears.
Corrected function:
double numTrees(int n)
{
double res = fact(2 * n) / ((fact(n + 1))*fact(n));
return res;
}
Related
I am implementing a kind of dataframe and I want to define a RandomAccessIterator over it, in order to execute the different std algorithms, such as the sorting one. The dataframe of the example contains two column "a" and "b":
a; b;
20; 21;
20; 19;
10; 11;
40; 41;
10; 11;
After sorting with a trivial selection sort this is the result:
a; b;
10; 11;
10; 11;
20; 19;
20; 21;
40; 41;
The problem that I am facing is that the std::sort does not work properly. And I don't know weather the implementation of the iterator is sound or not.
This is the code.
File: dataframe.hpp
#pragma once
#include <iostream>
#include <charconv>
#include <vector>
#include <memory>
#include <cstring>
#include <numeric>
#include "iterator.hpp"
namespace df
{
class Record;
class Column;
class Dataframe;
namespace types
{
enum class Base : char
{
CHAR = 'A',
UNSIGNED = 'U',
// Other types..
};
class Dtype
{
public:
Dtype(types::Base base, std::size_t size) : m_base_dtype{base}, m_size{size} {}
[[nodiscard]] auto name() const
{
return std::string{static_cast<char>(m_base_dtype)} + std::to_string(m_size);
}
[[nodiscard]] auto base() const { return m_base_dtype; }
[[nodiscard]] auto size() const { return m_size; }
[[nodiscard]] auto is_primitive() const
{
switch (base())
{
case types::Base::CHAR:
return size() == 1;
case types::Base::UNSIGNED:
return size() == 1 or size() == 2 or size() == 4 or size() == 8;
}
return false;
}
private:
types::Base m_base_dtype;
std::size_t m_size;
};
[[nodiscard]] static auto CHAR(const std::size_t size) { return Dtype(types::Base::CHAR, size); }
[[nodiscard]] static auto UNSIGNED(const std::size_t size) { return Dtype(types::Base::UNSIGNED, size); }
}
class Column
{
public:
Column(std::vector<char> &raw, const types::Dtype dtype) : m_raw{std::move(raw)}, m_dtype{dtype} {}
Column &operator=(Column &&c) = default; // Move constructor
[[nodiscard]] const auto &dtype() const { return m_dtype; }
[[nodiscard]] auto &raw() { return m_raw; }
[[nodiscard]] const auto &raw() const { return m_raw; }
[[nodiscard]] auto *data() { return m_raw.data(); }
[[nodiscard]] const auto *data() const { return m_raw.data(); }
private:
std::vector<char> m_raw;
types::Dtype m_dtype;
};
class Dataframe
{
public:
Dataframe(std::vector<char> &raw, std::vector<std::string> names, std::vector<types::Dtype> dtypes)
{
m_raw = std::move(raw);
m_column_dtypes = dtypes;
m_column_names = names;
m_record_size = 0;
for (const auto dt : dtypes)
{
m_column_offsets.emplace_back(m_record_size);
m_record_size += dt.size();
}
m_record_count = m_raw.size() / m_record_size;
}
Dataframe(std::vector<char> &raw, std::vector<types::Dtype> dtypes) : Dataframe(raw, {}, dtypes) {}
Dataframe &operator=(Dataframe &&c) = default; // Move constructor
[[nodiscard]] auto &raw() { return m_raw; }
[[nodiscard]] const auto &raw() const { return m_raw; }
[[nodiscard]] auto *data() { return m_raw.data(); }
[[nodiscard]] const auto *data() const { return m_raw.data(); }
// Iterators
[[nodiscard]] df::Iterator begin()
{
return df::Iterator{m_raw.data(), m_record_size};
}
[[nodiscard]] df::Iterator end()
{
return df::Iterator{m_raw.data() + m_raw.size(), m_record_size};
}
[[nodiscard]] auto shape() const { return std::make_pair(m_record_count, m_column_dtypes.size()); }
[[nodiscard]] auto record_count() const { return m_record_count; }
[[nodiscard]] auto record_size() const { return m_record_size; }
[[nodiscard]] const auto &names() const { return m_column_names; }
[[nodiscard]] const auto &dtypes() const { return m_column_dtypes; }
[[nodiscard]] const auto &offsets() const { return m_column_offsets; }
void print() { print(m_record_count); }
void print(const std::size_t initial_records)
{
// Print header
for (auto column_name : m_column_names)
{
std::cout << column_name << "; ";
}
std::cout << std::endl;
// Print rows
std::size_t records_to_print = std::min(initial_records, m_record_count);
for (std::size_t i = 0; i < records_to_print; i++)
{
const auto start_p = i * record_size();
auto start_field = 0;
auto end_field = 0;
for (auto field : m_column_dtypes)
{
end_field += field.size();
switch (field.base())
{
case types::Base::UNSIGNED:
{
std::uint64_t uint_value = 0;
memcpy(&uint_value, m_raw.data() + start_p + start_field, field.size());
std::cout << uint_value;
break;
}
case types::Base::CHAR:
{
std::string str_value = std::string(m_raw.data() + start_p + start_field, field.size());
std::cout << str_value;
break;
}
}
start_field = end_field;
// New column
std::cout << "; ";
}
// New row
std::cout << std::endl;
}
}
std::shared_ptr<Dataframe> copy() const
{
auto x = std::vector<char>(m_raw);
return std::make_shared<Dataframe>(x, std::vector<std::string>(m_column_names), std::vector<types::Dtype>(m_column_dtypes));
}
private:
std::vector<char> m_raw = {};
std::vector<std::string> m_column_names = {};
std::vector<types::Dtype> m_column_dtypes = {};
std::vector<std::size_t> m_column_offsets = {};
std::size_t m_record_size = {};
std::size_t m_record_count = {};
};
using namespace types;
static std::shared_ptr<Dataframe> read_from_vector(const std::vector<std::vector<std::string>> values, const std::vector<std::string> names, const std::vector<Dtype> dtypes)
{
const auto record_size = std::accumulate(dtypes.begin(), dtypes.end(), std::size_t{0},
[](std::size_t accum, const auto &m)
{ return accum + m.size(); });
const auto total_size = values.size() * record_size;
const std::size_t INCR_RECORDS = std::max(total_size / (10 * record_size), std::size_t{65536});
auto raw = std::vector<char>{};
std::size_t written_records = 0;
auto offsets = std::vector<std::size_t>{};
for (int offset = 0; const auto &kd : dtypes)
{
offsets.push_back(offset);
offset += kd.size();
}
for (auto value : values)
{
if (written_records >= raw.size() / record_size)
{
raw.resize(raw.size() + INCR_RECORDS * record_size, char{' '});
}
for (int i = 0; i < names.size(); i++)
{
const auto name = names[i];
const auto dtype = dtypes[i];
const auto offset = offsets[i];
const auto pos = written_records * record_size + offset;
switch (dtype.base())
{
case df::Base::CHAR:
{
const auto v = value[i];
const auto byte_to_copy = std::min(v.size(), dtype.size());
std::memcpy(raw.data() + pos,
v.data() + v.size() - byte_to_copy, byte_to_copy); // Prendo gli ultimi byte
break;
}
case df::Base::UNSIGNED:
{
const auto v = std::stoull(value[i]);
const auto byte_to_copy = dtype.size();
std::memcpy(raw.data() + pos, &v, byte_to_copy); // Prendo gli ultimi byte
break;
}
default:
throw std::runtime_error("ColumnType non riconosciuto");
}
}
written_records++;
}
raw.resize(written_records * record_size);
raw.shrink_to_fit();
return std::make_shared<Dataframe>(raw, names, dtypes);
}
}
File: iterator.hpp
#pragma once
#include <iostream>
#include <cstring>
namespace df
{
class Iterator
{
std::size_t size;
char *ptr;
public:
struct record_reference;
struct record_value
{
std::size_t size;
char *ptr;
record_value(const record_reference &t) : record_value(t.size, t.ptr){};
record_value(const std::size_t m_size, char *m_ptr)
{
this->size = m_size;
this->ptr = new char[this->size];
std::memcpy(ptr, m_ptr, this->size);
}
~record_value()
{
delete[] this->ptr;
}
};
struct record_reference
{
std::size_t size;
char *ptr;
record_reference(const std::size_t m_size, char *m_ptr)
{
this->size = m_size;
this->ptr = m_ptr;
}
record_reference(const record_reference &t)
{
this->size = t.size;
this->ptr = t.ptr;
}
// record_reference(const record_value &t) : record_reference(t.size, t.ptr) {};
record_reference &operator=(const record_value &t)
{
std::memcpy(ptr, t.ptr, size);
return *this;
}
record_reference &operator=(const record_reference &t)
{
std::memcpy(ptr, t.ptr, size);
return *this;
}
record_reference &operator=(char *t)
{
std::memcpy(ptr, t, size);
return *this;
}
operator char *()
{
return ptr;
}
operator const char *() const { return ptr; }
};
using iterator_category = std::random_access_iterator_tag;
using value_type = record_value;
using reference = record_reference;
using difference_type = std::ptrdiff_t;
// default constructible
Iterator() : size(0), ptr(nullptr)
{
}
// copy assignable
Iterator &operator=(const Iterator &t)
{
size = t.size;
ptr = t.ptr;
return *this;
}
Iterator(char *ptr, const std::size_t size) : size{size}, ptr(ptr)
{
}
record_reference operator*() const
{
return {size, ptr};
}
// Prefix
Iterator &operator++()
{
ptr += size;
return *this;
}
// Postfix
Iterator operator++(int)
{
auto tmp = *this;
++*this;
return tmp;
}
Iterator &operator--()
{
ptr -= size;
return *this;
}
difference_type operator-(const Iterator &it) const
{
return (this->ptr - it.ptr) / size;
}
Iterator operator+(const difference_type &offset) const
{
return Iterator(ptr + offset * size, size);
}
friend Iterator operator+(const difference_type &diff, const Iterator &it)
{
return it + diff;
}
Iterator operator-(const difference_type &diff) const
{
return Iterator(ptr - diff * size, size);
}
reference operator[](const difference_type &offset) const
{
return {size, ptr + offset * size};
}
bool operator==(const Iterator &it) const
{
return this->ptr == it.ptr;
}
bool operator!=(const Iterator &it) const
{
return !(*this == it);
}
bool operator<(const Iterator &it) const
{
return this->ptr < it.ptr;
}
bool operator>=(const Iterator &it) const
{
return this->ptr >= it.ptr;
}
bool operator>(const Iterator &it) const
{
return this->ptr > it.ptr;
}
bool operator<=(const Iterator &it) const
{
return this->ptr <= it.ptr;
}
Iterator &operator+=(const difference_type &diff)
{
ptr += diff * size;
return *this;
}
operator Iterator() const
{
return Iterator(ptr, size);
}
};
void swap(df::Iterator::record_reference a, df::Iterator::record_reference b)
{
unsigned char *p;
unsigned char *q;
unsigned char *const sentry = (unsigned char *)a.ptr + a.size;
for (p = (unsigned char *)a.ptr, q = (unsigned char *)b.ptr; p < sentry; ++p, ++q)
{
const unsigned char t = *p;
*p = *q;
*q = t;
}
}
}
File: comparator.hpp
#pragma once
#include <memory>
#include <functional>
#include "dataframe.hpp"
#include "iterator.hpp"
namespace compare
{
using comparator_fn = std::function<int(const df::Iterator::record_reference, const df::Iterator::record_reference)>;
template <typename T, std::size_t offset = 0, std::size_t size = sizeof(T)>
static inline comparator_fn make_comparator()
{
if constexpr (size == 3 or size == 5 or size == 7 or size > 8)
return [=](const df::Iterator::record_reference a, const df::Iterator::record_reference b)
{ return std::memcmp(a + offset, b + offset, size); };
return [](const df::Iterator::record_reference a, const df::Iterator::record_reference b)
{ return *(T *)(a + offset) < *(T *)(b + offset) ? -1 : *(T *)(b + offset) < *(T *)(a + offset) ? +1
: 0; };
}
template <typename T>
static inline comparator_fn make_comparator(const std::size_t offset)
{
return [=](const df::Iterator::record_reference a, const df::Iterator::record_reference b)
{ return *(T *)(a + offset) < *(T *)(b + offset) ? -1 : *(T *)(b + offset) < *(T *)(a + offset) ? +1
: 0; };
}
static inline comparator_fn make_column_comparator(const df::Dtype dtype, const std::size_t offset)
{
switch (dtype.base())
{
case df::Base::CHAR:
{
if (dtype.size() == 1)
return make_comparator<std::uint8_t>(offset);
else if (dtype.size() == 2)
return [=](const df::Iterator::record_reference a, const df::Iterator::record_reference b)
{ return std::memcmp(a + offset, b + offset, 2); }; // C'� qualche beneficio a fissare il 2? o conviene trattarlo come uno unsigned short?
return [=](const df::Iterator::record_reference a, const df::Iterator::record_reference b)
{ return std::memcmp(a + offset, b + offset, dtype.size()); };
}
case df::Base::UNSIGNED:
{
return [=](const df::Iterator::record_reference a, const df::Iterator::record_reference b)
{
std::uint64_t uint_value_a = 0;
std::uint64_t uint_value_b = 0;
std::memcpy(&uint_value_a, a + offset, dtype.size());
std::memcpy(&uint_value_b, b + offset, dtype.size());
return (uint_value_a < uint_value_b ? -1 : uint_value_a > uint_value_b ? +1
: 0);
};
}
default:
throw std::runtime_error("Unsupported dtype");
break;
}
}
static inline comparator_fn make_composite_two_way_comparator(const std::shared_ptr<df::Dataframe> &T)
{
const auto K = T->dtypes().size();
std::vector<comparator_fn> F;
for (int i = 0; i < K; i++)
{
F.emplace_back(make_column_comparator(T->dtypes()[i], T->offsets()[i]));
}
const auto comparator = [=](const df::Iterator::record_reference a, const df::Iterator::record_reference b)
{
for (int i = 0; i < K; i++)
{
// If equal go to the next column, otherwise return the result
// The return value is true if the first argument is less than the second
// and false otherwise
if (const auto result = F[i](a, b); result != 0)
return result < 0;
}
return false;
};
return comparator;
}
}
File: main.cpp
#include <iostream>
#include <vector>
#include "dataframe.hpp"
#include "comparator.hpp"
template <typename RandomAccessIterator, typename Comparator>
static void selection_sort(RandomAccessIterator first, RandomAccessIterator last, Comparator comp)
{
for (auto i = first; i != last; ++i)
{
auto min = i;
for (auto j = i + 1; j != last; ++j)
{
if (comp(*j, *min))
min = j;
}
df::Iterator::value_type temp = *i;
*i = *min;
*min = temp;
// Alternative
// std::iter_swap(i, min);
}
}
int main(int argc, char const *argv[])
{
std::vector<std::string> values{"20", "21", "20", "19", "10", "11", "40", "41", "10", "11"};
// Create a vector that contains values grouped by 2
std::vector<std::vector<std::string>> v;
for (int i = 0; i < values.size(); i += 2)
{
std::vector<std::string> temp;
temp.push_back(values[i]);
temp.push_back(values[i + 1]);
v.push_back(temp);
}
std::vector<std::string> column_names = {"a", "b"};
df::Dtype d = df::Dtype(df::Base::UNSIGNED, 4);
std::vector dtypes = {d, d};
// Create a dataframe
std::shared_ptr<df::Dataframe> df = df::read_from_vector(v, column_names, dtypes);
std::cout << "Before sorting" << std::endl;
df->print();
// This comparator sorts the dataframe first by column a and then by column b in ascending order
auto comparator = compare::make_composite_two_way_comparator(df);
selection_sort(df->begin(), df->end(), comparator);
std::cout << "\nAfter sorting" << std::endl;
df->print();
// With the std::sort it does not work
std::sort(df->begin(), df->end(), comparator);
return 0;
}
Your type is not a C++17 RandomAccessIterator, because it isn't a C++17 ForwardIterator, because reference is an object type, not a reference type.
The type It satisfies ForwardIterator if
Let T be the value type of It. The type std::iterator_traits<It>::reference must be either
T& or T&& if It satisfies OutputIterator (It is mutable), or
const T& or const T&& otherwise (It is constant),
(Other requirements elided)
You will be able to satisfy the C++20 concept std::random_access_iterator, because that relaxes the requirement on It::reference.
In C++17, the reference type of an iterator must be precisely value_type& in order for that iterator to be random access. Only input iterators can have the reference type be something other than value_type&. So in C++17, proxy iterators are limited to input iterators. And every algorithm written against C++17 has this expectation.
The C++20 ranges library adds the ability to have random access proxy iterators. And the C++20 algorithms that use those range concepts will respect them.
Following the question in Pointer to portions of array, a structure that does operations with portions of an array was proposed.
I would like to request one further question within this issue.
I would like to create a structure for blockMatrices using std::vector and would require to change the implementation of the structure for getting a 3x3 matrix out of a 4x4 matrix.
The current test case is:
#include <vector>
#include <array>
#include <iostream>
// define matrix 4x4
typedef std::array<double, 16> matrix4;
// define matrix 3x3
typedef std::array<double, 9> matrix3;
// get 3x3 matrix out of a 4x4 matrix
struct subMat
{
matrix4& matrix_;
const double& operator[](size_t index) const
{
static size_t mapping[] = {0, 1, 2, 4, 5, 6, 8, 9, 10};
return matrix_[mapping[index]];
}
subMat (matrix4& A): matrix_(A){}
};
template <typename T>
double sum_of_elements(const T& arr)
{
double res = 0;
for (int i=0;i < 9; ++i)
{
res += arr[i];
}
return res;
}
int main(int argCount, char *args[])
{
std::vector<matrix4> myBlockMatrix(5);
for (int i=0; i < myBlockMatrix.size(); i++)
{
for (int j = 0; j<myBlockMatrix[0].size(); j++)
{
myBlockMatrix[i][j] = i*j;
}
}
for (int i = 0; i<myBlockMatrix.size(); i++)
{
std::cout << sum_of_elements(subMat(myBlockMatrix[i])) << std::endl; // this works
}
subBlockMatrix subBlock (myBlockMatrix);
for (int i = 0; i<myBlockMatrix.size(); i++)
{
std::cout << sum_of_elements(subBlock[i])) << std::endl;
}
return 0;
}
For overloading the [] operator, I have:
struct subBlockMatrix : std::vector<matrix4>
{
std::vector<matrix4>& blockMatrix_;
const matrix4& operator[](std::size_t index) const
{
static size_t mapping[] = {0, 1, 2, 4, 5, 6, 8, 9, 10};
return blockMatrix_[mapping[index]];
}
subBlockMatrix(std::vector<matrix4>& A) : blockMatrix_(A) {}
};
But this does not work...
I am having difficulty understanding how to make it work and would really appreciate the help!
Best Regards
I'd start with a matrix view, which starts with an array view.
#include <vector>
#include <iostream>
template<class T, class Size=std::size_t, class Stride=Size>
struct array_view {
array_view( T* start, Size sz, Stride s ):
b(start), length(sz), stride(s) {}
array_view( T* start, Size sz = {} ):
b(start), length(sz), stride(sz) {}
array_view() = default;
array_view( T* start, T* finish ):
array_view(start, finish-start) {}
T* begin() const { return b; }
T* end() const { return b+length; }
std::size_t size() const { return length; }
bool empty() const { return size() == 0; }
explicit operator bool() const { return b; }
T& operator[]( std::size_t i ) const { return begin()[i]; }
array_view& operator++() {
*this += 1;
return *this;
}
array_view operator++(int)& {
auto self = *this;
++this;
return self;
}
array_view& operator--() {
*this -= 1;
return *this;
}
array_view operator--(int)& {
auto self = *this;
--this;
return self;
}
array_view& operator+=(std::ptrdiff_t delta)&{
b+=delta*length;
return *this;
}
array_view& operator-=(std::ptrdiff_t delta)&{
b-=delta*length;
return *this;
}
friend array_view operator+(array_view self, std::ptrdiff_t delta) {
self += delta;
return self;
}
friend array_view operator-(array_view self, std::ptrdiff_t delta) {
self -= delta;
return self;
}
friend array_view operator+(std::ptrdiff_t delta, array_view self) {
self += delta;
return self;
}
friend array_view operator-(std::ptrdiff_t delta, array_view self) {
self -= delta;
return self;
}
// checks address, not contents
friend bool operator==(array_view const& lhs, array_view const& rhs) {
return lhs.b == rhs.b && lhs.length == rhs.length && lhs.stride == rhs.stride;
}
friend bool operator!=(array_view const& lhs, array_view const& rhs) {
return !(lhs==rhs);
}
private:
T* b = nullptr;
Size length = {};
Stride stride = {};
};
then we get a matrix_view. First we write an index_iterator for an iterator wrapper around something that is a value (like a sequence of rows or columns, or an integer):
template<class V>
struct index_iterator {
index_iterator(V v):value(v) {}
V const& operator*() const& { return value; }
V& operator*()& { return value; }
V operator*()&& { return std::move(value); }
V* operator->() { return std::addressof(value); }
V const* operator->() const { return std::addressof(value); }
friend bool operator==(index_iterator const& lhs, index_iterator const& rhs ) {
return lhs.value==rhs.value;
}
friend bool operator!=(index_iterator const& lhs, index_iterator const& rhs ) {
return lhs.value!=rhs.value;
}
index_iterator& operator++() {
++value;
return *this;
}
index_iterator operator++(int)& {
auto self = *this;
++value;
return self;
}
index_iterator& operator--() {
--value;
return *this;
}
index_iterator operator--(int)& {
auto self = *this;
--value;
return self;
}
index_iterator& operator+=( std::ptrdiff_t delta )& {
value += delta;
return *this;
}
index_iterator& operator-=( std::ptrdiff_t delta )& {
value -= delta;
return *this;
}
friend index_iterator operator+(index_iterator self, std::ptrdiff_t delta) {
self += delta;
return self;
}
friend index_iterator operator-(index_iterator self, std::ptrdiff_t delta) {
self -= delta;
return self;
}
friend index_iterator operator+(std::ptrdiff_t delta, index_iterator self) {
self += delta;
return self;
}
friend index_iterator operator-(std::ptrdiff_t delta, index_iterator self) {
self -= delta;
return self;
}
V operator[](std::size_t i)const {
return *((*this) + i);
}
private:
V value = {};
};
template<class T, class M=std::size_t, class Stride=M, class N=M>
struct matrix_view {
using row_view = array_view<T, N, Stride>;
matrix_view( T* start, M cols={}, Stride stride = {}, N rows={} ):
b(start), m(cols), s(stride), n(rows)
{}
matrix_view() = default;
index_iterator<row_view> begin() const { return {{b, n, s}}; }
index_iterator<row_view> end() const { return begin()+m; }
std::size_t size() const { return m; }
bool empty() const { return size() == 0; }
explicit operator bool() const { return b; }
row_view operator[]( std::size_t i ) const { return begin()[i]; }
private:
T* b = nullptr;
M m = {};
Stride s = {};
N n = {};
};
template<std::size_t N>
using size = std::integral_constant<std::size_t, N>;
int main(){
std::vector<int> v {00,01,02,03, 10,11,12,13, 20,21,22,23, 30,31,32,33};
matrix_view<int, size<3>, size<4>> m = v.data()+5;
for (auto col:m) {
for (auto e:col) {
std::cout << e << ",";
}
std::cout << "\n";
}
}
and then clean it up with some CRTP DRY and EBO.
But that is just me.
Live example.
I try my best to code something in C++.When i use unsigned int and int to subtract, that's OK. However, using the unsigned short int and short int to subtract, i have a problem. So what i need to do in my code?
Thanks a lot.
Test value:
21758612232416725117133766166700 1758612232416725117155428849047
In the beginning, i have to define
*this > op2
absolutely.
template< typename T >
HugeInteger< T > HugeInteger< T >::operator-(const HugeInteger &op2)const // subtraction operator; HugeInteger - HugeInteger
{
int size = integer.getSize();
int op2Size = op2.integer.getSize();
int differenceSize = size;
HugeInteger < T > difference(differenceSize);
difference = *this;
Vector<T>::iterator it = difference.integer.begin();
int counter = 0;
for (Vector<T>::iterator i = difference.integer.begin(), j = op2.integer.begin(); j < op2.integer.end(); i++, j++) {
if ((*i - *j - counter) < 10) {
*i -= (*j + counter);
counter = 0;
}
else {
*i += 10;
*i -= (*j + counter);
counter = 1;
}
}
while (counter == 1) {
if ((*(it + op2Size) - counter) < 10) {
*(it + op2Size) -= counter;
counter = 0;
op2Size++;
}
else {
*(it + op2Size) += 10;
*(it + op2Size) -= counter;
counter = 1;
op2Size++;
}
}
if (*this == op2) {
HugeInteger<T> zero(1);
return zero;
}
for (Vector<T>::iterator i = difference.integer.end() - 1; i > difference.integer.begin(); i--) {
if (*i == 0) {
differenceSize--;
}
else {
break;
}
}
difference.integer.resize(differenceSize);
return difference;
}
There's not enough information in the code you posted to determine what is going wrong. I suspect it has something to do with how the "short" types are being converted to a HugeInt.
Below, I show a class definition for something very similar to HugeInt. It keeps track of a value's sign, but unfortunately, it only a few members are defined, enough to demonstrate subtraction.
This class has a nutty template conversion constructor. If none of the other constructors can handle a type, it will try to convert values with that type as if they were some kind of integer value, in a size-independent manner.
main() has two example subtraction operations, both involving a short value and a "huge" value.
#include <iostream>
#include <vector>
#include <string>
// radix-10 arbitrary size integer class
template<typename T>
class HugInt {
// integer digits are stored in a Vector container
// The example uses the class Vector, derived (statically)
// from std::vector<T> in order to mimic the class from
// code in the Question. Normally, I would just use a std::vector.
class Vector : public std::vector<T> { // virtual never needed
public:
int getSize() const {
return static_cast<int>(std::vector<T>::size());
} };
// two member variables
Vector integer;
int sign;
// For encapsulation and compactness, this class uses a lot
// of inline-friend functions. If considering using your own
// inline-friends, it must always be called passing at least one
// object from the class where the function is defined.
// Otherwise, the compiler cannot find it.
// compares just the magnitude (unsigned) parts of two HugInts
// returns a>b:1, a==b:0, a<b:-1
friend int cmpMagnitude(const HugInt& lh, const HugInt& rh) {
const int lh_size = lh.integer.getSize();
const int rh_size = rh.integer.getSize();
if(lh_size != rh_size) return lh_size > rh_size ? 1 : -1;
for(int i=lh_size-1; i+1; --i) {
if(lh.integer[i] != rh.integer[i]) {
return lh.integer[i] > rh.integer[i] ? 1 : -1;
} }
return 0;
}
// subtract the magnitude of op2 from the magnitude of *this
// does not take signs into account, but
// flips sign of *this if op2 has a greater magnitude than *this
void subMagnitude(const HugInt& op2) {
const int cm = cmpMagnitude(*this, op2);
if(cm == 0) {
// magnitudes are equal, so result is zero
integer.clear();
sign = 0;
return;
}
if(cm < 0) {
// If op2's magnitude is greater than this's
// subtract this's Magnitude from op2's,
// then set this to the negated result
HugInt temp{op2};
temp.subMagnitude(*this);
integer = temp.integer;
sign = -sign;
return;
}
// perform digit-wise Magnitude subtraction
// here, this's Magnitude is always greater or
// equal to op2's
T borrow = 0;
const int min_size = op2.integer.getSize();
int i;
for(i=0; i<min_size; ++i) {
const T s = op2.integer[i] + borrow;
if(borrow = (integer[i] < s)) {
integer[i] += T(10);
}
integer[i] -= s;
}
// propagate borrow to upper words (beyond op2's size)
// i is guaranteed to stay in bounds
while(borrow) {
if(borrow = (integer[i] < 1)) {
integer[i] += T(10);
}
--integer[i++];
}
// remove zeroes at end until a nonzero
// digit is encountered or the vector is empty
while(!integer.empty() && !integer.back()) {
integer.pop_back();
}
// if the vector is empty after removing zeroes,
// the object's value is 0, fixup the sign
if(integer.empty()) sign = 0;
}
void addMagnitude(const HugInt& op2) {
std::cout << "addMagnitude called but not implemented\n";
}
// get_sign generically gets a value's sign as an int
template <typename D>
static int get_sign(const D& x) { return int(x > 0) - (x < 0); }
public:
HugInt() : sign(0) {} // Default ctor
// Conversion ctor for template type
// Handles converting from any type not handled elsewhere
// Assumes D is some kind of integer type
// To be more correct, narrow the set of types this overload will handle,
// either by replacing with overloads for specific types,
// or use <type_traits> to restrict it to integer types.
template <typename D>
HugInt(D src) : sign(get_sign(src)) {
// if src is negative, make absolute value to store magnitude in Vector
if(sign < 0) src = D(0)-src; // subtract from zero prevents warning with unsigned D
// loop gets digits from least- to most-significant
// Repeat until src is zero: get the low digit, with src (mod 10)
// then divide src by 10 to shift all digits down one place.
while(src >= 1) {
integer.push_back(T(src % D(10)));
src /= D(10);
} }
// converting floating-point values will cause an error if used with the integer modulo
// operator (%). New overloads could use fmod. But for a shorter example, do something cheesy:
HugInt(double src) : HugInt(static_cast<long long>(src)) {}
HugInt(float src) : HugInt(static_cast<long long>(src)) {}
// conversion ctor from std::string
HugInt(const std::string& str) : sign(1) {
for(auto c : str) {
switch(c) {
// for simple, short parsing logic, a '-'
// found anywhere in the parsed value will
// negate the sign. If the '-' count is even,
// the result will be positive.
case '-': sign = -sign; break;
case '+': case ' ': case '\t': break; // '+', space and tab ignored
case '0': if(integer.empty()) break; // ignore leading zeroes or fallthrough
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
integer.insert(integer.begin(), T(c - '0'));
break;
} }
if(integer.empty()) sign = 0; // fix up zero value if no digits between '1' and '9' found
}
// conversion ctor from C-String (dispatches to std::string ctor)
HugInt(const char* str) : HugInt(std::string(str)) {}
// The default behavior, using value semantics to copy the
// two data members, is correct for our copy/move ctors/assigns
HugInt(const HugInt& src) = default;
HugInt& operator = (const HugInt& src) = default;
// some "C++11" compilers refuse to default the moves
// HugInt(HugInt&& src) = default;
// HugInt& operator = (HugInt&& src) = default;
// cmp(a, b) returns 1 if a>b, 0 if a==b or -1 if a<b
friend int cmp(const HugInt& lh, const HugInt& rh) {
if(lh.sign != rh.sign) return lh.sign > rh.sign ? 1 : -1;
const int cmpmag = cmpMagnitude(lh, rh);
return lh.sign < 0 ? -cmpmag : cmpmag;
}
friend bool operator == (const HugInt& lh, const HugInt& rh) {
return cmp(lh, rh) == 0;
}
friend bool operator != (const HugInt& lh, const HugInt& rh) {
return cmp(lh, rh) != 0;
}
friend bool operator > (const HugInt& lh, const HugInt& rh) {
return cmp(lh, rh) == 1;
}
friend bool operator < (const HugInt& lh, const HugInt& rh) {
return cmp(lh, rh) == -1;
}
friend bool operator >= (const HugInt& lh, const HugInt& rh) {
return cmp(lh, rh) != -1;
}
friend bool operator <= (const HugInt& lh, const HugInt& rh) {
return cmp(lh, rh) != 1;
}
// negate operator
HugInt operator - () const {
HugInt neg;
neg.integer = integer;
neg.sign = -sign;
return neg;
}
// subtract-assign operator
HugInt& operator -= (const HugInt &op2) {
if(op2.sign == 0) { // op2 is zero, do nothing
return *this;
}
if(sign == 0) { // *this is zero, set *this to negative op2
integer = op2.integer;
sign = -op2.sign;
return *this;
}
if(sign == op2.sign) { // same signs: use magnitude subtratction
subMagnitude(op2);
return *this;
}
// opposite signs here: needs magnitude addition (but not implemented)
addMagnitude(op2);
return *this;
}
friend HugInt operator - (const HugInt& lh, const HugInt& rh) {
// a - b uses the -= operator to avoid duplicate code
HugInt result{lh};
return result -= rh;
}
// overload stream output operator for HugInt values
friend std::ostream& operator << (std::ostream& os, const HugInt& hi) {
// assumes decimal output and class radix is 10
if(hi.integer.getSize() == 0) return os << '0';
if(hi.sign < 0) os << '-';
for(int i=hi.integer.getSize()-1; i+1; --i) {
os << char('0' + int(hi.integer[i]));
}
return os;
}
};
int main() {
using HugeInt = HugInt<char>;
{
HugeInt a = "21758612232416725117133766166700 1758612232416725117155428849047";
unsigned short b = 55427;
HugeInt c = a - b;
std::cout << a << " - " << b << " = \n" << c << '\n';
}
std::cout << '\n';
{
short a = 6521;
HugeInt b = 1234567;
HugeInt c = a - b;
std::cout << a << " - " << b << " = \n" << c << '\n';
}
}
Is there a nicer way to generate a list of points like than this? Libraries wise I'm open to any Eigen based method.
auto it = voxels.begin();
for(auto i = -180; i < 90; i++) {
for(auto j = -80; j < 70; j++) {
for(auto k = 20; k < 460; k++) {
*it = (Point3(i,j,k));
it++;
}
}
}
There's an immediate way to improve performance, by reserving enough space in the vector before you fill it with values.
There are many 'nicer' ways of doing it depending on what you think is nice.
Here's one way:
std::vector<Point3> populate()
{
// (arguable) maintainability benefit
constexpr auto I = axis_limits(-180, 90);
constexpr auto J = axis_limits(-80, 70);
constexpr auto K = axis_limits(20, 460);
// pre-reserve the space
std::vector<Point3> voxels;
voxels.reserve(volume(I, J, K));
// although it looks like it might be more work for the compiler, it gets optimised
// there is no loss of performance
for(i : I)
for(j : J)
for(k : J)
voxels.emplace_back(i, j, k);
return voxels;
}
Which will rely on the following infrastructure code:
struct Point3 {
Point3(int, int, int) {}
};
struct int_generator {
int_generator(int v)
: _v(v)
{}
int operator*() const {
return _v;
}
int_generator& operator++() {
++_v;
return *this;
}
bool operator!=(const int_generator& rhs) const {
return _v != rhs._v;
}
private:
int _v;
};
struct axis_limits : std::tuple<int, int>
{
using std::tuple<int, int>::tuple;
int_generator begin() const {
return std::get<0>(*this);
}
int_generator end() const {
return std::get<1>(*this);
}
};
constexpr int lower(const axis_limits& t)
{
return std::get<0>(t);
}
constexpr int upper(const axis_limits& t)
{
return std::get<1>(t);
}
int_generator begin(const axis_limits& t)
{
return std::get<0>(t);
}
int_generator end(const axis_limits& t)
{
return std::get<1>(t);
}
constexpr int volume(const axis_limits& x, const axis_limits& y, const axis_limits& z)
{
return (upper(x) - lower(x))
* (upper(y) - lower(y))
* (upper(z) - lower(z));
}
I am having trouble writing a function to rotate a circular array. I need to rotate it in place (no temp arrays) and I need to move around as few elements as possible. For background information the class "Quack" is just a queue mixed with a stack. So items can be pushed and popped off of both ends of the circular array. Here is what I have so far:
void Quack::rotate(int r)
{
front = (front + capacity + r) % capacity;
back = (back + capacity + r) % capacity;
}
front and back are ints that act as indexes for the array. r is the amount to rotate. capacity is the max size of the array.
The problem is if the array has "garbage" values in it, I end up rotating those into the array. For example lets say the ACTUAL array of chars is {a, b, c, d, e, f, g}, and front is 5 and back is 3. If I printed the circular array I would see {f, g, a, b, c, d}. Since front is 5 and back is 3, the index 4 is a "garbage" value (it got popped at some point). So my rotate function as it stands has a problem in that the index 4 gets "rotated in". If I rotate the array by 2, the ACTUAL array is still {a, b, c, d, e, f, g}, except now when I print it out since front and back are different I get {a, b, c, d, e, f}. What I want to see is {a, b, c, d, f, g}. My print function just prints from front to back (wrapping around as needed) so I need my rotate function to somehow eliminate the garbage value.
I think I need to move the back elements over so I have consecutive values without garbage in the middle. But I'm not sure how to do it.
So if the array isn't full you need to move some char's around. First you check if r is positive or negative. If it's negative you need to push the back over to be flush with the front for the number r or vise versa. example:
print out: c, b, a, z, f, g rotate 2
a z f g - c b
0 1 2 3 4 5 6
the c (items[5]) is in the front and g (items[3]) is back. If we just add r to both it will print garbage for the empty space. If r is 2, we want to copy c to items[4] and b to items[5]. Then items[0] should be the front and b now items[5] should be the back.
void Quack::rotate(int r)
{
if (nItems < capacity) { //if it's not full
if (r < 0) { // if r is negative
int r2 = r*(-1); //find absolute value
for (int i = 0; i < r2; i++) {
items[(back + 1 - i) % (capacity)] = items[(back - i < 0) ? capacity + back - i : back - i]; //push back the back chars up to the front r times
}
}
else {
for (int i = 0; i < r; i++){
items[(back + 1 + i)% capacity] = items[(front + i) % capacity];
}
}
}
front = ((front + r > 0) ? (front + r)%capacity : front + r + capacity); //if front + r is negative add capacity to it
back = (back + r) % capacity;
}
With a cyclic iterator and std::rotate:
#include <algorithm>
#include <iterator>
template <typename Iterator>
class cyclic_range
{
public:
typedef Iterator iterator;
cyclic_range(iterator first, iterator middle, iterator last)
: m_first(first), m_middle(middle), m_last(last)
{
if(m_middle == m_last) m_middle = m_first;
}
iterator first() const { return m_first; }
iterator middle() const { return m_middle; }
iterator last() const { return m_last; }
private:
iterator m_first;
iterator m_middle;
iterator m_last;
};
template <typename Iterator>
inline cyclic_range<Iterator>
make_cyclic_range(Iterator first, Iterator middle, Iterator last) {
return cyclic_range<Iterator>(first, middle, last);
}
/// A cyclic random access iterator operating on a iterator range [first, last).
/// If an iterator reaches the last (or is at last) position of the range the iterator
/// becomes equal to the first position of the range.
template <
typename RandomAccessIterator,
typename CyclicRange = cyclic_range<RandomAccessIterator> >
class cyclic_iterator
{
public:
typedef RandomAccessIterator inner_iterator;
typedef std::iterator_traits<inner_iterator> inner_iterator_traits;
typedef typename std::random_access_iterator_tag iterator_category;
typedef typename inner_iterator_traits::value_type value_type;
typedef typename inner_iterator_traits::difference_type difference_type;
typedef typename inner_iterator_traits::reference reference;
typedef typename inner_iterator_traits::pointer pointer;
typedef CyclicRange range_type;
public:
cyclic_iterator(inner_iterator pos, range_type range, bool at_end = false)
: m_pos(pos), m_range(range), m_at_end(at_end)
{
if(m_pos == range.last()) {
m_pos = range.first();
}
if(m_range.first() == m_range.last()) m_at_end = true;
}
const range_type& range() const { return m_range; }
/// True if the incremented or decremented iterator is at the middle of
/// the circular range.
bool at_end() const { return m_at_end; }
reference operator * () const noexcept {
return *m_pos;
}
pointer operator -> () const noexcept { return &*m_pos; }
cyclic_iterator& operator ++ () noexcept {
if(++m_pos == m_range.last()) m_pos = m_range.first();
m_at_end = (m_pos == m_range.middle());
return *this;
}
cyclic_iterator operator ++ (int) noexcept {
return ++cyclic_iterator(*this);
}
cyclic_iterator& operator += (difference_type n) noexcept {
if(n) {
if(n < 0) *this -= -n;
else {
n %= (m_range.last() - m_range.first());
difference_type avail = m_range.last() - m_pos;
if(n < avail) m_pos += n;
else {
m_pos = m_range.first();
n -= avail;
m_pos += n;
}
m_at_end = (m_pos == m_range.middle());
}
}
return *this;
}
cyclic_iterator operator + (difference_type n) const noexcept {
return cyclic_iterator(*this) += n;
}
cyclic_iterator& operator -- () noexcept {
if(m_pos == m_range.first()) m_pos = m_range.last();
--m_pos;
m_at_end = (m_pos == m_range.middle());
return *this;
}
cyclic_iterator operator -- (int) noexcept {
return --cyclic_iterator(*this);
}
cyclic_iterator& operator -= (difference_type n) noexcept {
if(n) {
if(n < 0) *this += -n;
else {
n %= (m_range.last() - m_range.first());
difference_type avail = m_pos - m_range.first();
if(avail < n) {
m_pos = m_range.last();
n -= avail;
}
m_pos -= n;
m_at_end = (m_pos == m_range.middle());
}
}
return *this;
}
cyclic_iterator operator - (difference_type n) const noexcept {
return cyclic_iterator(*this) -= n;
}
difference_type operator - (const cyclic_iterator& other) const noexcept {
return index() - other.index();
}
bool operator == (const cyclic_iterator& other) noexcept {
return (index() == other.index());
}
bool operator != (const cyclic_iterator& other) noexcept {
return ! (*this == other);
}
bool operator < (const cyclic_iterator& other) noexcept {
return index < other.index();
}
bool operator <= (const cyclic_iterator& other) noexcept {
return ! (other < this);
}
bool operator > (const cyclic_iterator& other) noexcept {
return (other < this);
}
bool operator >= (const cyclic_iterator& other) noexcept {
return ! (this < other);
}
private:
/// The index of the iterator position.
typedef std::size_t size_type;
size_type index() const noexcept {
size_type n = m_range.last() - m_range.first();
if( ! m_at_end) {
if(m_range.middle() <= m_pos) {
n = m_pos - m_range.middle();
}
else {
n = (m_pos - m_range.first()) + (m_range.last() - m_range.middle());
}
}
return n;
}
private:
inner_iterator m_pos;
range_type m_range;
bool m_at_end;
};
template <typename Iterator>
cyclic_iterator<Iterator> begin(const cyclic_range<Iterator>& range) {
return cyclic_iterator<Iterator>(range.middle(), range);
}
template <typename Iterator>
cyclic_iterator<Iterator> end(const cyclic_range<Iterator>& range) {
return cyclic_iterator<Iterator>(range.middle(), range, true);
}
// Test
// ====
#include <iostream>
#include <vector>
template <typename Iterator>
void print_cyclic_range(Iterator first, Iterator last) {
std::cout << "Cyclic Range: ";
for( ; first != last; ++first) {
std::cout << *first << ' ';
}
std::cout << '\n';
}
template <typename Iterator>
void print_range(Iterator first, Iterator last) {
std::cout << " Range: ";
for( ; first != last; ++first) {
std::cout << *first << ' ';
}
std::cout << '\n';
}
int main()
{
typedef cyclic_iterator<char*> cyclic_iterator;
char v[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g'};
print_range(v, v + sizeof(v));
// The cyclic range from 'f' to (including) 'e'
cyclic_iterator::range_type range(v, v + 5, v + sizeof(v));
// The cyclic iterator pointing to 'f'
cyclic_iterator first = begin(range);
// The cyclic iterator pointing to 'e'
cyclic_iterator last = end(range) - 1;
print_cyclic_range(first, last);
// Rotate the cyclic range from 'f' to (including) 'd', excluding 'e'
std::rotate(first, first + 2, last);
print_range(v, v + sizeof(v));
print_cyclic_range(first, last);
return 0;
}
Giving:
Range: a b c d e f g
Cyclic Range: f g a b c d
Range: c d f g e a b
Cyclic Range: a b c d f g