I've been creating a math engine in C++. I have decided now is a good time to ask for feedback from the community. Right now the main "good" things it has is complex numbers, calculus and a fraction class. I am planning to add set theory sometime in the future, although I don't know how useful it would be to programmers. Since my project is for brushing up my C++ skills, but I'm making it as if I was making it as a general-purpose library.
For nsqrt
and sqrt
; the parameter precision
represent the number of steps of a Newton-Raphson approximation to be performed
Is there anything I should improve on, change, add, etc.?
#include <iostream>
using namespace std;
namespace math{
const double mini = double (numeric_limits<double>::min());
const double e = 2.718281828459045;
const double pi = 3.141592653589793238462643383;
int def_prec = 16;
}
template <class t = double>
t exp(t base, int exponent){
if(exponent<0){
return 1/exp(base,-exponent);
} else if(exponent>0){
double output = 1;
for(int i=1;i<=exponent;i++){output *= base;}
return output;
} else {return 1;}
}
double nsqrt(double x, int precision = math::def_prec){
double sum = 1;
for (int i=1;i<=precision;i++){
sum -= ((sum*sum)-x)/(2*sum);
}
return sum;
}
double esqrt(double num, double precision = math::def_prec){
double h = num/precision;
double y = 1;
for (double x=1;x!=num;x+=h){
y += h*(1/(2*y));
}
return y;
}
double sqrt(double num, int precision = math::def_prec){
return nsqrt(num,precision);
}
double root(double num, int root, int precision = math::def_prec){
double sum = 1;
for (int i=1;i<=precision;i++){
sum -= ((exp(sum,root))-num)/(root*exp(sum,root-1));
}
return sum;
}
class complex{
private:
double r,i;
public:
complex(double r_in,double i_in): r(r_in), i(i_in) {};
double get_re() {return r;}
double get_im(){return i;}
double magnitude(int precision = math::def_prec){ return sqrt((r*r)+(i*i),precision);}
complex operator + (complex a){
r += a.get_re();
i += a.get_im();
return (*this);
}
complex operator + (double a){r += a;return (*this);}
complex operator - (complex a){
r -= a.get_re();
i -= a.get_im();
return (*this);
}
complex operator - (double a){r -= a;return (*this);}
complex operator * (complex a){
r = (r*a.get_re())-(i*a.get_im());
i = (r*a.get_im())+(i*a.get_re());
return (*this);
}
complex operator * (double a){r *=a;i *= a;return (*this);}
complex operator / (complex a){
r = (r/a.get_re())-(i/a.get_im());
i = (r/a.get_im())+(i/a.get_re());
return (*this);
}
complex operator / (double a){r /=a;i /= a;return (*this);}
void operator = (double a[2]){r=a[0];i=a[1];}
void operator = (complex a){r=a.get_re();i=a.get_im();}
bool operator == (complex a){return (r==a.get_re() && i==a.get_im());}
bool operator == (double a[2]){return (r==a[0] && i==a[1]);}
bool operator != (complex a){return (r!=a.get_re() || i!=a.get_im());}
bool operator != (double a[2]){return (r!=a[0] || i!=a[1]);}
void operator += (complex a){
r += a.get_re();
i += a.get_im();
}
bool operator > (complex a){return (r==a.get_re())? (i>a.get_im()) : (r>a.get_re());}
bool operator < (complex a){return (r==a.get_re())? (i<a.get_im()) : (r<a.get_re());}
bool operator <= (complex a){return (r==a.get_re())? (i<=a.get_im()) : (r<=a.get_re());}
bool operator >= (complex a){return (r==a.get_re())? (i>=a.get_im()) : (r>=a.get_re());}
void operator += (double a){r += a;}
void operator -= (complex a){
r -= a.get_re();
i -= a.get_im();
}
void operator -= (double a){r -= a;}
void operator *= (complex a){
r = (r*a.get_re())-(i*a.get_im());
i = (r*a.get_im())+(i*a.get_re());
}
void operator *= (double a){r *= a;i *= a;}
void operator /= (complex a){
r = (r/a.get_re())-(i/a.get_im());
i = (r/a.get_im())+(i/a.get_re());
}
void operator /= (double a){r /= a;i /= a;}
void operator ++ (){r++;}
void operator -- (){r--;}
ostream& operator<<(ostream& os)
{
os << r << "+" << i << "i";
return os;
}
void operator = (int a){r=a;}
};
complex exp(complex base, int exponent){
if(exponent<0){
complex one(1,0);
return one/exp(base,-exponent);
} else if(exponent>0){
complex output(1,0);
for(int i=1;i<=exponent;i++){output *= base;}
return output;
} else {return base/base;}
}
template <class t = int>
t gcd(t X, t Y) {
t pre = 0;
if (X%Y == 0) {return (X>Y)? Y : X;}
pre = X%Y;
X = Y;
Y = pre;
while (X%Y != 0) {
pre = X%Y;
X = Y;
Y = pre;
}
return pre;
}
int round(double x){return (x-int(x)>0.5)? int(x)+1 : int(x);}
class fraction{
private:
int n,d;
public:
fraction(int n_in,int d_in): n(n_in),d(d_in){};
void simplify(){n/=gcd(n,d);d/=gcd(n,d);}
double get_double(){return n/d;}
int get_num(){return n;}
int get_den(){return d;}
fraction operator + (fraction a){
n = (n*a.get_den())+(a.get_num()*d);
d *= a.get_den();
simplify();
return (*this);
}
fraction operator + (int a){n += a*d;return (*this);}
fraction operator - (fraction a){
n = (n*a.get_den())-(a.get_num()*d);
d *= a.get_den();
simplify();
return (*this);
}
fraction operator - (int a){n -= a*d;return (*this);}
fraction operator * (fraction a){
n *= a.get_num();
d *= a.get_den();
simplify();
return (*this);
}
fraction operator * (int a){n *= a;return (*this);}
fraction operator / (fraction a){
n /= a.get_num();
d /= a.get_den();
simplify();
return (*this);
}
fraction operator / (int a){n /= a;return (*this);}
void operator += (fraction a){
n = (n*a.get_den())+(a.get_num()*d);
d *= a.get_den();
simplify();
}
void operator += (int a){n += a*d;}
void operator -= (fraction a){
n = (n*a.get_den())-(a.get_num()*d);
d *= a.get_den();
simplify();
}
void operator -= (int a){n -= a*d;}
void operator *= (fraction a){
n *= a.get_num();
d *= a.get_den();
simplify();
}
void operator *= (int a){n*=a;}
void operator /= (fraction a){
n /= a.get_num();
d /= a.get_den();
simplify();
}
void operator /= (int a){n /= a;}
void operator = (fraction a){n = a.get_num();d=a.get_den();}
void operator = (int a){n=a;d=1;}
bool operator < (fraction a){return (n*a.get_den()<a.get_num()*d);}
bool operator > (fraction a){return (n*a.get_den()>a.get_num()*d);}
bool operator >= (fraction a){return (n*a.get_den()>=a.get_num()*d);}
bool operator <= (fraction a){return (n*a.get_den()<=a.get_num()*d);}
bool operator == (fraction a){return (n*a.get_den()==a.get_num()*d);}
bool operator != (fraction a){return (n*a.get_den()!=a.get_num()*d);}
bool operator < (int a){return (n<a*d);}
bool operator > (int a){return (n>a*d);}
bool operator >= (int a){return (n>=a*d);}
bool operator <= (int a){return (n<=a*d);}
bool operator == (int a){return (n==a*d);}
bool operator != (int a){return (n!=a*d);}
operator double () {return n/d;}
};
fraction tofrac(double x, int precision = 1000000000){
long gcd_ = gcd(round(x-int(x) * precision), precision);
fraction output(round(x-int(x)*precision)/gcd_,precision/gcd_);
return output;
}
template <class t = double>
t limit(double (*f)(t),t to) {
return (f(to+math::mini)+f(to-math::mini))/2;
}
template <class t = double>
t derivative(double (*f)(t),t x){
return ((f(x+math::mini)-f(x))/math::mini+(f(x-math::mini)-f(x))/(-math::mini))/2;
}
template <class t = double>
t sigma(double (*f)(t),int from, int to){
t out = 0;
for (int n=from;n<=to;n++){out += f(n);}
return out;
}
template <class t = double>
t pi(double (*f)(t),int from, int to){
t out = 1;
for (int n=from;n<=to;n++){out *= f(n);}
return out;
}
double factorial1(int x) {
double out = 1;
for(int n=x;n>0;n--){out*=n;}
return out;
}
template <class t = double>
t sin(t x, int precision = math::def_prec){
t output = 0;
for(int n=0;n<=precision;n++){
output += exp(-1,n)*(exp(x,(2*n)+1)/factorial1((2*n)+1));
}
return output;
}
template <class t = double>
t cos(t x, int precision = math::def_prec){
t output = 0;
for(int n=0;n<=precision;n++){
output += exp(-1,n)*(exp(x,2*n)/factorial1(2*n));
}
return output;
}
template <class t = double>
t tan(t x, int precision = math::def_prec){return sin(x,precision)/cos(x,precision);}
template <class t = double>
t ln(t x, int precision = math::def_prec){
t output = 0;
for(int n=1;n<=precision;n++){
output += (exp(x-2,n)*exp(-1,n-1))/n;
}
return output;
}
complex ln(complex x, int precision = math::def_prec){
complex output(0,0);
for(int n=1;n<=precision;n++){
output += (exp(x-1,n)*exp(-1,n-1))/n;
}
return output;
}
template <class t = double>
t log(t base, t x, int precision = math::def_prec){return ln(x,precision)/ln(base,precision);}
template <class t = double>
t derivative_fast(t (*f)(t),t x){return (f(x+1)-f(x-1))/2;}
double pi(int precision = math::def_prec){
double output = 0;
for(int i=0;i<=precision+(precision%2);i++){
output += exp(-1.0,i)/((2*i)+1);
}
return output*4;
}
//this pi algorithm isn't my work
double spigotpi(long digits){
long LEN = (digits / 4 + 1) * 14; //nec. array length
long array[LEN]; //array of 4-digit-decimals
long b; //nominator prev. base
long c = LEN; //index
long d; //accumulator and carry
long e = 0; //save previous 4 digits
long f = 10000; //new base, 4 decimal digits
long g; //denom previous base
long h = 0; //init switch
for (; (b = c -= 14) > 0;) { //outer loop: 4 digits per loop
for (; --b > 0;) { //inner loop: radix conv
d *= b; //acc *= nom prev base
if (h == 0)
d += 2000 * f; //first outer loop
else
d += array[b] * f; //non-first outer loop
g = b + b - 1; //denom prev base
array[b] = d % g;
d /= g; //save carry
}
h = (("%d"), e + d / f);//print prev 4 digits
std::cout << h;
d = e = d % f; //save currently 4 digits
//assure a small enough d
}
if (getchar())
{
return 0;
}
return 0;
}
double pi2(long precision){
double output = 1;
for (long k = precision;k>0;k--){
output *= 1.0+(k/((2.0*k)+1.0));
cout << output << endl;
}
return output;
}
double e(int precision = math::def_prec){
double output = 0;
for(int i=0;i<=precision;i++){
output += 1/factorial1(i);
}
return output;
}
double abs(complex x, int precision){return x.magnitude(precision);}
template <class t = double>
double abs(t x){return (x<0)? -x : x;}
complex sqrt(complex x, int precision = math::def_prec){
if (x.get_im()!=0){
complex output((1/sqrt(2,precision))*sqrt(x.magnitude()+x.get_re(),precision),((x.get_im()/abs(x.get_im()))/sqrt(2,precision))*sqrt(x.magnitude()-x.get_re(),precision));
return output;
} else {
complex output(sqrt(x.get_re()),0);
return output;
}
}
template <class t = double>
t quadratic(t a,t b, t c,t& otherroot, int precision = math::def_prec){
otherroot = (-b+sqrt((b*b)-4*a*c,precision))/(2*a);
return (-b-sqrt((b*b)-4*a*c,precision))/(2*a);
}
complex e_to_xi(double x, int precision = math::def_prec){
complex output(cos(x,precision),sin(x,precision));
return output;
}
template <class t>
t e_to_x(t x, int precision = math::def_prec){
t output = 0;
for(int i=0;i<=precision;i++){
output += exp(x,i)/factorial1(i);
}
return output;
}
complex e_to_x(complex x, int precision = math::def_prec){return e_to_xi(x.get_im(),precision)*e_to_x(x.get_re(),precision);}
complex exp(complex base, complex exponent, int precision = math::def_prec){return e_to_x(ln(base)*exponent);}
template <class t = double>
t exp(t base, double exponent, int precision = math::def_prec){
fraction asfrac(0,0);
asfrac = tofrac(exponent);
return exp(root(base,asfrac.get_den(),precision),asfrac.get_num());
}
template <class t = double>
t zeta(t s, int precision = math::def_prec){
t output(0,0);
for(int n=1.0;n<=precision;n++){output += 1/exp(n,s);}
return output;
}
template <class t = double>
t eta(t s, int precision = math::def_prec){
t output = 0;
for(int n=1;n<=precision;n++){output += exp(-1,(n-1)%2)/exp(n,s);}
return output;
}
template <class c=double>
c rsum(double (*f)(c), int n,c x[n],c t[n-1]){
c output = 0;
for(int i=0;i<=n-1;i++){
output += f(t[i])*(x[i+1]-x[i]);
}
return output;
}
template <class t=double>
t inf(t a, t b){return (a<b)? a:b;}
template <class t=double>
t sup(t a, t b){return (a>b)? a:b;}
template <class c=double>
c ldsum(double (*f)(c), int n,c x[n]){
c output = 0;
for(int i=0;i<=n-1;i++){
output += f(inf(x[i],x[i+1]))*(x[i+1]-x[i]);
}
return output;
}
template <class c=double>
c udsum(double (*f)(c), int n,c x[n]){
c output = 0;
for(int i=0;i<=n-1;i++){
output += f(sup(x[i],x[i+1]))*(x[i+1]-x[i]);
}
return output;
}
template <class c=double>
c rint(c a, c b, c (*f)(c), int precision=math::def_prec){
c partition[precision];
for(int i=0;i<=precision;i++){
partition[i] = a+(((b-a)/precision)*(i+1));
}
return rsum(f, precision, partition, partition); //use the lower bounds as tags
}
template <class c=double>
c udint(c a, c b, c (*f)(c), int precision = math::def_prec){
c P[precision];
}