I am trying to add two polynomials in C++ and I'm lost as to where to even start. So the user can enter values for a polynomial, they do not need to be in order or anything.
For example it can be:
Poly 1: 2x^5 + 5x^2 - 2x + 9
Poly 2: x^2 + 0
I have coefficient and exponent stored in the class (objects) private fields. So would I look at the first exponent in Poly 1, search Poly 2 for same exponent first and if found add them? Then go on to the second term?
Code as requested: (NOTE: The implementation is currently wrong and I need help on how to work through this problem.)
#include <cmath>
#include <iostream>
using namespace std;
class polynomial
{
public:
polynomial();
polynomial(int);
polynomial(int exponent[], int coefficient[], int);
~polynomial();
polynomial &operator = (const polynomial &obj);
int evaluate(double uservalue);
polynomial operator+(const polynomial &obj) const;
void operator-(const polynomial &obj) const;
void operator*(const polynomial &obj) const;
friend istream & operator>> (istream & in, polynomial &obj);
friend ostream & operator<< (ostream & out, const polynomial &obj);
friend void growone(polynomial &obj);
private:
int *coefficient;
int *exponent;
int size;
};
And the implementation
polynomial polynomial::operator+(const polynomial &obj) const
{
bool matchFound = false;
polynomial tmp;
if (size >= obj.size) {
for (int i = 0; i < size; i++) {
if (i >= tmp.size) {
growone(tmp);
}
for(int y = 0; i < obj.size; i++) {
if (exponent[i] == obj.exponent[y]) {
tmp.coefficient[i] = (coefficient[i]+obj.coefficient[y]);
tmp.exponent[i] = exponent[i];
tmp.size++;
matchFound = true;
}
}
if (matchFound == false) {
tmp.coefficient[i] = coefficient[i];
tmp.exponent[i] = exponent[i];
tmp.size++;
}
matchFound = false;
}
} else {
}
return tmp;
}
You're not really using the power of C++ to its fullest there. A good rule is that, if you are using non-smart pointers for anything, you should step back and have a rethink.
It's no accident that a large number of questions about C on Stack Overflow have to do about problems with pointers :-)
The other point I would add is that it may be worth actually wasting a small amount of memory to greatly simplify your code. By that, I mean don't try to create sparse arrays to hold your terms (coefficient-exponent pairs). Instead, allow each expression to hold every term up to its maximum, with the coefficients for the unused ones simply set to zero. Unless you have an expression like 4x99999999999999 + 3, the amount of extra memory taken may be worth it.
To that end, I'd propose using a std::vector for just the coefficients starting at an exponent of zero. The exponents are actually decided by the position within the vector. So the expression 4x9 - 17x3 + 3 would be stored as the vector:
{3, 0, 0, -17, 0, 0, 0, 0, 0, 4}
0 <------- exponent -------> 9
That actually makes the task of adding and subtracting polynomials incredibly easy since the coefficients are all nicely lined up.
So, with that in mind, let's introduce a cut-down class for showing how it's done:
#include <iostream>
#include <vector>
using std::cout;
using std::vector;
using std::ostream;
class Polynomial {
public:
Polynomial();
Polynomial(size_t expon[], int coeff[], size_t sz);
~Polynomial();
Polynomial &operator=(const Polynomial &poly);
Polynomial operator+(const Polynomial &poly) const;
friend ostream &operator<<(ostream &os, const Polynomial &poly);
private:
std::vector<int> m_coeff;
};
The default constructor (and the destructor) are very simple, we just ensure that an initialised polynomial always has at least one term:
Polynomial::Polynomial() { m_coeff.push_back(0); }
Polynomial::~Polynomial() {}
The constructor-from-array is a little more complex because we want to, as early as possible, turn the user's "anything goes" format into something we can use easily:
Polynomial::Polynomial(size_t expon[], int coeff[], size_t sz) {
// Work out largest exponent and size vector accordingly.
auto maxExpon = 0;
for (size_t i = 0; i < sz; ++i) {
if (expon[i] > maxExpon) {
maxExpon = expon[i];
}
}
m_coeff.resize(maxExpon + 1, 0);
// Fill in coefficients.
for (size_t i = 0; i < sz; ++i) {
m_coeff[expon[i]] = coeff[i];
}
}
Now you'll see why we made the decision to not use sparse arrays and to place the zero exponent at the start of the vector. Bothe operator= and operator+ are simple because they already know where all terms are:
Polynomial &Polynomial::operator=(const Polynomial &poly) {
if (this != &poly) {
m_coeff.clear();
for (int coeff: poly.m_coeff) {
m_coeff.push_back(coeff);
}
}
return *this;
}
Polynomial Polynomial::operator+(const Polynomial &poly) const {
// Create sum with required size.
size_t thisSize = this->m_coeff.size();
size_t polySize = poly.m_coeff.size();
Polynomial sum;
if (thisSize > polySize) {
sum.m_coeff.resize(thisSize, 0);
} else {
sum.m_coeff.resize(polySize, 0);
}
// Do the actual sum (ignoring terms beyond each limit).
for (size_t idx = 0; idx < sum.m_coeff.size(); ++idx) {
if (idx < thisSize) sum.m_coeff[idx] += this->m_coeff[idx];
if (idx < polySize) sum.m_coeff[idx] += poly.m_coeff[idx];
}
return sum;
}
Now we just need to complete this with an output function and a small test mainline:
ostream &operator<< (ostream &os, const Polynomial &poly) {
bool firstTerm = true;
if (poly.m_coeff.size() == 1 && poly.m_coeff[0] == 0) {
os << "0";
return os;
}
for (size_t idx = poly.m_coeff.size(); idx > 0; --idx) {
if (poly.m_coeff[idx - 1] != 0) {
if (firstTerm) {
os << poly.m_coeff[idx - 1];
} else if (poly.m_coeff[idx - 1] == 1) {
os << " + ";
if (idx == 1) {
os << poly.m_coeff[idx - 1];
}
} else if (poly.m_coeff[idx - 1] == -1) {
os << " - ";
} else if (poly.m_coeff[idx - 1] < 0) {
os << " - " << -poly.m_coeff[idx - 1];
} else {
os << " + " << poly.m_coeff[idx - 1];
}
if (idx > 1) {
os << "x";
if (idx > 2) {
os << "^" << idx - 1;
}
}
firstTerm = false;
}
}
return os;
}
int main() {
int c1[] = {1, 2, 3, 4, 5};
size_t e1[] = {3, 1, 4, 0, 9};
Polynomial p1(e1, c1, (size_t)5);
cout << "Polynomial 1 is " << p1 << " (p1)\n";
int c2[] = {6, 7, 8};
size_t e2[] = {3, 7, 9};
Polynomial p2(e2, c2, (size_t)3);
cout << "Polynomial 2 is " << p2 << " (p2)\n";
Polynomial p3 = p1 + p2;
cout << "Polynomial 3 is " << p3 << " (p3 = p1 = p2);
}
And the output, which I've slightly reformatted to show like terms, shows it in action:
Polynomial 1 is 5x^9 + 3x^4 + x^3 + 2x + 4
Polynomial 2 is 8x^9 + 7x^7 + 6x^3
===================================
Polynomial 3 is 13x^9 + 7x^7 + 3x^4 + 7x^3 + 2x + 4
Related
Intro:
I have a homework assignment to create a type for "ints larger than existing types can store."
We should store the numbers in an array of digits(backward for easier math logic).
I'm using a dynamic array to store the info in the object.
I am required to overload at least the +, -, * , <, >, << and >> operators.
Also .cpp and .h files must be separate.
Problem:
Not too sure how to overload the >> operator based on the class attributes and manipulation needed.
BigIntegers.h
#include <string>
#include <iostream>
typedef int* BigIntPtr;
class BigIntegers {
private:
int size; // based on string size, if neg string size -1
BigIntPtr number; // dynamic array ptr
bool isNeg; // set default to false, assumes a positive number
public:
explicit BigIntegers(std::string num = "");
BigIntegers(const BigIntegers &bi);
~BigIntegers();
friend std::istream &operator>>(std::istream &is, BigIntegers &bi) {
/**
* using eg "is >> bi.data;" doesn't seem viable given the data manipulation needed
* see constructor
*/
std::string input;
getline(is,input);
bi = BigIntegers(input);
return is;
}
friend std::ostream &operator<<(std::ostream &os, const BigIntegers &bi) {
if(bi.isNeg) //add sign if needed
os << '-';
for(int s=bi.size-1;s>-1;s--) //print reverse
{
os << bi.number[s];
}
return os;
}
};
BigIntegers.cpp
#include <algorithm>
#include "BigIntegers.h"
BigIntegers::BigIntegers(std::string num) {
//if null
if(num.empty())
{
size = 0;
number = NULL;
isNeg = 0;
return;
}
//determine if its negative
if (num.find('-') == 0)
{
num.erase(remove(num.begin(),num.end(), '-'),num.end());
isNeg =true;
}else {isNeg= false;}
size = num.length();
number = new int[size];
//add array backwards for math optimization
std::string rev; rev.assign(num.rbegin(),num.rend());
for(int i = 0; i < size; i++)
{
number[i]=rev[i]-'0';
}
}
BigIntegers::~BigIntegers() {
delete [] number;
size =0;
isNeg =0;
}
#include <iostream>
#include "BigIntegers.h"
using std::cout;
using std::cin;
using std::string;
int main() {
//basic functionality test
string stringInt = "123456";
string stringIntNeg = "-99987654321";
BigIntegers test1(stringInt);
cout << test1 << "\n";
BigIntegers test2(stringIntNeg);
cout << test2 << "\n";
//iostream test
cout << "Enter a big integer in the form 123456 or -123456.\n";
BigIntegers test3;
cin >> test3;
cout << test3 << "\n";
return 0;
}
output
pr4_bigIntegers\cmake-build-debug\pr4_bigIntegers.exe
123456
-12345678987654321
Enter a big integer in the form 123456 or -123456.
5789256
-57883070081-2144186072
Process finished with exit code 0
Note:
Additionally, sometimes the output is almost correct but negative or some other garbage values are included. eg) cin >> 5314 , cout <<-5314
edit - I've realized that after 4 digits the garbage is introduced. The experimentation continues.
Assignment Instructions - (for additional context, this is a direct copy/paste)
The existing types of integers in C++ cannot store very large integers. We need a new type that can store these large integers we possibly need in dealing with scientific problems.
You can represent an integer by storing the integer as an array of digits.
Design and implement a class for integer arithmetic in which a number is implemented as an array of digits. Each entry of the array will be a digit from 0 to 9 (inclusive).
The number represented is the concatenation of the digits in the array.
You are required to overload at least the +, -, * , <, >, << and >> operators for this class. Try to overload the division operator /.
Do not forget to implement the gang of three: assignment operator, copy constructor and destructor.
Your division operator is an integer operator so that it returns the integer part of the quotient. You need to understand that the purpose of this class is to store large integers so you should not convert your array representation into regular integer representation during the process of overloading these operators. Again, we assume that these integers cannot be handled by using the build-in integer types so your explicit constructor should have a string type parameter, not an integer type parameter, and get each character from the string, convert it to a digit and store it to your array. To perform operations easily, you may want to store an integer in reversed order in your array.
Use dynamic array to store your integer.
Include professional documentation of your code and proper indentation
Separate your header file from implementation file
Test every aspect of your class.
Email clarification from teacher
Just answer a couple of questions from some of you.
The integers are signed because when you do your subtraction you may get a negative integer. So use the first spot of the array to store 0 or 1 (0 for negative and 1 for positive).
The instructions do not allow you to convert the string parameter to an integer. I mean that you should not convert string s="123456" to int n=123456. But, you have to convert character 1 into integer 1, ..., character 6 into integer 6 and store each into your array.
Your overloaded >> operator seems to be correct.
Your second problem: The minus sign is no garbage.
bool isNeg; // set default to false, assumes a positive number
You never set it to false. I debugged your code, and the solution is simple:
BigIntegers::BigIntegers(std::string num) : isNeg(false) {
//your constructor stuff
}
I suggest using a dynamic array of type unsigned short instead.
Saving each digit in an integer each ranging from -2.14 Billion to 2.14 Billion is overkill will require a lot of memory. You don't need negative values to store. You may consider using chars, as you can convert each integer digit into a char and backward but less memory is required. The most memory-efficient way is perhaps an Enum ranging from 0 to 9.
Your class would require storing a number greater than a long long (8 bytes) at least 64 bytes (number array) + 4 bytes for the size variable + 1 bit (isNeg). This is quite large for a number :)
According to your task, you are not allowed to use integers. So you have to change it :)
My approach exploits the fact that each element of an enum class can be converted to an integer type according to its index in the enum class definition (and vice versa). Eventually, each integer can be converted to a char. Thus, there are still integers but you can spot them hardly.
enum class Digit{Zero,One,Two,Three,Four,Five,Six,Seven,Eight,Nine};
typedef Digit* BigIntPtr;
class BigIntegers
{
public:
explicit BigIntegers(std::string num = "");
BigIntegers(const BigIntegers& src);
BigIntegers& operator=(const BigIntegers&src);
~BigIntegers();
friend bool operator<(const BigIntegers& lhs, const BigIntegers& rhs);
friend bool operator>(const BigIntegers& lhs, const BigIntegers& rhs);
friend BigIntegers operator+(const BigIntegers& lhs, const BigIntegers& rhs);
friend BigIntegers operator-(const BigIntegers& lhs, const BigIntegers&rhs);
friend std::istream &operator>>(std::istream &is, BigIntegers &bi);
friend std::ostream &operator<<(std::ostream &os, const BigIntegers &bi);
private:
size_t size; // based on string size, if neg string size -1
BigIntPtr number; // dynamic array ptr
bool isNeg; // set default to false, assumes a positive number
};
Your .cpp file:
#include <algorithm>
#include "bigint.h"
using namespace std;
BigIntegers::BigIntegers(std::string num):isNeg(false)
{
//if null
if (num.empty())
{
size = 0;
number = NULL;
isNeg = 0;
return;
}
//determine if its negative
if (num.find('-') == 0)
{
num.erase(remove(num.begin(), num.end(), '-'), num.end());
isNeg = true;
}
size = num.length();
number = new Digit[size];
//add array backwards for math optimization
std::string rev; rev.assign(num.rbegin(), num.rend());
Digit * aux = number;
std::for_each (rev.begin(),rev.end(),[&](const char c)
{
*number = Digit(c - '0');
number++;
});
number = aux;
}
BigIntegers::BigIntegers(const BigIntegers & src)
: size(src.size), number{new Digit[src.size]}, isNeg(src.isNeg)
{
for (auto i = number, j = src.number; i < number + size; i++, j++)
{
*i = *j;
}
}
BigIntegers & BigIntegers::operator=(const BigIntegers & src)
{
if (this == &src)
return *this;
size = src.size;
isNeg = src.isNeg;
if (number != NULL) delete[] number;
number = new Digit[src.size];
for (auto i = number, j = src.number; i < number + size; i++,j++)
{
*i = *j;
}
return *this;
}
BigIntegers::~BigIntegers()
{
delete[] number;
}
bool operator<(const BigIntegers & lhs, const BigIntegers & rhs)
{
if (lhs.size > rhs.size) return false;
if (lhs.size < rhs.size) return true;
for (auto i = lhs.number + lhs.size - 1, j = rhs.number + rhs.size - 1; i >= lhs.number || j >= rhs.number; i--, j--)
{
if (char(*i) > char(*j))return false;
if (char(*i) < char(*j))return true;
}
return false;
}
bool operator>(const BigIntegers & lhs, const BigIntegers & rhs)
{
return !(lhs < rhs);
}
BigIntegers operator+(const BigIntegers & lhs, const BigIntegers & rhs)
{
string value = "";
Digit aux = Digit::Zero;
for (auto i = lhs.number, j = rhs.number; i < lhs.number + lhs.size || j < rhs.number + rhs.size; i++, j++)
{
char c = char(aux);
c += i < lhs.number + lhs.size ? char(*i) : char(0);
c += j < rhs.number + rhs.size ? char(*j) : char(0);
aux = Digit(0);
if (c > 9)
{
aux = Digit::One;
c -= 10;
}
// 48 is '0' in Ascii table
value += (c+48);
}
if (aux == Digit::One)
{
value += '1';
}
reverse(value.begin(), value.end());
return BigIntegers(value);
}
BigIntegers operator-(const BigIntegers & lhs, const BigIntegers & rhs)
{
bool reverse = false;
if (lhs < rhs)reverse = true;
const BigIntegers& bigger = reverse ? rhs : lhs;
const BigIntegers& smaller = reverse ? lhs : rhs;
Digit aux = Digit::Zero;
std::string value = "";
for (auto i = bigger.number, j = smaller.number; i < bigger.number+bigger.size; i++, j++)
{
char c1 = char(*i);
char c2 = j < smaller.number+smaller.size ? char(*j) : 0;
c2 += char(aux);
aux = Digit::Zero;
if (c1 < c2)
{
aux = Digit::One;
c1 = c1 + 10 - c2;
}
else
{
c1 -= c2;
}
if (c1 > 0 || i < bigger.number + bigger.size - 1)
{
// if condition is to avoid leading zeros
value += (c1 + 48);
}
}
if (reverse)value += "-";
std::reverse(value.begin(), value.end());
return BigIntegers(value);
}
istream& operator>>(istream& is, BigIntegers& bi)
{
std::string input;
getline(is, input);
bi = BigIntegers(input);
return is;
}
std::ostream &operator<<(std::ostream &os, const BigIntegers &bi) {
if (bi.isNeg) //add sign if needed
os << '-';
for (int s = bi.size - 1; s > -1; s--) //print reverse
{
os << static_cast<int>(bi.number[s]);
}
return os;
}
As you may notice, I replaced all for loops using an integer ;)
At least I am not using the int keyword once. However, something like +10 is of course a const integer.
Up to this point, I have not yet been able to determine that storing the digits in reverse is advantageous.
The multiplication is up to you. Nice task :)
This overload is what solved the problem of the garbage values.
BigIntegers &BigIntegers::operator=(const BigIntegers &bi) {
//if number is already assigned here
if(this==&bi)
return *this;
//else assign the number
size = bi.size; isNeg = bi.isNeg;
if (number != nullptr) delete[] number;
number= new int[bi.size];
for (auto i = number, j = bi.number; i < number+size; i++, j++)
*i = *j;
return *this;
}
So I have this test case and am trying to no have to make one million operator overloads or handle overload collisions or complexity. I want to be able to handle literal array constants with operator overloads. This is sort of a requirement to create ease of use for an intended library (this test case shoots in the same direction.)
I am looking for a solution to being able to add, subtract variable length carray literal constants. I have a few solutions, one that works but only if both C_COORDS and N_COORDS are more than one. I am using defines instead of Templates to simplify the test case but those defines would be replaced with Templates in the final hour.
Any suggestions welcome. Note, I'm sure I could make this more clear but can't see how at the moment. I use to do lots of C programming 30 years ago. But haven't touched CPP much since then, yes I understand CPP mostly and the differences between it and old C, but not much experience yet. I am just noting because I am sure I am missing a few OBVIOUS things. Thanks. My testcase follows....
/** Coord.cpp */
#include <iostream>
#include <cstring>
#include <initializer_list>
#include <cassert>
#define T_COORDS float // the type of coordinates
#define N_COORDS (2) // the coordinates per item
#define C_COORDS (2) // the number of coordinate items
#define L_COORDS (N_COORDS*C_COORDS) // the number of coordinate items
using namespace std;
class Coords {
public:
T_COORDS coords[L_COORDS];
Coords()
{
memset(this->coords, 0, sizeof(Coords));
}
Coords(const T_COORDS inits[L_COORDS])
{
memmove(this->coords, &inits, sizeof(Coords));
}
Coords(initializer_list<T_COORDS> inits) : coords{}
{
copy( inits.begin(), next( inits.begin(), L_COORDS ), coords );
}
friend Coords operator + (const Coords &coords0, const Coords &coords1)
{
Coords result = coords0;
for (int i=0; i < L_COORDS; i++)
result.coords[i] += coords1.coords[i];
return result;
}
/* original that complains about taking size from a temporary array. the next
* 2 UNCOMMENTED overloads accept a fixed length array, but then I have to
* have for every case and they cannot overlap.
friend Coords operator + (const Coords& coords0, const T_COORDS (& coords1)[])
{
int n = sizeof(coords1) / sizeof(T_COORDS);
if ( ! n || n > L_COORDS || n % N_COORDS )
throw "coordinate count must be a multiple and at least N_COORDS and not more then T_COORDS";
cout << "n = " << n << endl;
Coords result = coords0;
for (int i=0; i < L_COORDS; i++)
result.coords[i] += coords1[i%n];
return result;
}
*/
/* bad solution was to make to overloads that match of a fixed length array,
* however it sucks because if N_COORDS is 1, then it also won't compile
* because it ends up with duplicate overloads as L_COORDS is equal to
* C_COORDS when N_COORDS is one, and same is true is C_COORDS is one.
* WHat I hope for is a way to accept any array or at least any array with a
* length >= and on boundaries of C_COORDS and not more the L_COORDS */
friend Coords operator + (const Coords& coords0, const T_COORDS (& coords1)[C_COORDS])
{
int n = sizeof(coords1) / sizeof(T_COORDS);
if ( ! n || n > L_COORDS || n % N_COORDS )
throw "coordinate count must be a multiple and at least N_COORDS and not more then T_COORDS";
cout << "n = " << n << endl;
Coords result = coords0;
for (int i=0; i < L_COORDS; i++)
result.coords[i] += coords1[i%n];
return result;
}
/* as above, so below but for different size array */
friend Coords operator + (const Coords& coords0, const T_COORDS (& coords1)[L_COORDS])
{
int n = sizeof(coords1) / sizeof(T_COORDS);
if ( ! n || n > L_COORDS || n % N_COORDS )
throw "coordinate count must be a multiple and at least N_COORDS and not more then T_COORDS";
cout << "n = " << n << endl;
Coords result = coords0;
for (int i=0; i < L_COORDS; i++)
result.coords[i] += coords1[i%n];
return result;
}
};
void print_coords(const char* label, Coords coords)
{
cout << label << ": ( " << coords.coords[0];
for (int i=1; i < L_COORDS; i++) {
cout << ", " << coords.coords[i];
}
cout << " }" << endl;
};
int main () {
Coords coords0;
print_coords("coords0", coords0);
Coords coords1 {4,5,6,7};
print_coords("coords1", coords1);
Coords coords2 {8,9,10,11};
print_coords("coords2", coords2);
Coords coords3 = coords1 + coords2;
print_coords("coords3", coords3);
T_COORDS tmp[] = {-2,-2,-2,-2};
Coords coords4 = coords3 + tmp;
print_coords("coords4", coords4);
T_COORDS tmp2[] = {-2,-2};
Coords coords5 = coords4 + tmp2;
print_coords("coords5", coords5);
Coords coords6 = coords5 + (T_COORDS[]){10,20,30,40};
print_coords("coords6", coords6);
Coords coords7 = coords6 + (T_COORDS[]){10,20};
print_coords("coords7", coords7);
/* this won't compile with fixes length overloads because it don't match and thats ok.
try {
Coords coords8 = coords7 + (T_COORDS[]){10,20,30};
print_coords("coords8", coords8);
} catch (const char* msg) {
cout << "threw exception on 3 coordinates as expected" << endl;
}
*/
cout << "Done!" << endl;
return 0;
}
/**
* g++ Coord.cpp -o coord
* ./coord
* RESULING OUTPUT:
* coords0: ( 0, 0, 0, 0 }
* coords1: ( 4, 5, 6, 7 }
* coords2: ( 8, 9, 10, 11 }
* coords3: ( 12, 14, 16, 18 }
* n = 4
* coords4: ( 10, 12, 14, 16 }
* n = 2
* coords5: ( 8, 10, 12, 14 }
* n = 4
* coords6: ( 18, 30, 42, 54 }
* n = 2
* coords7: ( 28, 50, 52, 74 }
* Done!
*/
const T_COORDS (& coords1)[] is array of unknown bound. you know the size, so it is not what you want.
You might use template:
template <std::size_t N>
// SFINAE, instead of throw
// care, then Coords+Coords is viable and no exception in Coords(initializer_list)
// For invalid size
/*, std::enable_if_t<N != 0 && N <= L_COORDS && N % N_COORDS == 0, bool> = false*/>
friend Coords operator + (const Coords& coords0, const T_COORDS (& coords1)[N])
{
if ( ! N || N > L_COORDS || N % N_COORDS )
throw "coordinate count must be a multiple and at least N_COORDS and not more then T_COORDS";
std::cout << "n = " << N << std::endl;
Coords result = coords0;
for (int i=0; i < L_COORDS; i++)
result.coords[i] += coords1[i%N];
return result;
}
Demo
For one of our class assignments we had to implement a polynomial class. It stores the coefficients of a polynomial and outputs the answer.
In my class definition, I have a friend operator that outputs the function:
friend std::ostream& operator << (std::ostream& out, Polynomial& p);
and my implementation is as follows:
std::ostream& operator << (std::ostream& out, Polynomial& p) {
double ans = 0;
for(int i = 0; i <= p.order; ++i)
ans += (double)p.coefficents[i] * pow(p.x, i);
out << ans;
return out;
}
My main function (written by my instructor) is:
int main ()
{
Polynomial p1 (0.5,3); // Invokes two argument constructor for p1
p1.inputCoefficients(); // Set the coefficient of polynomial p1
cout << "Polynomial p1 evaluates to " << p1 << endl;
Polynomial p2(p1), p3; // Copy constructor for p2 and default constructor for p3
cout << "Polynomial p2 evaluates to " << p2 << endl;
cout << "Polynomial p3 evaluates to " << p3 << endl;
p3 = p2; // Copy assignment operator
return 0;
}
My question is:
When I run my program with this line of code:
double ans = 0;
my output is this:
Polynomial p1 evaluates to 1.375
Polynomial p2 evaluates to 1.375
Polynomial p3 evaluates to 0
Polynomial destroyed!
Polynomial destroyed!
Polynomial destroyed!
Which is the correct output
but if I change that line to this:
double ans;
Unexpected things start to happen:
Polynomial p1 evaluates to 1.375
Polynomial p2 evaluates to 1.375
Polynomial p3 evaluates to 1.375
Polynomial destroyed!
Polynomial destroyed!
Polynomial destroyed!
Why is p3 evaluated to 1.375? p3 was created using the default constructor so wouldn't it output 0?
As soon as the polynomial is outputted wouldn't the scope of ans die? Even if it didn't, or ans kept the value from the last time it ran, then wouldn't p2 be doubled (be 2.75) because the << operator ran twice?
Please feel free to get technical and offer advice, I'm curious and want to know the insides of what's actually going on.
Here is the entirety of my code (for reference):
/*
Using dynamic arrays, implement a polynomial class. In mathematics, polynomial is a function of the form f(x) = a0*x^0 + a1*x^1 + a2*x^2 + a3*x^3 + ....n terms. Here, a0, a1, a2 etc. are the coefficients of the polynomial and n is the order of the polynomial.
The private variables include the value of x (a real number), the order of the polynomial (an integer) and the dynamic array that stores the coefficients (real numbers).
The public methods include
a. default constructor that sets the value of x to zero and the order to 0,
b. a two argument constructor that takes as arguments the value of x and the order of the polynomial. The values of the coefficients are set to zero.
c. inputCoefficients(): prompts the user to input the value of the coefficients of the polynomial. For this homework, skip the user input. Instead assign the coefficent values equal to the index of the position in the array. For example, a0 = 0, a1 = 1, a2 = 2 and so on depending on the order of the particular polynomial object
c. a copy constructor
d. << operator overloaded that returns the value of the polynomial (obtained by evaluating the polynomial).
e. == overloaded (copy assignment operator)
f. destructor. Deallocates dynamic arrays and prints a message "Polynomial destroyed! "
Below is the testing program -
*/
#include <iostream>
using std::cin;
using std::endl;
using std::cout;
#include <cmath>
class Polynomial {
public:
Polynomial() {
x = 0,
order = 0;
coefficents = new double[order + 1];
}
Polynomial(const double x, const int order) {
this->x = x;
this->order = order;
this->coefficents = new double[order + 1];
for(int i = 0; i <= order; ++i)
this->coefficents[i] = 0;
}
Polynomial(const Polynomial& p) {
this->x = p.x;
this->order = p.order;
this->coefficents = new double[this->order];
for(int i = 0; i <= this->order; ++i)
this->coefficents[i] = p.coefficents[i];
}
~Polynomial() {
std::cout << "Polynomial destroyed! " << std::endl;
delete[] coefficents;
}
void inputCoefficients() {
/*
for(auto& num: coefficents) {
std::cout << "Enter the next coefficent:: ";
std::cin >> num;
}
std::cout << "Thank you" << std::endl;
*/
for(int i = 0; i <= order; ++i) {
coefficents[i] = i;
}
}
Polynomial& operator = (const Polynomial& p) {
this->x = p.x;
this->order = p.order;
delete[] this->coefficents;
this->coefficents = new double[order + 1];
for(int i = 0; i <= this->order; ++i)
this->coefficents[i] = p.coefficents[i];
return *this;
}
friend std::ostream& operator << (std::ostream& out, Polynomial& p);
friend bool operator == (const Polynomial& p1, const Polynomial& p2);
private:
double x;
double* coefficents;
int order;
};
std::ostream& operator << (std::ostream& out, Polynomial& p) {
double ans;
for(int i = 0; i <= p.order; ++i)
ans += (double)p.coefficents[i] * pow(p.x, i);
out << ans;
return out;
}
bool operator == (const Polynomial& p1, const Polynomial& p2) {
if((p1.x != p2.x) && (p1.order != p2.order))
return false;
for(int i = 0; i < p1.order; ++i) {
if(p1.coefficents[i] != p2.coefficents[i])
return false;
}
return true;
}
int main ()
{
Polynomial p1 (0.5,3); // Invokes two argument constructor for p1
p1.inputCoefficients(); // Set the coefficient of polynomial p1
cout << "Polynomial p1 evaluates to " << p1 << endl;
Polynomial p2(p1), p3; // Copy constructor for p2 and default constructor for p3
cout << "Polynomial p2 evaluates to " << p2 << endl;
cout << "Polynomial p3 evaluates to " << p3 << endl;
p3 = p2; // Copy assignment operator
return 0;
}
Your << function contains the line:
ans += (double)p.coefficents[i] * pow(p.x, i);
If you don't initialize ans to 0, then the initial value of ans will be indeterminate, and then you're adding each term to this. So you get a random result.
In your case, ans is apparently holding on to its value from the previous call. And since p3 is an empty polynomial, the loop never adds anything to it, so you print the previous result.
I have a vector with digits of number, vector represents big integer in system with base 2^32. For example:
vector <unsigned> vec = {453860625, 469837947, 3503557200, 40}
This vector represent this big integer:
base = 2 ^ 32
3233755723588593872632005090577 = 40 * base ^ 3 + 3503557200 * base ^ 2 + 469837947 * base + 453860625
How to get this decimal representation in string?
Here is an inefficient way to do what you want, get a decimal string from a vector of word values representing an integer of arbitrary size.
I would have preferred to implement this as a class, for better encapsulation and so math operators could be added, but to better comply with the question, this is just a bunch of free functions for manipulating std::vector<unsigned> objects. This does use a typedef BiType as an alias for std::vector<unsigned> however.
Functions for doing the binary division make up most of this code. Much of it duplicates what can be done with std::bitset, but for bitsets of arbitrary size, as vectors of unsigned words. If you want to improve efficiency, plug in a division algorithm which does per-word operations, instead of per-bit. Also, the division code is general-purpose, when it is only ever used to divide by 10, so you could replace it with special-purpose division code.
The code generally assumes a vector of unsigned words and also that the base is the maximum unsigned value, plus one. I left a comment wherever things would go wrong for smaller bases or bases which are not a power of 2 (binary division requires base to be a power of 2).
Also, I only tested for 1 case, the one you gave in the OP -- and this is new, unverified code, so you might want to do some more testing. If you find a problem case, I'll be happy to fix the bug here.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
namespace bigint {
using BiType = std::vector<unsigned>;
// cmp compares a with b, returning 1:a>b, 0:a==b, -1:a<b
int cmp(const BiType& a, const BiType& b) {
const auto max_size = std::max(a.size(), b.size());
for(auto i=max_size-1; i+1; --i) {
const auto wa = i < a.size() ? a[i] : 0;
const auto wb = i < b.size() ? b[i] : 0;
if(wa != wb) { return wa > wb ? 1 : -1; }
}
return 0;
}
bool is_zero(BiType& bi) {
for(auto w : bi) { if(w) return false; }
return true;
}
// canonize removes leading zero words
void canonize(BiType& bi) {
const auto size = bi.size();
if(!size || bi[size-1]) return;
for(auto i=size-2; i+1; --i) {
if(bi[i]) {
bi.resize(i + 1);
return;
}
}
bi.clear();
}
// subfrom subtracts b from a, modifying a
// a >= b must be guaranteed by caller
void subfrom(BiType& a, const BiType& b) {
unsigned borrow = 0;
for(std::size_t i=0; i<b.size(); ++i) {
if(b[i] || borrow) {
// TODO: handle error if i >= a.size()
const auto w = a[i] - b[i] - borrow;
// this relies on the automatic w = w (mod base),
// assuming unsigned max is base-1
// if this is not the case, w must be set to w % base here
borrow = w >= a[i];
a[i] = w;
}
}
for(auto i=b.size(); borrow; ++i) {
// TODO: handle error if i >= a.size()
borrow = !a[i];
--a[i];
// a[i] must be set modulo base here too
// (this is automatic when base is unsigned max + 1)
}
}
// binary division and its helpers: these require base to be a power of 2
// hi_bit_set is base/2
// the definition assumes CHAR_BIT == 8
const auto hi_bit_set = unsigned(1) << (sizeof(unsigned) * 8 - 1);
// shift_right_1 divides bi by 2, truncating any fraction
void shift_right_1(BiType& bi) {
unsigned carry = 0;
for(auto i=bi.size()-1; i+1; --i) {
const auto next_carry = (bi[i] & 1) ? hi_bit_set : 0;
bi[i] >>= 1;
bi[i] |= carry;
carry = next_carry;
}
// if carry is nonzero here, 1/2 was truncated from the result
canonize(bi);
}
// shift_left_1 multiplies bi by 2
void shift_left_1(BiType& bi) {
unsigned carry = 0;
for(std::size_t i=0; i<bi.size(); ++i) {
const unsigned next_carry = !!(bi[i] & hi_bit_set);
bi[i] <<= 1; // assumes high bit is lost, i.e. base is unsigned max + 1
bi[i] |= carry;
carry = next_carry;
}
if(carry) { bi.push_back(1); }
}
// sets an indexed bit in bi, growing the vector when required
void set_bit_at(BiType& bi, std::size_t index, bool set=true) {
std::size_t widx = index / (sizeof(unsigned) * 8);
std::size_t bidx = index % (sizeof(unsigned) * 8);
if(bi.size() < widx + 1) { bi.resize(widx + 1); }
if(set) { bi[widx] |= unsigned(1) << bidx; }
else { bi[widx] &= ~(unsigned(1) << bidx); }
}
// divide divides n by d, returning the result and leaving the remainder in n
// this is implemented using binary division
BiType divide(BiType& n, BiType d) {
if(is_zero(d)) {
// TODO: handle divide by zero
return {};
}
std::size_t shift = 0;
while(cmp(n, d) == 1) {
shift_left_1(d);
++shift;
}
BiType result;
do {
if(cmp(n, d) >= 0) {
set_bit_at(result, shift);
subfrom(n, d);
}
shift_right_1(d);
} while(shift--);
canonize(result);
canonize(n);
return result;
}
std::string get_decimal(BiType bi) {
std::string dec_string;
// repeat division by 10, using the remainder as a decimal digit
// this will build a string with digits in reverse order, so
// before returning, it will be reversed to correct this.
do {
const auto next_bi = divide(bi, {10});
const char digit_value = static_cast<char>(bi.size() ? bi[0] : 0);
dec_string.push_back('0' + digit_value);
bi = next_bi;
} while(!is_zero(bi));
std::reverse(dec_string.begin(), dec_string.end());
return dec_string;
}
}
int main() {
bigint::BiType my_big_int = {453860625, 469837947, 3503557200, 40};
auto dec_string = bigint::get_decimal(my_big_int);
std::cout << dec_string << '\n';
}
Output:
3233755723588593872632005090577
I am looking for a very simple C++ class implementing an unsigned integer with arbitrary precision and just the post increment operator.
I know there are library for arbitrary precision integer arithmetic but my needs are quite simple and I prefer to avoid the weight of a full library.
It seems to me that my current implementation is still not simple enough and not elegant enough. What do you suggest?
#include <vector>
#include <string>
#include <algorithm>
class UNat
{
public:
static const char base = 10;
UNat( const char* n )
{
std::string s(n);
std::reverse(s.begin(),s.end());
for ( size_t i = 0; i < s.length(); i++ ) {
n_.push_back(s[i]-'0');
}
}
UNat& operator++(int)
{
bool carry = false;
bool finished = false;
for ( size_t i = 0; i < n_.size() && !finished; i++ ) {
n_[i] = add(n_[i],1,carry);
if ( carry ) {
finished = false;
} else {
finished = true;
}
}
if ( carry ) {
n_.push_back(1);
}
return *this;
}
std::string to_string() const
{
std::string r(n_.begin(), n_.end());
std::reverse(r.begin(),r.end());
std::for_each(r.begin(), r.end(), [](char& d) { d+='0';});
return r;
}
private:
char add( const char& a, const char& b, bool& carry )
{
char cc = a + b;
if ( cc >= base ) {
carry = true;
cc -= base;
} else {
carry = false;
}
return cc;
}
std::vector< char > n_;
};
std::ostream& operator<<(std::ostream& oss, const UNat& n)
{
oss << n.to_string();
return oss;
}
#include <iostream>
int main()
{
UNat n("0");
std::cout << n++ << "\n";
std::cout << UNat("9")++ << "\n";
std::cout << UNat("99")++ << "\n";
std::cout << UNat("19")++ << "\n";
std::cout << UNat("29")++ << "\n";
std::cout << UNat("39")++ << "\n";
return 0;
}
In order to avoid returning the mutated value, save a local copy and return it:
UNat operator++(int)
{
UNat copy = *this;
// ....
return copy;
} // don't return by reference
Comparatively, the prefix operator does return by reference.
UNat& operator++ ()
{
// ....
return *this;
}
Some tips and tricks from Arbitrary-precision arithmetic Explanation:
1/ When adding or multiplying numbers, pre-allocate the maximum space
needed then reduce later if you find it's too much. For example,
adding two 100-"digit" (where digit is an int) numbers will never give
you more than 101 digits. Multiply a 12-digit number by a 3 digit
number will never generate more than 15 digits (add the digit counts).
An alternative implementation for your addition function can look like this:
c->lastdigit = std::max(a->lastdigit, b->lastdigit)+1;
carry = 0;
for (i=0; i<=(c->lastdigit); i++) {
c->digits[i] = (char) (carry+a->digits[i]+b->digits[i]) % 10;
carry = (carry + a->digits[i] + b->digits[i]) / 10;
}
The code implements what's generally known as Binary Coded Decimal (BCD). Very simple, and, as you say, the implementation can be much simpler if you only want to increment and don't need general addition. To simplify even further, use the internal character representations for the digits '0' through '9' instead of the values 0 through 9. And for another simplification, store the characters in a std::string:
for (int index = 0; index < digits.size(); ++index) {
if (digits[index] != '9') {
++digits[index];
break;
}
digits[index] = '0';
}
if (index == digits.size())
digits.push_back('1');
This makes the stream inserter nearly trivial.