Overloading the * operator to multiply two polynomials - c++

Beginner at C++ here. I specifically need help trying to figure out what is wrong with my overloaded * operator which is supposed to multiply two polynomials of a class Poly I made. My other overloaded operators appear to work just fine. Here is the original question:
P(x) = 2x4 + 3x3 – 12x2 + x – 19 (4th order polynomial)
or
P(x) = 2x7 + 5x5 – 7x2 + x – 19 (7th order polynomial)
Where the coefficients for the first and second equations can be described by the following array of integers
'Coeff1[ ] = {-19, 1, -12, 3, 2}'
'Coeff2[[ ] = {-19, 1, -7, 0, 0, 5, 0, 2}'
Design and code a polynomial class in C++ that has the following properties:
class Poly{
private:
int order; //order of the polynomial
int *coeff; // pointer to array of coeff on the heap
// size of coeff array predicated on (order + 1)
public:
Poly( ); //default constructor – order=0 & coeff[0] =1
Poly(int Order , int Default = 1) ;// creates Nth order poly
// and inits all coeffs
Poly(int Order, int *Coeff); //creates an Nth polynomial & inits
~Poly( ); // destructor
::::::: // copy constructor
//mutators & accessors
void set( ){// Query user for coefficient values);
void set(int coeff[ ], int size); // input coeffs via external coeff vector
int getOrder( )const; // get order of polynomial
int * get( ); //returns pointer to coeff array
//overloaded operators
Poly operator+( const Poly &rhs); // add two polynomials
Poly operator-( const Poly &rhs); // subt two polynomials
Poly operator*( const int scale); // scale a polynomial
Poly operator*(const Poly &rhs); // mult two polynomials
bool operator==(const Poly &rhs); // equality operator
const int & operator[ ](int I)const; // return the Ith coefficient
int & operator[ ](int I); // return the Ith coefficient
int operator( )(int X); // evaluate P(x) according
Poly & operator=(const Poly & rhs);
friend ostream & operator<<(ostream & Out, const Poly &rhs);
//other member functions
};
Demonstrate the following operations for the following Polynomials:
P1(x) = 2x4 + 3x3 – 12x2 + x – 19 (4th order polynomial)
P2(x) = 2x7 + 7x5 – 6x2 + x – 19 (7th order polynomial)
//display the following results for the polynomials defined above
o P3 = P1 + P2;
o P3 = P2 – P1;
o P3 = P1*10;
o P3 = 10*P1;
o P3 = P1*P2;
o bool flag = (P1==P2);
o P1[3] = P2[5]; // assign the 5th coefficient of P2 to 3rd coefficient of P1
o int Z = P1(int X = 5); // evaluate Polynomial for input X
// suggest using Horner’s method
o The displayed polynomial for P2 should be printed as follows
2X^7 + 7X^5 – 6X^2 + 1X – 1
Heres my code so far:
#include <iostream>
#include <cmath>
using namespace std;
class Poly
{
private:
int order;
int *coeff;
public:
Poly();
Poly(int Order, int Default=1);
Poly(int Order, int *Coeff);
Poly(const Poly &copy);
~Poly();
void set(); //ask the user for the coefficient values
void set(int *Coeff, int size); //put the coefficient values in a external coeff vector
int getOrder() const; //gets the order of the polynomial
int* get() const; //returns pointer to coeff array
Poly operator +(const Poly &rhs);
Poly operator -(const Poly &rhs);
Poly operator *(const int scale);
Poly operator *(const Poly &rhs);
bool operator ==(const Poly &rhs);
const int & operator [](int access) const;
int & operator [](int access);
int operator ()(int X);
Poly & operator =(const Poly &rhs);
friend ostream & operator <<(ostream &Out, const Poly &rhs);
};
int main() {
int coeff1[] = {-19,1,-12,3,2};
int coeff2[] = {-19,1,-7,0,0,5,0,2};
Poly P1(4,coeff1);
Poly P2(7, coeff2);
Poly P3;
cout << "P1: " << P1 << endl;
cout << "P2: " << P2 << endl;
P3 = P1 * P2;
cout << "P1 * P2: " << P3 << endl;
return 0;
}
Poly::Poly() : order(0)
{
coeff = new int[1];
coeff[0] = 1;
}
Poly::Poly(int Order, int Default) : order(Order)
{
coeff = new int[order+1];
for (int i = 0; i < order+1; i++){
coeff[i] = Default;
}
}
Poly::Poly(int Order, int *Coeff) : order(Order), coeff(Coeff)
{
}
Poly::Poly(const Poly & copy)
{
order = copy.getOrder();
coeff = new int[order+1];
for (int i = 0; i < order+1; i++){
coeff[i] = copy.get()[i];
}
}
Poly::~Poly()
{
//if(coeff){
//delete [] coeff;
//}
}
void Poly::set()
{
cout << "Enter your coefficients:\n";
for (int i = 0; i < order+1; i++){
cin >> coeff[i];
}
}
void Poly::set(int *Coeff, int size)
{
delete [] coeff;
coeff = new int[size];
order = size;
for (int i = 0; i < order+1; i++){
coeff[i] = Coeff[i];
}
}
int Poly::getOrder() const
{
return order;
}
int* Poly::get() const
{
return coeff;
}
Poly Poly::operator +(const Poly &rhs)
{
int length = max(order+1, rhs.getOrder()+1);
int *answer = new int[length];
for (int i = 0; i < length + 1; i++){
answer[i] = coeff[i] + rhs.get()[i];
}
if (order > rhs.getOrder()){
for (int i = order+1 - rhs.getOrder()+1 ; i < order+1; i++){
answer[i] = coeff[i];
}
}
else if (order < rhs.getOrder()){
for (int i = rhs.getOrder()+1 - order+1; i < rhs.getOrder()+1; i++){
answer[i] = rhs.get()[i];
}
}
return Poly(length-1, answer);
}
Poly Poly::operator -(const Poly &rhs)
{
int length = max(order+1, rhs.getOrder()+1);
int *answer = new int[length];
for (int i = 0; i < order+1 && i < rhs.getOrder() + 1; i++){
answer[i] = coeff[i] - rhs.get()[i];
}
if (order > rhs.getOrder()){
for (int i = order+1-rhs.getOrder()+1; i < order+1; i++){
answer[i] = coeff[i];
}
}
else if (order < rhs.getOrder()){
for (int i = rhs.getOrder()+1 - order+1; i < rhs.getOrder()+1; i++){
answer[i] = 0 - rhs.get()[i];
}
}
return Poly(length-1, answer);
}
Poly Poly::operator *(const int scale)
{
int *answer = new int[order+1];
for (int i = 0; i < order+1; i++){
answer[i] = coeff[i] * scale;
}
return Poly(order, answer);
}
Poly Poly::operator *(const Poly &rhs)
{
int *shorter = NULL;
int *longer = NULL;
int s = 0;
int l = 0;
if(order < rhs.getOrder()){
shorter = coeff;
s = order;
longer = rhs.coeff;
l = rhs.order;
} else {
shorter = rhs.coeff;
s = rhs.order;
longer = coeff;
l = order;
}
Poly sum = Poly(l, longer) * shorter[0];
int *prod;
int nl;
for (int i = 1; i <= s; i++){
nl = l + i;
prod = new int[nl + 1];
for(int j = 0; j < i; j++){
prod[j] = 0;
}
for(int k = 0; k <= l; k++){
prod[k+i] = shorter[i] * longer[k];
}
sum = sum + Poly(nl, prod);
}
return sum;
}
bool Poly::operator ==(const Poly &rhs)
{
bool result;
if (order == rhs.order){
result = true;
for(int i = 0; i<order+1; i++){
if (coeff[i] != rhs.get()[i]){
result = false;
}
}
}else result = false;
return result;
}
const int& Poly::operator[](int access) const
{
return coeff[order + 1 - access];
}
int& Poly::operator [](int access)
{
return coeff[order + 1 - access];
}
int Poly::operator ()(int x)
{
int total = 0;
for(int i = 0; i < order + 1; i++){
total += coeff[i] * pow(x, i);
}
return total;
}
Poly &Poly::operator =(const Poly &rhs)
{
order = rhs.getOrder();
coeff = rhs.get();
return *this;
}
ostream& operator <<(ostream & Out, const Poly &rhs)
{
Out << rhs.get()[rhs.getOrder()] << "x^" << rhs.getOrder(); //first
for (int i = rhs.getOrder()-1; i > 0; i--){
if (rhs.get()[i] < 0 || rhs.get()[i] > 1) {
if(rhs.get()[i] > 0){
Out << " + ";
}
Out << rhs.get()[i] << "x^" << i << " ";
}else if (rhs.get()[i] == 1){
Out << "+ x ";
}else if (rhs.get()[i] == 1){
Out << "- x";
}
}
if (rhs.get()[rhs.getOrder() - rhs.getOrder()] > 0) {
Out << " + " << rhs.get()[rhs.getOrder() - rhs.getOrder()]; //last
}else Out << rhs.get()[rhs.getOrder() - rhs.getOrder()]; //last
Out << endl;
return Out;
}
`
Here is my current output. The answer I keep getting is half of the correct answer but I can't seem to get the first half.
P1: 2x^4 + 3x^3 -12x^2 + x -19
P2: 2x^7 + 5x^5 -7x^2 + x -19
P1 * P2: -114x^5 + 49x^4 -76x^3 + 362x^2 -38x^1 + 361
Any help is appreciated. Thank you

First, stop manually managing memory. Replace order and coeff with std::vector<int> values;. This bundles size() for order, and handles memory management for you.
If you don't know how to use std::vector yet, learn: it is far easier than learning how to write your own Poly class.
The next step in implementing Poly * Poly is to implement Poly& operator*=( Poly const& rhs );
The final step is friend Poly operator*( Poly lhs, Poly const& rhs ) { return std::move(lhs*=rhs); } There is little reason to use more than one line, and it can be inline.
That leaves operator*=.
The first step in implementing *= it so implement operator+(Poly const&, Poly const&), again via Poly& operator+=(Poly const&). As addition is easy, I will leave that to you.
The next step is scalar multiplication. Implement Poly& operator*=(int), and from it friend Poly operator*(Poly lhs, int x) { return std::move( lhs*=x ); } and friend Poly operator*(int x, Poly rhs) { return std::move( rhs*= x ); }. This is called 'scalar multiplication'.
Once we have those, *= becomes easy.
Store a copy of our initial value. (Poly init = std::move(*this);)
Create a return value (empty).
For each coefficient on the right hand side, do retval += coeff * init;
return *this = std::move(retval);
This is a sketch of the solution. To solve it really, you'll want to implement tests at each phase. Because I implemented *= in terms of other operations, testing each of those operations to make sure they work is key to having a debuggable *=. Then you test *=, then you test *, and then you are done.
If you are compiling in a compliant C++ compiler, a nice thing about using std::vector is that your default copy, move, assign and move-assign operations do the right thing, as does your default destructor. Seek to manage resources with specialized resource management classes, and follow The Rule of Zero, and you will have less pain.
Note that the above *= is not much easier to write than *, but in general *= is easier, so you should get into the habit anyhow.
Finally, note that this allocates more memory than is required, and is not optimal. It is, however, easy to get correct. After you have something like the above implemented, you can make it more optimal a number of ways. You can use karatsuba multiplication, you could use expression templates to avoid intermediate multiplication on the result += coeff * init; lines, you could reserve the right amount of space in result, or you could start playing with indexes manually.
The first step should be correctness, because if you have a correct algorithm you can at the very least use it to test your more optimal (trickier) algorithms.

Your code (for the polynomial multiplication) contains no comments and is rather opaque and hard to read/understand. So, I refuse to compile it (mentally) and can only guess, but it seems you don't know how multiplication of polynomials is defined, since your product polynomial is set to have order = min(order(A), order(B)) + 1, while correct is order(A)+order(B).
I suggest, you
1 make sure you understand polynomial multiplication before starting to code
2 write clear code with minimal instructions and useful comments (or better: useful variable names)
3 manage memory via the C++ standard library (using std::vector<>)
4 structure your code (write polynomial& polynomial::operator+=(polynomial const&) and then define the product as a standalone (can be a friend) via
polynomial operator*(polynomial const&a,polynomial const&b)
{
auto c=a;
c*=b;
return std::move(c);
}
though you may want to improve on this particular design (avoiding the re-allocation the is necessary in the above code in the c*=b operation).

I think this:
sum = sum + Poly(length, prod);
should be
sum = sum + Poly(length + i - 1, prod);
Also, the loop on i should stop at the shortest coeff array length.
Here's a modified version of the function:
Poly Poly::operator *(const Poly &rhs)
{
int *shorter = NULL;
int *longer = NULL;
int s = 0;
int l = 0;
if(order < rhs.order){
shorter = coeff;
s = order;
longer = rhs.coeff;
l = rhs.order;
} else {
shorter = rhs.coeff;
s = rhs.order;
longer = coeff;
l = order;
}
Poly sum = Poly(l, longer) * shorter[0];
int *prod;
int nl;
for (int i = 1; i <= s; i++){
nl = l + i;
prod = new int[nl + 1];
for(int j = 0; j < i; j++){
prod[j] = 0;
}
for(int k = 0; k <= l; k++){
prod[k+i] = shorter[i] * longer[k];
}
sum = sum + Poly(nl, prod);
}
return sum;
}
Note how it is based on order values rather than coeff array lengths (contrarily to the fix I indicated at the top of this answer).
If it doesn't work for you, then you may have other bugs in the code you didn't provide, or your algorithms work with array lengths, so you might have to adjust either to get things working.
Finally, as it has been said in other answers, you should use the tools provided by the standard library instead of handling array allocation by hand.

Related

Finding the total area and cover area of multiple polygon

I'm trying to solve this problem using the slicing technic.
But I just passed the first two test cases in this gym (Problem A)
2017-2018 ACM-ICPC East Central North America Regional Contest (ECNA 2017)
The whole step in my code looks like this:
calculate the total area using vector cross when inputting the polygon information.
find all the endpoints and intersection points, and record x value of them.
for each slice (sort x list and for each interval) find the lines from every polygon which crosses this interval and store this smaller segment.
sort segments.
for each trapezoid or triangle, calculate the area if this area is covered by some polygon.
sum them all to find the cover area.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<typename T> using p = pair<T, T>;
template<typename T> using vec = vector<T>;
template<typename T> using deq = deque<T>;
// #define dbg
#define yccc ios_base::sync_with_stdio(false), cin.tie(0)
#define al(a) a.begin(),a.end()
#define F first
#define S second
#define eb emplace_back
const int INF = 0x3f3f3f3f;
const ll llINF = 1e18;
const int MOD = 1e9+7;
const double eps = 1e-9;
const double PI = acos(-1);
double fcmp(double a, double b = 0, double eps = 1e-9) {
if (fabs(a-b) < eps) return 0;
return a - b;
}
template<typename T1, typename T2>
istream& operator>>(istream& in, pair<T1, T2>& a) { in >> a.F >> a.S; return in; }
template<typename T1, typename T2>
ostream& operator<<(ostream& out, pair<T1, T2> a) { out << a.F << ' ' << a.S; return out; }
struct Point {
double x, y;
Point() {}
Point(double x, double y) : x(x), y(y) {}
Point operator+(const Point& src) {
return Point(src.x + x, src.y + y);
}
Point operator-(const Point& src) {
return Point(x - src.x, y - src.y);
}
Point operator*(double src) {
return Point(x * src, y * src);
}
//* vector cross.
double operator^(Point src) {
return x * src.y - y * src.x;
}
};
struct Line {
Point sp, ep;
Line() {}
Line(Point sp, Point ep) : sp(sp), ep(ep) {}
//* check if two segment intersect.
bool is_intersect(Line src) {
if (fcmp(ori(src.sp) * ori(src.ep)) < 0 and fcmp(src.ori(sp) * src.ori(ep)) < 0) {
double t = ((src.ep - src.sp) ^ (sp - src.sp)) / ((ep - sp) ^ (src.ep - src.sp));
return fcmp(t) >= 0 and fcmp(t, 1) <= 0;
}
return false;
}
//* if two segment intersect, find the intersection point.
Point intersect(Line src) {
double t = ((src.ep - src.sp) ^ (sp - src.sp)) / ((ep - sp) ^ (src.ep - src.sp));
return sp + (ep - sp) * t;
}
double ori(Point src) {
return (ep - sp) ^ (src - sp);
}
bool operator<(Line src) const {
if (fcmp(sp.y, src.sp.y) != 0)
return sp.y < src.sp.y;
return ep.y < src.ep.y;
}
};
int next(int i, int n) {
return (i + 1) % n;
}
int main()
{
yccc;
int n;
cin >> n;
//* the point list and the line list of polygons.
vec<vec<Point>> p_list(n);
vec<vec<Line>> l_list(n);
//* x's set for all endpoints and intersection points
vec<double> x_list;
//* initializing point list and line list
double total = 0, cover = 0;
for (int i = 0; i < n; i++) {
int m;
cin >> m;
p_list[i].resize(m);
for (auto &k : p_list[i]) {
cin >> k.x >> k.y;
x_list.eb(k.x);
}
l_list[i].resize(m);
for (int k = 0; k < m; k++) {
l_list[i][k].sp = p_list[i][k];
l_list[i][k].ep = p_list[i][next(k, m)];
}
//* calculate the polygon area.
double tmp = 0;
for (int k = 0; k < m; k++) {
tmp += l_list[i][k].sp.x * l_list[i][k].ep.y - l_list[i][k].sp.y * l_list[i][k].ep.x;
}
total += abs(tmp);
}
//* find all intersection points
for (int i = 0; i < n; i++)
for (int k = i+1; k < n; k++) {
for (auto li : l_list[i])
for (auto lk : l_list[k])
if (li.is_intersect(lk)) {
x_list.eb(li.intersect(lk).x);
}
}
sort(al(x_list));
auto same = [](double a, double b) -> bool {
return fcmp(a, b) == 0;
};
x_list.resize(unique(al(x_list), same) - x_list.begin());
//* for each slicing, calculate the cover area.
for (int i = 0; i < x_list.size() - 1; i++) {
vec<pair<Line, int>> seg;
for (int k = 0; k < n; k++) {
for (auto line : l_list[k]) {
//* check if line crosses this slicing
if (fcmp(x_list[i], min(line.sp.x, line.ep.x)) >= 0 and fcmp(max(line.sp.x, line.ep.x), x_list[i+1]) >= 0) {
Point sub = line.ep - line.sp;
double t_sp = (x_list[i] - line.sp.x) / sub.x, t_ep = (x_list[i+1] - line.sp.x) / sub.x;
seg.eb(Line(Point(x_list[i], line.sp.y + sub.y * t_sp), Point(x_list[i+1], line.sp.y + sub.y * t_ep)), k);
}
}
}
//* sort this slicing
sort(al(seg));
deq<bool> inside(n);
int count = 0;
Line prev;
// cout << x_list[i] << ' ' << x_list[i+1] << endl;
//* calculate cover area in this slicing.
for (int k = 0; k < seg.size(); k++) {
if (count)
cover += ((seg[k].F.sp.y - prev.sp.y) + (seg[k].F.ep.y - prev.ep.y)) * (x_list[i+1] - x_list[i]);
prev = seg[k].F;
// cout << seg[k].S << ": (" << seg[k].F.sp.x << ", " << seg[k].F.sp.y << "), (" << seg[k].F.ep.x << ", " << seg[k].F.ep.y << ")" << endl;
inside[k] = !inside[k];
count += (inside[k] ? 1 : -1);
}
}
//* answer
cout << total / 2 << ' ' << cover / 2;
}
I can't not figure out which part I made a mistake :(

What algorithm can I use in this liner function question?

Firstly, I would like to apologise for my bad English.
when I submit the code below to DomJudge I got TimeLimit ERROR.
I can't think of ways to solve this question albeit I searched all over the internet and still couldn't find a solution.
Can someone give me a hint?
Question:
Here are N linear function fi(x) = aix + bi, where 1 ≤ i ≤ N。Define F(x) = maxifi(x). Please compute
the following equation for the input c[i], where 1 ≤ i ≤ m.
**Σ(i=1 to m) F(c[i])**
For example, given 4 linear function as follows. f1(x) = –x, f2 = x, f3 = –2x – 3, f4 = 2x – 3. And the
input is c[1] = 4, c[2] = –5, c[3] = –1, c[4] = 0, c[5] = 2. We have F(c[1]) = 5, F(c[2]) = 7, F(c[3])
= 1, F(c[4]) = 0, F(c[5]) = 2. Then,
**Σ(i=1 to 5)𝐹(𝑐[𝑖])
= 𝐹(𝑐[1]) + 𝐹(𝑐[2]) + 𝐹(𝑐[3]) + 𝐹(𝑐[4]) + 𝐹([5]) = 5 + 7 + 1 + 0 + 2 = 15**
Input Format:
The first line contains two positive integers N and m. The next N lines will contain two integers ai
and bi, and the last line will contain m integers c[1], c[2], c[3],…, c[m]. Each element separated by
a space.
Output Format:
Please output the value of the above function.
question image:https://i.stack.imgur.com/6HeaA.png
Sample Input:
4 5
-1 0
1 0
-2 -3
2 -3
4 -5 -1 0 2
Sample Output:
15
My Program
#include <iostream>
#include <vector>
struct L
{
int a;
int b;
};
int main()
{
int n{ 0 };
int m{ 0 };
while (std::cin >> n >> m)
{
//input
std::vector<L> arrL(n);
for (int iii{ 0 }; iii < n; ++iii)
{
std::cin >> arrL[iii].a >> arrL[iii].b;
}
//find max in every linear polymore
int answer{ 0 };
for (int iii{ 0 }; iii < m; ++iii)
{
int input{ 0 };
int max{ 0 };
std::cin >> input;
max = arrL[0].a * input + arrL[0].b;
for (int jjj{ 1 }; jjj < n; ++jjj)
{
int tmp{arrL[jjj].a * input + arrL[jjj].b };
if (tmp > max)max = tmp;
}
answer += max;
}
//output
std::cout << answer << '\n';
}
return 0;
}
Your solution is O(n*m).
A faster solution is obtained by iteratively determinating the "dominating segments", and the correspong crossing points, called "anchors" in the following.
Each anchor is linked to two segments, on its left and on its right.
The first step consists in sorting the lines according to the a values, and then adding each new line iteratively.
When adding line i, we know that this line is dominant for large input values, and must be added (even if it will be removed in the following steps).
We calculate the intersection of this line with the previous added line:
if the intersection value is higher than the rightmost anchor, then we add a new anchor corresponding to this new line
if the intersection value is lower than the rightmost anchor, then we know that we have to suppress this last anchor value. In this case, we iterate the process, calculating now the intersection with the right segment of the previous anchor.
Complexity is dominated by sorting: O(nlogn + mlogm). The anchor determination process is O(n).
When we have the anchors, then determining the rigtht segment for each input x value is O(n+ m). If needed, this last value could be further reduced with a binary search (not implemented).
Compared to first version of the code, a few errors have been corrected. These errors were concerning some corner cases, with some identical lines at the extreme left (i.e. lowest values of a). Besides, random sequences have been generated (more than 10^7), for comparaison of the results with those obtained by OP's code. No differences were found. It is likely that if some errors remain, they correspond to other unknown corner cases. The algorithm by itself looks quite valid.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
// lines of equation `y = ax + b`
struct line {
int a;
int b;
friend std::ostream& operator << (std::ostream& os, const line& coef) {
os << "(" << coef.a << ", " << coef.b << ")";
return os;
}
};
struct anchor {
double x;
int segment_left;
int segment_right;
friend std::ostream& operator << (std::ostream& os, const anchor& anc) {
os << "(" << anc.x << ", " << anc.segment_left << ", " << anc.segment_right << ")";
return os;
}
};
// intersection of two lines
double intersect (line& seg1, line& seg2) {
double x;
x = double (seg1.b - seg2.b) / (seg2.a - seg1.a);
return x;
}
long long int max_funct (std::vector<line>& lines, std::vector<int> absc) {
long long int sum = 0;
auto comp = [&] (line& x, line& y) {
if (x.a == y.a) return x.b < y.b;
return x.a < y.a;
};
std::sort (lines.begin(), lines.end(), comp);
std::sort (absc.begin(), absc.end());
// anchors and dominating segments determination
int n = lines.size();
std::vector<anchor> anchors (n+1);
int n_anchor = 1;
int l0 = 0;
while ((l0 < n-1) && (lines[l0].a == lines[l0+1].a)) l0++;
int l1 = l0 + 1;
if (l0 == n-1) {
anchors[0] = {0.0, l0, l0};
} else {
while ((l1 < n-1) && (lines[l1].a == lines[l1+1].a)) l1++;
double x = intersect(lines[l0], lines[l1]);
anchors[0] = {x, l0, l1};
for (int i = l1 + 1; i < n; ++i) {
if ((i != (n-1)) && lines[i].a == lines[i+1].a) continue;
double x = intersect(lines[anchors[n_anchor-1].segment_right], lines[i]);
if (x > anchors[n_anchor-1].x) {
anchors[n_anchor].x = x;
anchors[n_anchor].segment_left = anchors[n_anchor - 1].segment_right;
anchors[n_anchor].segment_right = i;
n_anchor++;
} else {
n_anchor--;
if (n_anchor == 0) {
x = intersect(lines[anchors[0].segment_left], lines[i]);
anchors[0] = {x, anchors[0].segment_left, i};
n_anchor = 1;
} else {
i--;
}
}
}
}
// sum calculation
int j = 0; // segment index (always increasing)
for (int x: absc) {
while (j < n_anchor && anchors[j].x < x) j++;
line seg;
if (j == 0) {
seg = lines[anchors[0].segment_left];
} else {
if (j == n_anchor) {
if (anchors[n_anchor-1].x < x) {
seg = lines[anchors[n_anchor-1].segment_right];
} else {
seg = lines[anchors[n_anchor-1].segment_left];
}
} else {
seg = lines[anchors[j-1].segment_right];
}
}
sum += seg.a * x + seg.b;
}
return sum;
}
int main() {
std::vector<line> lines = {{-1, 0}, {1, 0}, {-2, -3}, {2, -3}};
std::vector<int> x = {4, -5, -1, 0, 2};
long long int sum = max_funct (lines, x);
std::cout << "sum = " << sum << "\n";
lines = {{1,0}, {2, -12}, {3, 1}};
x = {-3, -1, 1, 5};
sum = max_funct (lines, x);
std::cout << "sum = " << sum << "\n";
}
One possible issue is the loss of information when calculating the double x corresponding to line intersections, and therefoe to anchors. Here is a version using Rational to avoid such loss.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
struct Rational {
int p, q;
Rational () {p = 0; q = 1;}
Rational (int x, int y) {
p = x;
q = y;
if (q < 0) {
q -= q;
p -= p;
}
}
Rational (int x) {
p = x;
q = 1;
}
friend std::ostream& operator << (std::ostream& os, const Rational& x) {
os << x.p << "/" << x.q;
return os;
}
friend bool operator< (const Rational& x1, const Rational& x2) {return x1.p*x2.q < x1.q*x2.p;}
friend bool operator> (const Rational& x1, const Rational& x2) {return x2 < x1;}
friend bool operator<= (const Rational& x1, const Rational& x2) {return !(x1 > x2);}
friend bool operator>= (const Rational& x1, const Rational& x2) {return !(x1 < x2);}
friend bool operator== (const Rational& x1, const Rational& x2) {return x1.p*x2.q == x1.q*x2.p;}
friend bool operator!= (const Rational& x1, const Rational& x2) {return !(x1 == x2);}
};
// lines of equation `y = ax + b`
struct line {
int a;
int b;
friend std::ostream& operator << (std::ostream& os, const line& coef) {
os << "(" << coef.a << ", " << coef.b << ")";
return os;
}
};
struct anchor {
Rational x;
int segment_left;
int segment_right;
friend std::ostream& operator << (std::ostream& os, const anchor& anc) {
os << "(" << anc.x << ", " << anc.segment_left << ", " << anc.segment_right << ")";
return os;
}
};
// intersection of two lines
Rational intersect (line& seg1, line& seg2) {
assert (seg2.a != seg1.a);
Rational x = {seg1.b - seg2.b, seg2.a - seg1.a};
return x;
}
long long int max_funct (std::vector<line>& lines, std::vector<int> absc) {
long long int sum = 0;
auto comp = [&] (line& x, line& y) {
if (x.a == y.a) return x.b < y.b;
return x.a < y.a;
};
std::sort (lines.begin(), lines.end(), comp);
std::sort (absc.begin(), absc.end());
// anchors and dominating segments determination
int n = lines.size();
std::vector<anchor> anchors (n+1);
int n_anchor = 1;
int l0 = 0;
while ((l0 < n-1) && (lines[l0].a == lines[l0+1].a)) l0++;
int l1 = l0 + 1;
if (l0 == n-1) {
anchors[0] = {0.0, l0, l0};
} else {
while ((l1 < n-1) && (lines[l1].a == lines[l1+1].a)) l1++;
Rational x = intersect(lines[l0], lines[l1]);
anchors[0] = {x, l0, l1};
for (int i = l1 + 1; i < n; ++i) {
if ((i != (n-1)) && lines[i].a == lines[i+1].a) continue;
Rational x = intersect(lines[anchors[n_anchor-1].segment_right], lines[i]);
if (x > anchors[n_anchor-1].x) {
anchors[n_anchor].x = x;
anchors[n_anchor].segment_left = anchors[n_anchor - 1].segment_right;
anchors[n_anchor].segment_right = i;
n_anchor++;
} else {
n_anchor--;
if (n_anchor == 0) {
x = intersect(lines[anchors[0].segment_left], lines[i]);
anchors[0] = {x, anchors[0].segment_left, i};
n_anchor = 1;
} else {
i--;
}
}
}
}
// sum calculation
int j = 0; // segment index (always increasing)
for (int x: absc) {
while (j < n_anchor && anchors[j].x < x) j++;
line seg;
if (j == 0) {
seg = lines[anchors[0].segment_left];
} else {
if (j == n_anchor) {
if (anchors[n_anchor-1].x < x) {
seg = lines[anchors[n_anchor-1].segment_right];
} else {
seg = lines[anchors[n_anchor-1].segment_left];
}
} else {
seg = lines[anchors[j-1].segment_right];
}
}
sum += seg.a * x + seg.b;
}
return sum;
}
long long int max_funct_op (const std::vector<line> &arrL, const std::vector<int> &x) {
long long int answer = 0;
int n = arrL.size();
int m = x.size();
for (int i = 0; i < m; ++i) {
int input = x[i];
int vmax = arrL[0].a * input + arrL[0].b;
for (int jjj = 1; jjj < n; ++jjj) {
int tmp = arrL[jjj].a * input + arrL[jjj].b;
if (tmp > vmax) vmax = tmp;
}
answer += vmax;
}
return answer;
}
int main() {
long long int sum, sum_op;
std::vector<line> lines = {{-1, 0}, {1, 0}, {-2, -3}, {2, -3}};
std::vector<int> x = {4, -5, -1, 0, 2};
sum_op = max_funct_op (lines, x);
sum = max_funct (lines, x);
std::cout << "sum = " << sum << " sum_op = " << sum_op << "\n";
}
To reduce the time complexity from O(n*m) to something near O(nlogn), we need to order the input data in some way.
The m points where the target function is sampled can be easily sorted using std::sort, which has an O(mlogm) complexity in terms of comparisons.
Then, instead of searching the max between all the lines for each point, we can take advantage of a divide-and-conquer technique.
Some considerations can be made in order to create such an algorithm.
If there are no lines or no sample points, the answer is 0.
If there is only one line, we can evaluate it at each point, accumulating the values and return the result. In case of two lines we could easily accumulate the max between two values. Searching for the intersection and then separating the intervals to accumulate only the correct value may be more complicated, with multiple corner cases and overflow issues.
A recursive function accepting a list of lines, points and two special lines left and right, may start by calculating the middle point in the set of points. Then it could find the two lines (or the only one) that have the greater value at that point. One of them also have the greatest slope between all the ones passing for that maximum point, that would be the top "right". The other one, the top "left" (which may be the same one), have the least slope.
We can partition all the remaining lines in three sets.
All the lines having a greater slope than the "top right" one (but lower intercept). Those are the ones that we need to evaluate the sum for the subset of points at the right of the middle point.
All the lines having a lower slope than the "top left" one (but lower intercept). Those are the ones that we need to evaluate the sum for the subset of points at the left of the middle point.
The remaining lines, that won't partecipate anymore and can be removed. Note this includes both "top right" and "top left".
Having splitted both the points and the lines, we can recurively call the same function passing those subsets, along with the previous left line and "top left" as left and right to the left, and the "top right" line with the previous right as left and right to the right.
The return value of this function is the sum of the value at the middle point plus the return values of the two recursive calls.
To start the procedure, we don't need to evaluate the correct left and right at the extreme points, we can use an helper function as entry point which sorts the points and calls the recursive function passing all the lines, the points and two dummy values (the lowest possible line, y = 0 + std::numeric_limits<T>::min()).
The following is a possible implementation:
#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
#include <limits>
struct Line
{
using value_type = long;
using result_type = long long;
value_type slope;
value_type intercept;
auto operator() (value_type x) const noexcept {
return static_cast<result_type>(x) * slope + intercept;
}
static constexpr Line min() noexcept {
return { 0, std::numeric_limits<value_type>::min()};
}
};
auto result_less_at(Line::value_type x)
{
return [x] (Line const& a, Line const& b) { return a(x) < b(x); };
}
auto slope_less_than(Line::value_type slope)
{
return [slope] (Line const& line) { return line.slope < slope; };
}
auto slope_greater_than(Line::value_type slope)
{
return [slope] (Line const& line) { return slope < line.slope; };
}
auto accumulate_results(Line const& line)
{
return [line] (Line::result_type acc, Line::value_type x) {
return acc + line(x);
};
}
struct find_max_lines_result_t
{
Line::result_type y_max;
Line left, right;
};
template< class LineIt, class XType >
auto find_max_lines( LineIt first_line, LineIt last_line
, Line left, Line right
, XType x )
{
auto result{ [left, right] (const auto max_left, const auto max_right)
-> find_max_lines_result_t {
if ( max_left < max_right )
return { max_right, right, right };
else if ( max_right < max_left )
return { max_left, left, left };
else
return { max_left, left, right };
}(left(x), right(x))
};
std::for_each( first_line, last_line
, [x, &result] (Line const& line) mutable {
auto const y{ line(x) };
if ( y == result.y_max ) {
if ( result.right.slope < line.slope )
result.right = line;
if ( line.slope < result.left.slope )
result.left = line;
}
else if ( result.y_max < y ) {
result = {y, line, line};
}
} );
return result;
}
template< class SampleIt >
auto sum_left_right_values( SampleIt const first_x, SampleIt const last_x
, Line const left, Line const right )
{
return std::accumulate( first_x, last_x, Line::result_type{},
[left, right] (Line::result_type acc, Line::value_type x) {
return acc + std::max(left(x), right(x)); } );
}
template< class LineIt, class XType >
auto find_max_result( LineIt const first_line, LineIt const last_line
, Line const left, Line const right
, XType const x )
{
auto const y_max{ std::max(left(x), right(x)) };
LineIt const max_line{ std::max_element(first_line, last_line, result_less_at(x)) };
return max_line == last_line ? y_max : std::max(y_max, (*max_line)(x));
}
template <class LineIt, class SampleIt>
auto sum_lines_max_impl( LineIt const first_line, LineIt const last_line,
SampleIt const first_x, SampleIt const last_x,
Line const left, Line const right )
{
if ( first_x == last_x ) {
return Line::result_type{};
}
if ( first_x + 1 == last_x ) {
return find_max_result(first_line, last_line, left, right, *first_x);
}
if ( first_line == last_line ) {
return sum_left_right_values(first_x, last_x, left, right);
}
auto const mid_x{ first_x + (last_x - first_x - 1) / 2 };
auto const top{ find_max_lines(first_line, last_line, left, right, *mid_x) };
auto const right_begin{ std::partition( first_line, last_line
, slope_less_than(top.left.slope) ) };
auto const right_end{ std::partition( right_begin, last_line
, slope_greater_than(top.right.slope) ) };
return top.y_max + sum_lines_max_impl( first_line, right_begin
, first_x, mid_x
, left, top.left )
+ sum_lines_max_impl( right_begin, right_end
, mid_x + 1, last_x
, top.right, right );
}
template <class LineIt, class SampleIt>
auto sum_lines_max( LineIt first_line, LineIt last_line
, SampleIt first_sample, SampleIt last_sample )
{
if ( first_line == last_line )
return Line::result_type{};
std::sort(first_sample, last_sample);
return sum_lines_max_impl( first_line, last_line
, first_sample, last_sample
, Line::min(), Line::min() );
}
int main()
{
std::vector<Line> lines{ {-1, 0}, {1, 0}, {-2, -3}, {2, -3} };
std::vector<long> points{ 4, -5, -1, 0, 2 };
std::cout << sum_lines_max( lines.begin(), lines.end()
, points.begin(), points.end() ) << '\n';
}
Testable here.

Trying to add two vectors but it is adding in the wrong order

In this function i'm working on the goal is to add the coefficients of polynomials, the coefficients are stored in vectors. P is a private member of the class Polynom that I have made. "RHS" is not a member of the class - it is another instance of the class, so I can still access all of its private members, like RHS.P[i]. This is the code that I have so far.
`
Polynom Polynom::operator+(const Polynom& RHS) cons
vector <int> temp;
vector <int> temp2;
vector <int> temp3;
for (int i = 0; i <= P.size()-1; i ++)
{
temp.push_back(P[i]);
}
for (int i = 0; i <= RHS.P.size()-1; i ++)
{
temp2.push_back(RHS.P[i]);
}
int largerPoly = P.size()-1;
for (int i = 0; i <= P.size()-1; i++)
{
if(largerPoly == RHS.P.size()-1)
{
temp3.push_back(temp2[largerPoly - i]);
}
else
{
temp3.push_back(temp[i]);
}
largerPoly --;
}
return Polynom(temp3);
`
So for example if I input in my P vector: (4)(2)(-1)(2)(0)(0)(2)
And in the other vector: (-4)(0)(1)
The resulting vector should be: (4)(2)(-1)(2)(-4)(0)(3) (1+2)=3 (0+-4)=-4
Which basically means I want to add the vector from the back (hopefully that makes sense)
unfortunately that's not the output i'm getting with this code. Any tips on what I am missing?
Make it easier and simply split the two cases:
Polynom Polynom::operator+(const Polynom& arg) const
{
const auto &lhs = this->P; // define some shorthand refs
const auto &rhs = RHS.P;
std::vector<int> res;
// case 1: lhs is larger
if (lhs.size() > rhs.size()) {
res.assign(lhs.begin(), lhs.end()); // copy lhs into res
auto offset = lhs.size() - rhs.size();
for (auto i = 0; i < rhs.size(); i++) {
res[i + offset] += rhs[i];
}
}
// case 2: rhs is larger
else {
res.assign(rhs.begin(), rhs.end()); // copy lhs into res
auto offset = rhs.size() - lhs.size();
for (auto i = 0; i < lhs.size(); i++) {
res[i + offset] += lhs[i];
}
}
return Polynom(res);
}
Using references also means, that we do not have to copy the whole data in several local variables.
Store your coefficients in the reverse order.
x^3 + x + 1 == 1 + x + x^3 <=> [1, 1, 0, 1]
And now all your terms will always line up and the coefficient of x^n is at index n.

overloading operators '+' and '=' C++

I've recently started learning C++, right now I'm working on a Matrix Class. I'm trying to overload operators and it turned out to be more difficult than I thought. So I've overloaded '=' and '+', first one works perfectly fine when I just want to set one matrix equal to another, but when I do something like 'matrix = matrix1 + matrix2' it crashes with no error. I'd be very thankful if someone helps me. Here's my code:
class Matrix
{
private:
int lines , columns;
int *Matrix_Numbers;
public:
Matrix();
Matrix(int n , int m)
{
lines = n , columns = m;
Matrix_Numbers = new int[lines * columns];
}
Matrix & operator = (Matrix &mat);
Matrix & operator + (Matrix &mat);
~Matrix()
{
delete Matrix_Numbers;
}
};
Matrix & Matrix::operator = (Matrix &mat)
{
this -> lines = mat.lines;
this -> columns = mat.columns;
int i , j;
for(i = 0 ; i < lines ; i++)
{
for(j = 0 ; j < columns ; j++)
{
this -> Matrix_Numbers[i * (this -> columns) + j] = mat(i , j);
}
}
return *this;
}
Matrix & Matrix::operator + (Matrix &mat)
{
Matrix result(lines , columns);
if(mat.lines == lines && mat.columns == columns)
{
int i , j;
for(i = 0 ; i < lines ; i++)
{
for(j = 0 ; j < columns ; j++)
{
result.Matrix_Numbers[i * columns + j] = Matrix_Numbers[i *
columns + j] + mat(i , j);
}
}
}
else
{
cout << "Error" << endl;
}
return result;
}
Of course it's just a part of my code, there's more, but I thought that this is the broken part. Let me know if you need more information:)
Your operator+ method returns a reference to the result. The only problem is that result is a local variable which means it gets destroyed upon the method returning. You should return it by value instead and let the compiler optimize stuff.
Like others pointed out in the comments, you should use const whenever possible so your operator+ can actually be called with constant parameters.

Multiply two int arrays

I have a type BigInt which stores large numbers as an array of digits (0-9) in a char array called privately m_digitArray.
I am overloading arithmetic and relational operators to help in development. However, I could not get the multiplicative operator *= to work for me. The code I posted works for single digit operations in int * BigInt only while I'd prefer it work for any length number and for all int * BigInt, BigInt * int, and especially BigInt * BigInt operations. Like it works for 6 * bigInt (with a value of 6) = 36; but not 11 * bigInt (with a value of 10).
BigInt.cpp
Overloaded operator in question
BigInt BigInt::operator *= (const BigInt &rhs){
int size = m_digitArraySize + rhs.getSize();
int* C = new int[size];
int s = size-1;
for(int j= rhs.getSize() - 1; j >= 0; j--){
int carry = 0;
int shift = s;
for(int i = m_digitArraySize - 1; i >= 0; i--){
int m = getDigit(i) * rhs.getDigit(j);
int sum = m + C[shift] + carry;
int num = sum % 10;
int c = sum/10;
C[shift] = num;
carry = c;
shift--;
}
C[shift]= C[shift] + carry;
s--;
}
reallocateArray(size);
// for(int i = 0; i < size < ++i){
// m_digitArray[i] = '0' + C[i];
// }
// Nothing being returned, printing to debug
for (int i = 0; i < size; ++i)
{
cout << C[i];
}
return *this;
}
// Overload the * operator for BigInt * BigInt operations
BigInt operator * (const BigInt &lhs, const BigInt &rhs){
return BigInt(lhs) *= rhs;
}
// Overload the * operator for BigInt * int operations
BigInt operator * (const BigInt &lhs, int num){
return BigInt(lhs) *= num;
}
// Overload the * operator for int * BigInt operations
BigInt operator * (int num, const BigInt &rhs){
return BigInt(rhs) *= num;
}
You have an error in the logic in that you're coding operator * as something that implements operator *= to do it's work. Your problem is that calling:
x = y * z
shouldn't change the value of "y". That's an unwanted side-effect. But if you define operator* for your BigInt as using *= to get the result, that's exactly what it would do. Also if you do that, then calling
x = z * y
will cause different behaviour to "x = y * z", because now z is changed instead of y, which violates basic commutative laws of mathematics.
Start with operator* and operator=, then construct operator *= by chaining together calls to those.
operator* should create a new BigInt, then multiply the two input BigInts (passed as "const BigInt&"), then return the newly-created BigInt. To optimize this, you look into move constructors. but it's not necessary.
operator= is your copy assignment function, it should be later built to use move semantics, but that's also not critical
Then after that you can use *= to combine the two other functions, by merely writing something simple such as:
BigInt BigInt::operator*=(const BigInt &rhs)
{
(*this) = (*this) * rhs;
return (*this);
}
Well I was able to figure it out after some help. Here's the solution to the problem:
BigInt BigInt::operator *= (const BigInt &rhs){
// Create new BigInt to make changes non-destructively
BigInt numbers;
// A safe capacity size for the new BigInt
int size = m_digitArraySize + rhs.getSize();
// If either number is negative, set self to negative
if(!m_isPositive || !rhs.isPositive())
numbers.initializeArray(size, false);
else
numbers.initializeArray(size, true);
// Go through the multiplier
for(int i = 0; i < rhs.getSize(); ++i){
int carry = 0;
// Go through the multiplicand
for(int j = 0; j < m_digitArraySize; ++j){
// The product of multiplicand and multiplier plus the sum of the previous digits and the carry
int product = (getDigit(j) * rhs.getDigit(i)) + numbers.getDigit(i + j) + carry;
// Reset carry, necessary if the product is just a digit
carry = 0;
// Set carry to the tens digit
carry = product / 10;
// Set product to the units digit
product = product % 10;
// Save to the new BigInt
numbers.setDigit(i +j, product);
}
// Inner loop cuts off near the end, continue the loop if there is a carry
int nextDigit = i + m_digitArraySize;
while(carry!=0){
int new_value = numbers.getDigit(nextDigit) + carry;
carry = 0;
carry = new_value / 10;
new_value = new_value % 10;
numbers.setDigit(nextDigit, new_value);
++nextDigit;
}
}
// Remove excess zeros
numbers.normalizeArray();
*this = numbers;
return *this;
}