Browse Source

Add addition and subtraction to `BigInt`

pull/8/head
Anton Tarasenko 2 years ago
parent
commit
5616bc817e
  1. 113
      sources/Data/Database/BigInt.uc
  2. 84
      sources/Data/Database/Tests/TEST_BigInt.uc

113
sources/Data/Database/BigInt.uc

@ -23,6 +23,13 @@
class BigInt extends AcediaObject class BigInt extends AcediaObject
dependson(MathAPI); dependson(MathAPI);
enum BigIntCompareResult
{
BICR_Less,
BICR_Equal,
BICR_Greater
};
var private bool negative; var private bool negative;
// Digits array, from least to most significant: // Digits array, from least to most significant:
// For example, for 13524: // For example, for 13524:
@ -70,7 +77,7 @@ private static function BigInt CreateMinimalNegative()
// Removes unnecessary zeroes from leading digit positions `digits`. // Removes unnecessary zeroes from leading digit positions `digits`.
// Does not change contained value. // Does not change contained value.
private final static function TrimLeadingZeroes() private final function TrimLeadingZeroes()
{ {
local int i, zeroesToRemove; local int i, zeroesToRemove;
@ -188,6 +195,53 @@ public final static function BigInt FromDecimal_S(string value)
return result; return result;
} }
public function BigIntCompareResult _compareModulus(BigInt other)
{
local int i;
local array<byte> otherDigits;
otherDigits = other.digits;
if (digits.length == otherDigits.length)
{
for (i = digits.length - 1; i >= 0; i -= 1)
{
if (digits[i] < otherDigits[i]) {
return BICR_Less;
}
if (digits[i] > otherDigits[i]) {
return BICR_Greater;
}
}
return BICR_Equal;
}
if (digits.length < otherDigits.length) {
return BICR_Less;
}
return BICR_Greater;
}
public function BigIntCompareResult Compare(BigInt other)
{
local BigIntCompareResult resultForModulus;
if (negative && !other.negative) {
return BICR_Less;
}
if (!negative && other.negative) {
return BICR_Greater;
}
resultForModulus = _compareModulus(other);
if (resultForModulus == BICR_Equal) {
return BICR_Equal;
}
if ( (negative && (resultForModulus == BICR_Greater))
|| (!negative && (resultForModulus == BICR_Less)) )
{
return BICR_Less;
}
return BICR_Greater;
}
private function _add(BigInt other) private function _add(BigInt other)
{ {
local int i; local int i;
@ -201,6 +255,9 @@ private function _add(BigInt other)
if (digits.length < otherDigits.length) { if (digits.length < otherDigits.length) {
digits.length = otherDigits.length; digits.length = otherDigits.length;
} }
else {
otherDigits.length = digits.length;
}
carry = 0; carry = 0;
for (i = 0; i < digits.length; i += 1) for (i = 0; i < digits.length; i += 1)
{ {
@ -211,11 +268,65 @@ private function _add(BigInt other)
if (carry > 0) { if (carry > 0) {
digits[digits.length] = carry; digits[digits.length] = carry;
} }
// No leading zeroes can be created here, so no need to trim
}
private function _sub(BigInt other)
{
local int i;
local int carry, nextDigit;
local array<byte> minuendDigits, subtrahendDigits;
local BigIntCompareResult resultForModulus;
if (other == none) {
return;
}
resultForModulus = _compareModulus(other);
if (resultForModulus == BICR_Equal)
{
negative = false;
digits.length = 1;
digits[0] = 0;
return;
}
if (resultForModulus == BICR_Less)
{
negative = !negative;
minuendDigits = other.digits;
subtrahendDigits = digits;
}
else
{
minuendDigits = digits;
subtrahendDigits = other.digits;
}
digits.length = minuendDigits.length;
subtrahendDigits.length = minuendDigits.length;
carry = 0;
for (i = 0; i < digits.length; i += 1)
{
nextDigit = int(minuendDigits[i]) - int(subtrahendDigits[i]) + carry;
if (nextDigit < 0)
{
nextDigit += 10;
carry = -1;
}
else {
carry = 0;
}
digits[i] = nextDigit;
}
TrimLeadingZeroes();
} }
public function BigInt Add(BigInt other) public function BigInt Add(BigInt other)
{ {
if (negative == other.negative) {
_add(other); _add(other);
}
else {
_sub(other);
}
return self; return self;
} }

84
sources/Data/Database/Tests/TEST_BigInt.uc

@ -27,10 +27,10 @@ protected static function TESTS()
Test_Creating(); Test_Creating();
// So here we nee to test `ToText()` methods separately // So here we nee to test `ToText()` methods separately
Test_ToText(); Test_ToText();
Test_LeadingZeroes(); Context("Testing basic arithmetic operations on `BigInt`s.");
//Test_AddingValues(); Test_AddingValues();
} }
// TODO: leading zeroes
protected static function Test_Creating() protected static function Test_Creating()
{ {
Context("Testing creation of `BigInt`s."); Context("Testing creation of `BigInt`s.");
@ -93,11 +93,81 @@ protected static function Test_ToText()
.ToString() == "-9827657892365923510176386357863078603212901078175829"); .ToString() == "-9827657892365923510176386357863078603212901078175829");
} }
/*protected static function Test_AddingValues() protected static function Test_AddingValues()
{
SubTest_AddingSameSignValues();
SubTest_AddingDifferentSignValues();
}
protected static function SubTest_AddingSameSignValues()
{
local BigInt main, addition;
Issue("Two positive `BigInt`s are incorrectly added.");
main = class'BigInt'.static.FromDecimal_S("927641962323462271784269213864");
addition = class'BigInt'.static.FromDecimal_S("16324234842947239847239239");
main.Add(addition);
TEST_ExpectTrue(main.ToString() == "927658286558305219024116453103");
main = class'BigInt'.static.FromDecimal_S("16324234842947239847239239");
addition = class'BigInt'.static
.FromDecimal_S("927641962323462271784269213864");
main.Add(addition);
TEST_ExpectTrue(main.ToString() == "927658286558305219024116453103");
main = class'BigInt'.static.FromDecimal_S("728965872936589276");
addition = class'BigInt'.static.FromDecimal_S("728965872936589276");
main.Add(addition);
TEST_ExpectTrue(main.ToString() == "1457931745873178552");
Issue("Two negative `BigInt`s are incorrectly added.");
main = class'BigInt'.static.FromDecimal_S("-27641962323462271784269213864");
addition = class'BigInt'.static.FromDecimal_S("-6324234842947239847239239");
main.Add(addition);
TEST_ExpectTrue(main.ToString() == "-27648286558305219024116453103");
main = class'BigInt'.static.FromDecimal_S("-16324234842947239847239239");
addition = class'BigInt'.static
.FromDecimal_S("-927641962323462271784269213864");
main.Add(addition);
TEST_ExpectTrue(main.ToString() == "-927658286558305219024116453103");
main = class'BigInt'.static.FromDecimal_S("-728965872936589276");
addition = class'BigInt'.static.FromDecimal_S("-728965872936589276");
main.Add(addition);
TEST_ExpectTrue(main.ToString() == "-1457931745873178552");
}
protected static function SubTest_AddingDifferentSignValues()
{ {
Context("Testing adding values to `BigInt`"); local BigInt main, addition;
Issue("`JSONPointer` is incorrectly extracted.");
}*/ Issue("Negative `BigInt`s is incorrectly added to positive one.");
main = class'BigInt'.static.FromDecimal_S("927641962323462271784269213864");
addition = class'BigInt'.static.FromDecimal_S("-1632423484294239847239239");
main.Add(addition);
TEST_ExpectTrue(main.ToString() == "927640329899977977544421974625");
main = class'BigInt'.static.FromDecimal_S("16324234842947239847239239");
addition = class'BigInt'.static
.FromDecimal_S("-927641962323462271784269213864");
main.Add(addition);
TEST_ExpectTrue(main.ToString() == "-927625638088619324544421974625");
main = class'BigInt'.static.FromDecimal_S("728965872936589276");
addition = class'BigInt'.static.FromDecimal_S("-728965872936589276");
main.Add(addition);
TEST_ExpectTrue(main.ToString() == "0");
Issue("Positive `BigInt`s is incorrectly added to negative one.");
main = class'BigInt'.static.FromDecimal_S("-27641962323462271784269213864");
addition = class'BigInt'.static.FromDecimal_S("6324234842947239847239239");
main.Add(addition);
TEST_ExpectTrue(main.ToString() == "-27635638088619324544421974625");
main = class'BigInt'.static.FromDecimal_S("-16324234842947239847239239");
addition = class'BigInt'.static
.FromDecimal_S("927641962323462271784269213864");
main.Add(addition);
TEST_ExpectTrue(main.ToString() == "927625638088619324544421974625");
main = class'BigInt'.static.FromDecimal_S("-728965872936589276");
addition = class'BigInt'.static.FromDecimal_S("728965872936589276");
main.Add(addition);
TEST_ExpectTrue(main.ToString() == "0");
}
defaultproperties defaultproperties
{ {

Loading…
Cancel
Save