I have implemented an elementary positive integer class that supports addition, subtraction, and multiplication for an arbitrary number of digits using a singly linked list.
class Node
{
Node ref_prev_node;
int value;
Node(int n)
{
this.ref_prev_node = null;
this.value = n;
}
}
class MyBigInt
{
private Node ref_tail_node;
private int size;
private MyBigInt()
{
this.ref_tail_node = null;
this.size = 0;
}
MyBigInt(String s)
{
if (s.length() == 0)
{
throw new IllegalStateException("Can't construct MyBigInt using an empty string!");
}
Node ref_old_node = null;
for (int i = s.length() - 1; i >= 0; --i)
{
if (!(Character.isDigit(s.charAt(i))))
{
throw new IllegalStateException("Can't construct MyBigInt using non-digit characters!");
}
Node ref_new_node = new Node((int) (s.charAt(i) - '0'));
if (i == s.length() - 1)
{
this.ref_tail_node = ref_new_node;
}
else
{
ref_old_node.ref_prev_node = ref_new_node;
}
ref_old_node = ref_new_node;
++(this.size);
}
this.trim_leading_zeroes();
}
MyBigInt add(MyBigInt n)
{
this.trim_leading_zeroes();
n.trim_leading_zeroes();
Node ref_curr_node_1 = this.ref_tail_node;
Node ref_curr_node_2 = n.ref_tail_node;
int carry = 0;
MyBigInt ans = new MyBigInt();
Node ref_old_node = null;
while ((ref_curr_node_1 != null) || (ref_curr_node_2 != null) || (carry != 0))
{
int sum = (ref_curr_node_1 == null ? 0 : ref_curr_node_1.value) + (ref_curr_node_2 == null ? 0 : ref_curr_node_2.value) + carry;
carry = sum / 10;
Node ref_new_node = new Node(sum % 10);
if (ans.ref_tail_node == null)
{
ans.ref_tail_node = ref_new_node;
}
else
{
ref_old_node.ref_prev_node = ref_new_node;
}
ref_old_node = ref_new_node;
if (ref_curr_node_1 != null)
{
ref_curr_node_1 = ref_curr_node_1.ref_prev_node;
}
if (ref_curr_node_2 != null)
{
ref_curr_node_2 = ref_curr_node_2.ref_prev_node;
}
++(ans.size);
}
return ans;
}
private void insert_trailing_zeroes(int number_of_zeroes)
{
if (number_of_zeroes > 0)
{
Node ref_new_tail_node = null;
Node ref_old_node = null;
for (int i = 0; i < number_of_zeroes; ++i)
{
Node ref_new_node = new Node(0);
if (i == 0)
{
ref_new_tail_node = ref_new_node;
}
else
{
ref_old_node.ref_prev_node = ref_new_node;
}
ref_old_node = ref_new_node;
}
ref_old_node.ref_prev_node = this.ref_tail_node;
this.ref_tail_node = ref_new_tail_node;
this.size += number_of_zeroes;
}
}
boolean is_greater_than_or_equal_to(MyBigInt n)
{
this.trim_leading_zeroes();
n.trim_leading_zeroes();
if (this.size > n.size)
{
return true;
}
else if (this.size < n.size)
{
return false;
}
else
{
int digit_1 = -1;
int digit_2 = -1;
Node ref_curr_node_1 = this.ref_tail_node;
Node ref_curr_node_2 = n.ref_tail_node;
while (ref_curr_node_1 != null)
{
if (ref_curr_node_1.value != ref_curr_node_2.value)
{
digit_1 = ref_curr_node_1.value;
digit_2 = ref_curr_node_2.value;
}
ref_curr_node_1 = ref_curr_node_1.ref_prev_node;
ref_curr_node_2 = ref_curr_node_2.ref_prev_node;
}
return digit_1 >= digit_2;
}
}
MyBigInt multiply(MyBigInt n)
{
this.trim_leading_zeroes();
n.trim_leading_zeroes();
Node ref_curr_node_2 = n.ref_tail_node;
MyBigInt ans = new MyBigInt("0");
for (int i = 0; ref_curr_node_2 != null; ++i)
{
MyBigInt temp = this.multiply_single_digit(ref_curr_node_2.value);
temp.insert_trailing_zeroes(i);
ans = ans.add(temp);
ref_curr_node_2 = ref_curr_node_2.ref_prev_node;
}
return ans;
}
private MyBigInt multiply_single_digit(int digit)
{
Node ref_curr_node = this.ref_tail_node;
int carry = 0;
MyBigInt ans = new MyBigInt();
Node ref_old_node = null;
while ((ref_curr_node != null) || (carry != 0))
{
int product = ((ref_curr_node == null ? 0 : ref_curr_node.value) * digit) + carry;
carry = product / 10;
Node ref_new_node = new Node(product % 10);
if (ans.ref_tail_node == null)
{
ans.ref_tail_node = ref_new_node;
}
else
{
ref_old_node.ref_prev_node = ref_new_node;
}
ref_old_node = ref_new_node;
if (ref_curr_node != null)
{
ref_curr_node = ref_curr_node.ref_prev_node;
}
++(ans.size);
}
ans.trim_leading_zeroes();
return ans;
}
MyBigInt subtract(MyBigInt n)
{
this.trim_leading_zeroes();
n.trim_leading_zeroes();
if (!(this.is_greater_than_or_equal_to(n)))
{
throw new IllegalStateException("Can't subtract larger MyBigInt from smaller MyBigInt!");
}
Node ref_curr_node_1 = this.ref_tail_node;
Node ref_curr_node_2 = n.ref_tail_node;
int carry = 0;
MyBigInt ans = new MyBigInt();
Node ref_old_node = null;
while ((ref_curr_node_1 != null) || (ref_curr_node_2 != null))
{
int diff = ref_curr_node_1.value - (ref_curr_node_2 == null ? 0 : ref_curr_node_2.value) - carry;
carry = (diff < 0) ? 1 : 0;
diff = (diff < 0) ? (diff + 10) : diff;
Node ref_new_node = new Node(diff);
if (ans.ref_tail_node == null)
{
ans.ref_tail_node = ref_new_node;
}
else
{
ref_old_node.ref_prev_node = ref_new_node;
}
ref_old_node = ref_new_node;
if (ref_curr_node_1 != null)
{
ref_curr_node_1 = ref_curr_node_1.ref_prev_node;
}
if (ref_curr_node_2 != null)
{
ref_curr_node_2 = ref_curr_node_2.ref_prev_node;
}
++(ans.size);
}
ans.trim_leading_zeroes();
return ans;
}
String to_string()
{
String s = new String();
Node ref_curr_node = this.ref_tail_node;
while (ref_curr_node != null)
{
s = ref_curr_node.value + s;
ref_curr_node = ref_curr_node.ref_prev_node;
}
if (this.size != s.length())
{
throw new IllegalStateException("The 'size' data member of this MyBigInt does not represent its actual size!");
}
return s;
}
private void trim_leading_zeroes()
{
if (this.size > 0)
{
// If there is only node, then that node will be considered as the
// leftmost node, even if it is zero. Else, we will look for the
// leftmost non-zero node.
Node ref_leftmost_node = this.ref_tail_node;
int size_leftmost_node = 1;
Node ref_curr_node = this.ref_tail_node.ref_prev_node;
for (int i = 2; ref_curr_node != null; ++i)
{
if (ref_curr_node.value > 0)
{
ref_leftmost_node = ref_curr_node;
size_leftmost_node = i;
}
ref_curr_node = ref_curr_node.ref_prev_node;
}
ref_leftmost_node.ref_prev_node = null;
this.size = size_leftmost_node;
}
}
}