Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Division operation #18

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* [Addition](#addition)
* [Subtraction](#subtraction)
* [Multiplication](#multiplication)
* [Division](#division)
* [Allocation](#allocation)
* [Comparison](#comparison)
* [Access](#access)
Expand Down Expand Up @@ -46,6 +47,17 @@ c *= a;
c = a * 6;
c *= 6;
```
##Division
```C++
Dodecahedron::Bigint a,b;
std::vector<Bigint> c;
Dodecahedron::Bigint quotient, remainder ;

c = a / b;

quotient = c[0];
remainder = c[1];
```
##Allocation
```C++
Dodecahedron::Bigint a = 12345;
Expand Down
204 changes: 202 additions & 2 deletions src/bigint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#include <sstream>
#include <map>
#include "bigint.h"
#include <cmath>
#include <stdlib.h>
#include <exception>

namespace Dodecahedron
{
Expand Down Expand Up @@ -118,7 +121,9 @@ Bigint &Bigint::operator+=(long long b)
number.insert(number.end(), skip - number.size(), 0);
}
it += skip;
while (b) {
bool initial_flag=true;
while (b || initial_flag) {
initial_flag=false;
if (it != number.end()) {
*it += b % base;
b /= base;
Expand Down Expand Up @@ -188,7 +193,7 @@ Bigint Bigint::operator*(Bigint const &b)
if (b.number.size() == 1) return *this *= b.number[0];
std::vector<int>::iterator it1;
std::vector<int>::const_iterator it2;
Bigint c;
Bigint c("0");
for (it1 = number.begin(); it1 != number.end(); ++it1) {
for (it2 = b.number.begin(); it2 != b.number.end(); ++it2) {
c.skip = (unsigned int) (it1 - number.begin()) + (it2 - b.number.begin()); //TODO
Expand Down Expand Up @@ -230,7 +235,201 @@ Bigint &Bigint::operator*=(int const &b)
return *this;
}

bool Bigint::is_even(){
if(number.size()==1){
int x = number[0];
if(x%2 == 0)
return true;
else
return false;
}

else if(number.size()>1){
int x = *(number.begin());
if(x%2 == 0)
return true;
else
return false;
}

}


Bigint Bigint::sub_number(Bigint &p, Bigint &q){

std::string tmpx0, tmpx1, tmpx3;
long window_size = q.digits();
int last_i_iterator;
std::vector<int>::iterator i=p.number.end()-1;

if(window_size>p.digits())
window_size=p.digits();


while(i>=p.number.begin() && window_size>0){

tmpx0 = to_string(*i);
int ssss = tmpx0.size();
if(i!=p.number.end()-1 && ssss<9){
tmpx0 = std::string(9-ssss,'0') + tmpx0;
}

if(window_size - ssss < 0){
tmpx3=tmpx0;
tmpx0="";
for(int i=0;i<window_size;i++){
tmpx0=tmpx0+tmpx3[i];
last_i_iterator=i;
}
window_size = window_size - tmpx0.size();
tmpx1 = tmpx1 + tmpx0;
}
else{
window_size = window_size - tmpx0.size();
tmpx1 = tmpx1 + tmpx0;
i--;
}
}

Bigint c(tmpx1);

if(c<q && i>=p.number.begin()){
if(tmpx3.size()!=0){
window_size++;
tmpx0 = tmpx3[last_i_iterator+1];
tmpx1 = tmpx1 + tmpx0;
c=tmpx1;
}
else{
window_size++;
tmpx0 = to_string(*i);
if(i!=p.number.end()-1 && tmpx0.size()<9){
tmpx0 = std::string(9-tmpx0.size(),'0') + tmpx0;
}
tmpx0 = tmpx0[0];
tmpx1 = tmpx1 + tmpx0;
c=tmpx1;
}

}

return c;
}
//Division

std::vector<Bigint> Bigint::divide(Bigint q){

/*Algorithm used is "Double division algorithm"*/

Bigint p = *this;
std::vector<Bigint> answer;
int look_up_table_size=4;
std::vector<Bigint> look_up(look_up_table_size);
bool done_flag=false ;
Bigint tmp_quotient, sum_quotient, tmpx1, tmpx2;

Bigint zero("0");

if(q==zero || q == 0){
//std::cout << "Error: Dividing by zero" << std::endl;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the commented out code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i will fix it.

//exit (EXIT_FAILURE);
throw "Dividing by zero!";
}

bool this_sign = this -> positive;
bool q_sign = q.positive;

p.positive = true;
q.positive = true;


look_up[0]=q;
look_up[1]=q*2;
look_up[2]=q*4;
look_up[3]=q*8;


while(true){

Bigint sub_p=sub_number(p, q); // cut a portion from the dividened equal in size with the divisor

for(int i=0;i<look_up_table_size;i++){ // looking in the look_up table

if(sub_p<look_up[i] && i!=0){
tmpx1=look_up[i-1];
tmp_quotient = std::pow(2,i-1);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe 1<<(i-1) is an easier and faster choice. pow in cmath is for float number

break;
}
else if(sub_p<look_up[i] && i==0){

if(q.digits()>=p.digits()){
done_flag=true;
break;
}
}
else if(sub_p==look_up[i] || (sub_p>look_up[i] && i==look_up_table_size-1)){
tmpx1=look_up[i];
tmp_quotient= std::pow(2,i);
break;
}
}

if(done_flag){
answer.push_back(sum_quotient);
answer.push_back(sub_p);
break;
}

std::string temppp(p.digits()-(sub_p.digits()),'0');
temppp="1"+temppp;
tmpx2=temppp;

if(sum_quotient.digits()==0)
sum_quotient=tmp_quotient*tmpx2;
else
sum_quotient=sum_quotient+(tmp_quotient*tmpx2);

tmpx1=tmpx1*tmpx2;
p=p-tmpx1;

}

if(this_sign == false && q_sign == false){
answer[0].positive = true;
}

else if(this_sign == false || q_sign == false){
if( this -> is_even() && q.is_even())
answer[0].positive = false;
else{
answer[0] = answer[0] + Bigint("1");
answer[0].positive = false;
}
}

else{
answer[0].positive = true;
}

return answer;

}

std::vector<Bigint> Bigint::operator/(Bigint q){
try{
return divide(q);
}
catch(const char* msg){
std::cerr << msg << std::endl;
std::terminate();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If an exception is thrown, is it user catchable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, user won't catch it. It is caught in the division function interface only and printed on screen as shown above.
It is a little tricky and i don't know how to handle the exception, so please can you clarify more.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throwing the error is enough, you dont have to catch it.

If division by zero occurs, let the user deal with it.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My solution is to make an inheriting class to std::runtime_error named arithmetic_error and throw it with "Divide by zero" when divided by zero just like Java does. Like this function for checking:

void check_divisor(Bigint const &b)
{
    if (b == 0)
        throw Bigint::arithmetic_error("Divide by zero");
}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@titansnow I agree. That would be better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, i will try it.

}


}


//Power

Bigint Bigint::pow(int const &power, std::map<int, Bigint> &lookup)
{
if (power == 1) return *this;
Expand Down Expand Up @@ -392,6 +591,7 @@ std::ostream &operator<<(std::ostream &out, Bigint a)
return out;
}


std::istream &operator>>(std::istream &in, Bigint &a)
{
std::string str;
Expand Down
7 changes: 7 additions & 0 deletions src/bigint.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ class Bigint
Bigint operator*(long long const &);
Bigint &operator*=(int const &);

//Division
bool is_even();
private:
std::vector<Bigint> divide(Bigint q); // returns quotient(index[0]) and remainder(index[1]).
public:
std::vector<Bigint> operator/(Bigint q); // interface for divide() function.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does division return a vector?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because it returns both quotient and remainder.

Copy link
Owner

@kasparsklavins kasparsklavins Mar 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

divide() can stay as is, but / operator should return just Bigint so syntax like this would work a * b / c.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there can be both operator/ and operator% wrapper divide and split the results, return what is needed, just like killing two birds with one stone. By the way, I think you algorithm is so cool 👍 @MahmoudRizk

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes make it two separate operators.

Also, could you also describe how the algorithm works and why it works?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, i will separate it.
About the Algorithm it is called "Double division algorithm", you can check this link http://www.doubledivision.org/

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the link. That is an awesome algorithm indeed.

//Compare
bool operator<(const Bigint &) const;
bool operator>(const Bigint &) const;
Expand Down Expand Up @@ -69,6 +75,7 @@ class Bigint
int segment_length(int) const;
Bigint pow(int const &, std::map<int, Bigint> &);
int compare(Bigint const &) const; //0 a == b, -1 a < b, 1 a > b
Bigint sub_number(Bigint &p, Bigint &q); // used in the division function
};

Bigint abs(Bigint);
Expand Down