|
|
@ -1,7 +1,8 @@ |
|
|
|
/** |
|
|
|
/** |
|
|
|
* A simple big integer implementation, mostly to allow Acedia's databases to |
|
|
|
* Author: dkanus |
|
|
|
* store integers of arbitrary size. |
|
|
|
* Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore |
|
|
|
* Copyright 2022 Anton Tarasenko |
|
|
|
* License: GPL |
|
|
|
|
|
|
|
* Copyright 2022-2023 Anton Tarasenko |
|
|
|
*------------------------------------------------------------------------------ |
|
|
|
*------------------------------------------------------------------------------ |
|
|
|
* This file is part of Acedia. |
|
|
|
* This file is part of Acedia. |
|
|
|
* |
|
|
|
* |
|
|
@ -19,41 +20,22 @@ |
|
|
|
* along with Acedia. If not, see <https://www.gnu.org/licenses/>. |
|
|
|
* along with Acedia. If not, see <https://www.gnu.org/licenses/>. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
class BigInt extends AcediaObject |
|
|
|
class BigInt extends AcediaObject |
|
|
|
dependson(MathAPI); |
|
|
|
dependson(MathApi); |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// A simple big integer implementation. |
|
|
|
* # `BigInt` |
|
|
|
/// |
|
|
|
* |
|
|
|
/// [`BigInt`]'s main purpose is to allow Acedia's databases to store integers of arbitrary size. |
|
|
|
* A simple big integer implementation, mostly to allow Acedia's databases to |
|
|
|
/// It can be used for long arithmetic computations, but it was mainly meant as a players' |
|
|
|
* store integers of arbitrary size. It can be used for long arithmetic |
|
|
|
/// statistics counter and, therefore, not optimized for performing large amount of operations. |
|
|
|
* computations, but it was mainly meant as a players' statistics counter and, |
|
|
|
|
|
|
|
* therefore, not optimized for performing large amount of operations. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* ## Usage |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* `BigInt` can be created from both `int` and decimal `BaseText`/`string` |
|
|
|
|
|
|
|
* representation, preferably by `MathAPI` (`_.math.`) methods |
|
|
|
|
|
|
|
* `ToBigInt()`/`MakeBigInt()`. |
|
|
|
|
|
|
|
* Then it can be combined either directly with other `BigInt` or with |
|
|
|
|
|
|
|
* `int`/`BaseText`/`string` through available arithmetic operations. |
|
|
|
|
|
|
|
* To make use of stored value one can convert it back into either `int` or |
|
|
|
|
|
|
|
* decimal `BaseText`/`string` representation. |
|
|
|
|
|
|
|
* Newly allocated `BigInt` is guaranteed to hold `0` as value. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// [`BigInt`] data as a struct - meant to be used to store [`BigInt`]'s values inside |
|
|
|
* `BigInt` data as a `struct` - meant to be used to store `BigInt`'s values |
|
|
|
/// the local databases. |
|
|
|
* inside the local databases. |
|
|
|
struct BigIntData { |
|
|
|
*/ |
|
|
|
|
|
|
|
struct BigIntData |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var bool negative; |
|
|
|
var bool negative; |
|
|
|
var array<byte> digits; |
|
|
|
var array<byte> digits; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Result of comparison for [`BigInt`]s with each other. |
|
|
|
* Used to represent a result of comparison for `BigInt`s with each other. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
enum BigIntCompareResult |
|
|
|
enum BigIntCompareResult |
|
|
|
{ |
|
|
|
{ |
|
|
|
BICR_Less, |
|
|
|
BICR_Less, |
|
|
@ -61,60 +43,60 @@ enum BigIntCompareResult |
|
|
|
BICR_Greater |
|
|
|
BICR_Greater |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// Does stored `BigInt` has negative sign? |
|
|
|
/// Does stored [`BigInt`] have a negative sign? |
|
|
|
var private bool negative; |
|
|
|
var private bool negative; |
|
|
|
// Digits array, from least to most significant. For example, for 13524: |
|
|
|
/// Digits array, from least to most significant. For example, for 13524: |
|
|
|
// `digits[0] = 4` |
|
|
|
/// |
|
|
|
// `digits[1] = 2` |
|
|
|
/// ``` |
|
|
|
// `digits[2] = 5` |
|
|
|
/// `digits[0] = 4` |
|
|
|
// `digits[3] = 3` |
|
|
|
/// `digits[1] = 2` |
|
|
|
// `digits[4] = 1` |
|
|
|
/// `digits[2] = 5` |
|
|
|
// Valid `BigInt` should not have this array empty: zero should be |
|
|
|
/// `digits[3] = 3` |
|
|
|
// represented by an array with a single `0`-element. |
|
|
|
/// `digits[4] = 1` |
|
|
|
// This isn't a most efficient representation for `BigInt`, but it's easy |
|
|
|
/// ``` |
|
|
|
// to convert to and from decimal representation. |
|
|
|
/// |
|
|
|
// INVARIANT: this array must not have leading (in the sense of significance) |
|
|
|
/// Valid [`BigInt`] should not have this array empty: zero should be represented by an array with |
|
|
|
// zeroes. That is, last element of the array should not be a `0`. The only |
|
|
|
/// a single `0`-element. |
|
|
|
// exception if if stored value is `0`, then `digits` must consist of a single |
|
|
|
/// This isn't a most efficient representation for [`BigInt`], but it's easy to convert to and from |
|
|
|
// `0` element. |
|
|
|
/// decimal representation. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// # Invariants |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// This array must not have leading (in the sense of significance) zeroes. |
|
|
|
|
|
|
|
/// That is, last element of the array should not be a `0`. |
|
|
|
|
|
|
|
/// The only exception if if stored value is `0`, then `digits` must consist of |
|
|
|
|
|
|
|
/// a single `0` element. |
|
|
|
var private array<byte> digits; |
|
|
|
var private array<byte> digits; |
|
|
|
|
|
|
|
|
|
|
|
// Constants useful for converting `BigInt` back to `int`, while avoiding |
|
|
|
/// Constants useful for converting [`BigInt`] back to [`int`], while avoiding overflow. |
|
|
|
// overflow. |
|
|
|
/// We can add less digits than that without any fear of overflow. |
|
|
|
// We can add less digits than that without any fear of overflow |
|
|
|
|
|
|
|
const DIGITS_IN_MAX_INT = 10; |
|
|
|
const DIGITS_IN_MAX_INT = 10; |
|
|
|
// Maximum `int` value is `2147483647`, so in case most significant digit |
|
|
|
/// Maximum [`int`] value is `2147483647`, so in case most significant digit is 10th and is `2` |
|
|
|
// is 10th and is `2` (so number has a form of "2xxxxxxxxx"), to check for |
|
|
|
/// (so number has a form of `2xxxxxxxxx`), to check for overflow we only need to compare |
|
|
|
// overflow we only need to compare combination of the rest of the digits with |
|
|
|
/// combination of the rest of the digits with this constant. |
|
|
|
// this constant. |
|
|
|
|
|
|
|
const ALMOST_MAX_INT = 147483647; |
|
|
|
const ALMOST_MAX_INT = 147483647; |
|
|
|
// To add last digit we add/subtract that digit multiplied by this value. |
|
|
|
/// To add last digit we add/subtract that digit multiplied by this value. |
|
|
|
const LAST_DIGIT_ORDER = 1000000000; |
|
|
|
const LAST_DIGIT_ORDER = 1000000000; |
|
|
|
|
|
|
|
|
|
|
|
protected function Constructor() |
|
|
|
protected function Constructor() { |
|
|
|
{ |
|
|
|
|
|
|
|
SetZero(); |
|
|
|
SetZero(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected function Finalizer() |
|
|
|
protected function Finalizer() { |
|
|
|
{ |
|
|
|
|
|
|
|
negative = false; |
|
|
|
negative = false; |
|
|
|
digits.length = 0; |
|
|
|
digits.length = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Auxiliary method to set current value to zero |
|
|
|
// Auxiliary method to set current value to zero |
|
|
|
private function BigInt SetZero() |
|
|
|
private function SetZero() { |
|
|
|
{ |
|
|
|
|
|
|
|
negative = false; |
|
|
|
negative = false; |
|
|
|
digits.length = 1; |
|
|
|
digits.length = 1; |
|
|
|
digits[0] = 0; |
|
|
|
digits[0] = 0; |
|
|
|
return self; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Minimal `int` value `-2,147,483,648` is somewhat of a pain to handle, so |
|
|
|
// Minimal [`int`] value `-2,147,483,648` is somewhat of a pain to handle, so just use this |
|
|
|
// just use this auxiliary pre-made constructor for it |
|
|
|
// auxiliary pre-made constructor for it |
|
|
|
private function BigInt SetMinimalNegative() |
|
|
|
private function SetMinimalNegative() { |
|
|
|
{ |
|
|
|
|
|
|
|
negative = true; |
|
|
|
negative = true; |
|
|
|
digits.length = 10; |
|
|
|
digits.length = 10; |
|
|
|
digits[0] = 8; |
|
|
|
digits[0] = 8; |
|
|
@ -127,20 +109,17 @@ private function BigInt SetMinimalNegative() |
|
|
|
digits[7] = 4; |
|
|
|
digits[7] = 4; |
|
|
|
digits[8] = 1; |
|
|
|
digits[8] = 1; |
|
|
|
digits[9] = 2; |
|
|
|
digits[9] = 2; |
|
|
|
return self; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 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 function TrimLeadingZeroes() |
|
|
|
private final function TrimLeadingZeroes() { |
|
|
|
{ |
|
|
|
|
|
|
|
local int i, zeroesToRemove; |
|
|
|
local int i, zeroesToRemove; |
|
|
|
|
|
|
|
|
|
|
|
// Find how many leading zeroes there is. |
|
|
|
// Finds how many leading zeroes there is. |
|
|
|
// Since `digits` stores digits from least to most significant, we need |
|
|
|
// Since `digits` stores digits from least to most significant, we need to check from the end of |
|
|
|
// to check from the end of `digits` array. |
|
|
|
// `digits` array. |
|
|
|
for (i = digits.length - 1; i >= 0; i -= 1) |
|
|
|
for (i = digits.length - 1; i >= 0; i -= 1) { |
|
|
|
{ |
|
|
|
|
|
|
|
if (digits[i] != 0) { |
|
|
|
if (digits[i] != 0) { |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
@ -155,142 +134,123 @@ private final function TrimLeadingZeroes() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Changes current value of [`BigInt`] to given value. |
|
|
|
* Changes current value of `BigInt` to given `BigInt` value. |
|
|
|
public final function Set(BigInt value) |
|
|
|
* |
|
|
|
|
|
|
|
* @param value New value of the caller `BigInt`. If `none` is given, |
|
|
|
|
|
|
|
* method does nothing. |
|
|
|
|
|
|
|
* @return Self-reference to allow for method chaining. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final function BigInt Set(BigInt value) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
if (value == none) { |
|
|
|
if (value != none) { |
|
|
|
return self; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
value.TrimLeadingZeroes(); |
|
|
|
value.TrimLeadingZeroes(); |
|
|
|
digits = value.digits; |
|
|
|
digits = value.digits; |
|
|
|
negative = value.negative; |
|
|
|
negative = value.negative; |
|
|
|
return self; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Changes current value of [`BigInt`] to given value. |
|
|
|
* Changes current value of `BigInt` to given `int` value `value`. |
|
|
|
public final function SetInt(int value) { |
|
|
|
* |
|
|
|
local MathApi.IntegerDivisionResult divisionResult; |
|
|
|
* Cannot fail. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param value New value of the caller `BigInt`. |
|
|
|
|
|
|
|
* @return Self-reference to allow for method chaining. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final function BigInt SetInt(int value) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local MathAPI.IntegerDivisionResult divisionResult; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
negative = false; |
|
|
|
negative = false; |
|
|
|
digits.length = 0; |
|
|
|
digits.length = 0; |
|
|
|
if (value < 0) |
|
|
|
if (value < 0) { |
|
|
|
{ |
|
|
|
// Treat special case of minimal [`int`] value `-2,147,483,648` that |
|
|
|
// Treat special case of minimal `int` value `-2,147,483,648` that |
|
|
|
// won't fit into positive [`int`] as special and use pre-made |
|
|
|
// won't fit into positive `int` as special and use pre-made |
|
|
|
|
|
|
|
// specialized constructor `CreateMinimalNegative()` |
|
|
|
// specialized constructor `CreateMinimalNegative()` |
|
|
|
if (value < -MaxInt) { |
|
|
|
if (value < -maxInt) { |
|
|
|
return SetMinimalNegative(); |
|
|
|
SetMinimalNegative(); |
|
|
|
} |
|
|
|
return; |
|
|
|
else |
|
|
|
} else { |
|
|
|
{ |
|
|
|
|
|
|
|
negative = true; |
|
|
|
negative = true; |
|
|
|
value *= -1; |
|
|
|
value *= -1; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (value == 0) { |
|
|
|
if (value == 0) { |
|
|
|
digits[0] = 0; |
|
|
|
digits[0] = 0; |
|
|
|
} |
|
|
|
} else { |
|
|
|
else |
|
|
|
while (value > 0) { |
|
|
|
{ |
|
|
|
|
|
|
|
while (value > 0) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
divisionResult = __().math.IntegerDivision(value, 10); |
|
|
|
divisionResult = __().math.IntegerDivision(value, 10); |
|
|
|
value = divisionResult.quotient; |
|
|
|
value = divisionResult.quotient; |
|
|
|
digits[digits.length] = divisionResult.remainder; |
|
|
|
digits[digits.length] = divisionResult.remainder; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
TrimLeadingZeroes(); |
|
|
|
TrimLeadingZeroes(); |
|
|
|
return self; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Changes current value of [`BigInt`] to the value, given by decimal representation. |
|
|
|
* Changes current value of `BigInt` to the value, given by decimal |
|
|
|
/// |
|
|
|
* representation inside `value` argument. |
|
|
|
/// If `none` or invalid decimal representation (digits only, possibly with leading sign) is given |
|
|
|
* |
|
|
|
/// as an argument, caller's value won't change. |
|
|
|
* If invalid decimal representation (digits only, possibly with leading sign) |
|
|
|
/// Returns `true` in case of success and `false` otherwise. |
|
|
|
* is given - behavior is undefined. Otherwise cannot fail. |
|
|
|
public final function bool SetDecimal(BaseText value) { |
|
|
|
* |
|
|
|
|
|
|
|
* @param value New value of the caller `BigInt`, given by decimal |
|
|
|
|
|
|
|
* its representation. If `none` is given, method does nothing. |
|
|
|
|
|
|
|
* @return Self-reference to allow for method chaining. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final function BigInt SetDecimal(BaseText value) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local int i; |
|
|
|
local int i; |
|
|
|
local byte nextDigit; |
|
|
|
local byte nextDigit; |
|
|
|
|
|
|
|
local bool newNegative; |
|
|
|
|
|
|
|
local array<byte> newDigits; |
|
|
|
local Parser parser; |
|
|
|
local Parser parser; |
|
|
|
local Basetext.Character nextCharacter; |
|
|
|
local Basetext.Character nextCharacter; |
|
|
|
|
|
|
|
|
|
|
|
if (value == none) { |
|
|
|
if (value == none) { |
|
|
|
return none; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
parser = value.Parse(); |
|
|
|
parser = value.Parse(); |
|
|
|
negative = parser.Match(P("-")).Ok(); |
|
|
|
newNegative = ParseSign(parser); |
|
|
|
if (!parser.Ok()) { |
|
|
|
|
|
|
|
parser.R().Match(P("+")).Ok(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Reset to valid state whether sign was consumed or not |
|
|
|
// Reset to valid state whether sign was consumed or not |
|
|
|
parser.Confirm(); |
|
|
|
parser.Confirm(); |
|
|
|
parser.R(); |
|
|
|
parser.R(); |
|
|
|
// Reset current value |
|
|
|
newDigits.length = parser.GetRemainingLength(); |
|
|
|
digits.length = 0; |
|
|
|
|
|
|
|
digits.length = parser.GetRemainingLength(); |
|
|
|
|
|
|
|
// Parse new one |
|
|
|
// Parse new one |
|
|
|
i = digits.length - 1; |
|
|
|
i = newDigits.length - 1; |
|
|
|
while (!parser.HasFinished()) |
|
|
|
while (!parser.HasFinished()){ |
|
|
|
{ |
|
|
|
|
|
|
|
// This should not happen, but just in case |
|
|
|
// This should not happen, but just in case |
|
|
|
if (i < 0) { |
|
|
|
if (i < 0) { |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
parser.MCharacter(nextCharacter); |
|
|
|
parser.MCharacter(nextCharacter); |
|
|
|
nextDigit = Clamp(__().text.CharacterToInt(nextCharacter), 0, 9); |
|
|
|
nextDigit = __().text.CharacterToInt(nextCharacter, 10); |
|
|
|
digits[i] = nextDigit; |
|
|
|
if (nextDigit < 0) { |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
newDigits[i] = nextDigit; |
|
|
|
i -= 1; |
|
|
|
i -= 1; |
|
|
|
} |
|
|
|
} |
|
|
|
parser.FreeSelf(); |
|
|
|
parser.FreeSelf(); |
|
|
|
|
|
|
|
digits = newDigits; |
|
|
|
|
|
|
|
negative = newNegative; |
|
|
|
TrimLeadingZeroes(); |
|
|
|
TrimLeadingZeroes(); |
|
|
|
return self; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
// Tries to parse either `+` or `-` and returns `true` iff it parsed `-`. |
|
|
|
* Changes current value of `BigInt` to the value, given by decimal |
|
|
|
// If neither got parsed, `parser` will enter failed state. |
|
|
|
* representation inside `value` argument. |
|
|
|
// Assumes `parser` isn't `none`. |
|
|
|
* |
|
|
|
private final function bool ParseSign(Parser parser) { |
|
|
|
* If invalid decimal representation (digits only, possibly with leading sign) |
|
|
|
parser.Match(P("-")); |
|
|
|
* is given - behavior is undefined. Otherwise cannot fail. |
|
|
|
negative = parser.Ok(); |
|
|
|
* |
|
|
|
if (parser.Ok()) { |
|
|
|
* @param value New value of the caller `BigInt`, given by decimal |
|
|
|
negative = true; |
|
|
|
* its representation. |
|
|
|
} |
|
|
|
* @return Self-reference to allow for method chaining. |
|
|
|
else { |
|
|
|
*/ |
|
|
|
parser.R(); |
|
|
|
public final function BigInt SetDecimal_S(string value) |
|
|
|
parser.Match(P("+")); |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
return negative; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Changes current value of [`BigInt`] to the value, given by decimal representation. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// If invalid decimal representation (digits only, possibly with leading sign) is given as |
|
|
|
|
|
|
|
/// an argument, caller's value won't change. |
|
|
|
|
|
|
|
/// Returns `true` in case of success and `false` otherwise. |
|
|
|
|
|
|
|
public final function bool SetDecimal_S(string value) { |
|
|
|
|
|
|
|
local bool result; |
|
|
|
local MutableText wrapper; |
|
|
|
local MutableText wrapper; |
|
|
|
|
|
|
|
|
|
|
|
wrapper = __().text.FromStringM(value); |
|
|
|
wrapper = __().text.FromStringM(value); |
|
|
|
SetDecimal(wrapper); |
|
|
|
result = SetDecimal(wrapper); |
|
|
|
wrapper.FreeSelf(); |
|
|
|
wrapper.FreeSelf(); |
|
|
|
return self; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Auxiliary method for comparing two `BigInt`s by their absolute value. |
|
|
|
// Auxiliary method for comparing two [`BigInt`]s by their absolute value. |
|
|
|
private function BigIntCompareResult _compareAbsolute(BigInt other) |
|
|
|
private function BigIntCompareResult _compareAbsolute(BigInt other) { |
|
|
|
{ |
|
|
|
|
|
|
|
local int i; |
|
|
|
local int i; |
|
|
|
local array<byte> otherDigits; |
|
|
|
local array<byte> otherDigits; |
|
|
|
|
|
|
|
|
|
|
@ -314,52 +274,32 @@ private function BigIntCompareResult _compareAbsolute(BigInt other) |
|
|
|
return BICR_Greater; |
|
|
|
return BICR_Greater; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Compares caller [`BigInt`] to [`other`]. |
|
|
|
* Compares caller `BigInt` to `other`. |
|
|
|
/// |
|
|
|
* |
|
|
|
/// [`BigIntCompareResult`] representing the result of comparison is returned as a result. |
|
|
|
* @param other Value to compare the caller `BigInt`. |
|
|
|
/// It describes how caller [`BigInt`] relates to the `other`, e.g. if `BICR_Less` was returned then |
|
|
|
* If given reference is `none` - behavior is undefined. |
|
|
|
/// it means that caller [`BigInt`] is smaller that `other`. |
|
|
|
* @return `BigIntCompareResult` representing the result of comparison. |
|
|
|
/// If argument is `none`, then it is considered to be less ([`BICR_Less`]) than caller [`BigInt`]. |
|
|
|
* Returned value describes how caller `BigInt` relates to the `other`, |
|
|
|
public function BigIntCompareResult Compare(BigInt other) { |
|
|
|
* e.g. if `BICR_Less` was returned - it means that caller `BigInt` is |
|
|
|
|
|
|
|
* smaller that `other`. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function BigIntCompareResult Compare(BigInt other) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local BigIntCompareResult resultForModulus; |
|
|
|
local BigIntCompareResult resultForModulus; |
|
|
|
|
|
|
|
|
|
|
|
if (other == none) { |
|
|
|
if (other == none) return BICR_Less; |
|
|
|
return BICR_Less; |
|
|
|
if (negative && !other.negative) return BICR_Less; |
|
|
|
} |
|
|
|
if (!negative && other.negative) return BICR_Greater; |
|
|
|
if (negative && !other.negative) { |
|
|
|
|
|
|
|
return BICR_Less; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!negative && other.negative) { |
|
|
|
|
|
|
|
return BICR_Greater; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
resultForModulus = _compareAbsolute(other); |
|
|
|
resultForModulus = _compareAbsolute(other); |
|
|
|
if (resultForModulus == BICR_Equal) { |
|
|
|
if (resultForModulus == BICR_Equal) return BICR_Equal; |
|
|
|
return BICR_Equal; |
|
|
|
if (negative && (resultForModulus == BICR_Greater)) return BICR_Less; |
|
|
|
} |
|
|
|
if (!negative && (resultForModulus == BICR_Less)) return BICR_Less; |
|
|
|
if ( (negative && (resultForModulus == BICR_Greater)) |
|
|
|
|
|
|
|
|| (!negative && (resultForModulus == BICR_Less)) ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return BICR_Less; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return BICR_Greater; |
|
|
|
return BICR_Greater; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Compares caller [`BigInt`] to [`other`]. |
|
|
|
* Compares caller `BigInt` to `other`. |
|
|
|
/// |
|
|
|
* |
|
|
|
/// [`BigIntCompareResult`] representing the result of comparison is returned as a result. |
|
|
|
* @param other Value to compare the caller `BigInt`. |
|
|
|
/// It describes how caller [`BigInt`] relates to the `other`, e.g. if `BICR_Less` was returned then |
|
|
|
* @return `BigIntCompareResult` representing the result of comparison. |
|
|
|
/// it means that caller [`BigInt`] is smaller that `other`. |
|
|
|
* Returned value describes how caller `BigInt` relates to the `other`, |
|
|
|
public function BigIntCompareResult CompareInt(int other) { |
|
|
|
* e.g. if `BICR_Less` was returned - it means that caller `BigInt` is |
|
|
|
|
|
|
|
* smaller that `other`. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function BigIntCompareResult CompareInt(int other) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local BigInt wrapper; |
|
|
|
local BigInt wrapper; |
|
|
|
local BigIntCompareResult result; |
|
|
|
local BigIntCompareResult result; |
|
|
|
|
|
|
|
|
|
|
@ -369,39 +309,31 @@ public function BigIntCompareResult CompareInt(int other) |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Compares caller [`BigInt`] to a decimal representation of a number. |
|
|
|
* Compares caller `BigInt` to `other`. |
|
|
|
/// |
|
|
|
* |
|
|
|
/// [`BigIntCompareResult`] representing the result of comparison is returned as a result. |
|
|
|
* @param other Value to compare the caller `BigInt`. |
|
|
|
/// It describes how caller [`BigInt`] relates to the `other`, e.g. if `BICR_Less` was returned then |
|
|
|
* If given reference is `none` - behavior is undefined. |
|
|
|
/// it means that caller [`BigInt`] is smaller that `other`. |
|
|
|
* @return `BigIntCompareResult` representing the result of comparison. |
|
|
|
/// If argument is `none` or is an invalid decimal representation (digits only, possibly with |
|
|
|
* Returned value describes how caller `BigInt` relates to the `other`, |
|
|
|
/// leading sign, then it is considered to be less ([`BICR_Less`]) than caller [`BigInt`]. |
|
|
|
* e.g. if `BICR_Less` was returned - it means that caller `BigInt` is |
|
|
|
public function BigIntCompareResult CompareDecimal(BaseText other) { |
|
|
|
* smaller that `other`. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function BigIntCompareResult CompareDecimal(BaseText other) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local BigInt wrapper; |
|
|
|
local BigInt wrapper; |
|
|
|
local BigIntCompareResult result; |
|
|
|
local BigIntCompareResult result; |
|
|
|
|
|
|
|
|
|
|
|
wrapper = _.math.MakeBigInt(other); |
|
|
|
wrapper = _.math.MakeBigInt(other); |
|
|
|
result = Compare(wrapper); |
|
|
|
result = Compare(wrapper); |
|
|
|
wrapper.FreeSelf(); |
|
|
|
_.memory.Free(wrapper); |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Compares caller [`BigInt`] to a decimal representation of a number. |
|
|
|
* Compares caller `BigInt` to `other`. |
|
|
|
/// |
|
|
|
* |
|
|
|
/// [`BigIntCompareResult`] representing the result of comparison is returned as a result. |
|
|
|
* @param other Value to compare the caller `BigInt`. |
|
|
|
/// It describes how caller [`BigInt`] relates to the `other`, e.g. if `BICR_Less` was returned then |
|
|
|
* If given value contains invalid decimal value - behavior is undefined. |
|
|
|
/// it means that caller [`BigInt`] is smaller that `other`. |
|
|
|
* @return `BigIntCompareResult` representing the result of comparison. |
|
|
|
/// If argument is an invalid decimal representation (digits only, possibly with leading sign, then |
|
|
|
* Returned value describes how caller `BigInt` relates to the `other`, |
|
|
|
/// it is considered to be less ([`BICR_Less`]) than caller [`BigInt`]. |
|
|
|
* e.g. if `BICR_Less` was returned - it means that caller `BigInt` is |
|
|
|
public function BigIntCompareResult CompareDecimal_S(string other) { |
|
|
|
* smaller that `other`. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function BigIntCompareResult CompareDecimal_S(string other) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local BigInt wrapper; |
|
|
|
local BigInt wrapper; |
|
|
|
local BigIntCompareResult result; |
|
|
|
local BigIntCompareResult result; |
|
|
|
|
|
|
|
|
|
|
@ -411,10 +343,8 @@ public function BigIntCompareResult CompareDecimal_S(string other) |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Adds absolute values of caller `BigInt` and `other` with no changes to |
|
|
|
// Adds absolute values of caller [`BigInt`] and [`other`] with no changes to the sign. |
|
|
|
// the sign |
|
|
|
private function _add(BigInt other) { |
|
|
|
private function _add(BigInt other) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local int i; |
|
|
|
local int i; |
|
|
|
local byte carry, digitSum; |
|
|
|
local byte carry, digitSum; |
|
|
|
local array<byte> otherDigits; |
|
|
|
local array<byte> otherDigits; |
|
|
@ -425,13 +355,11 @@ private function _add(BigInt other) |
|
|
|
otherDigits = other.digits; |
|
|
|
otherDigits = other.digits; |
|
|
|
if (digits.length < otherDigits.length) { |
|
|
|
if (digits.length < otherDigits.length) { |
|
|
|
digits.length = otherDigits.length; |
|
|
|
digits.length = otherDigits.length; |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
|
|
|
|
otherDigits.length = digits.length; |
|
|
|
otherDigits.length = digits.length; |
|
|
|
} |
|
|
|
} |
|
|
|
carry = 0; |
|
|
|
carry = 0; |
|
|
|
for (i = 0; i < digits.length; i += 1) |
|
|
|
for (i = 0; i < digits.length; i += 1) { |
|
|
|
{ |
|
|
|
|
|
|
|
digitSum = digits[i] + otherDigits[i] + carry; |
|
|
|
digitSum = digits[i] + otherDigits[i] + carry; |
|
|
|
digits[i] = _.math.Remainder(digitSum, 10); |
|
|
|
digits[i] = _.math.Remainder(digitSum, 10); |
|
|
|
carry = (digitSum - digits[i]) / 10; |
|
|
|
carry = (digitSum - digits[i]) / 10; |
|
|
@ -442,10 +370,9 @@ private function _add(BigInt other) |
|
|
|
// No leading zeroes can be created here, so no need to trim |
|
|
|
// No leading zeroes can be created here, so no need to trim |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Subtracts absolute value of `other` from the caller `BigInt`, flipping |
|
|
|
// Subtracts absolute value of [`other`] from the caller [`BigInt`], flipping caller's sign in case |
|
|
|
// caller's sign in case `other`'s absolute value is bigger. |
|
|
|
// `other`'s absolute value is bigger. |
|
|
|
private function _sub(BigInt other) |
|
|
|
private function _sub(BigInt other) { |
|
|
|
{ |
|
|
|
|
|
|
|
local int i; |
|
|
|
local int i; |
|
|
|
local int carry, nextDigit; |
|
|
|
local int carry, nextDigit; |
|
|
|
local array<byte> minuendDigits, subtrahendDigits; |
|
|
|
local array<byte> minuendDigits, subtrahendDigits; |
|
|
@ -455,34 +382,27 @@ private function _sub(BigInt other) |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
resultForModulus = _compareAbsolute(other); |
|
|
|
resultForModulus = _compareAbsolute(other); |
|
|
|
if (resultForModulus == BICR_Equal) |
|
|
|
if (resultForModulus == BICR_Equal) { |
|
|
|
{ |
|
|
|
|
|
|
|
SetZero(); |
|
|
|
SetZero(); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
if (resultForModulus == BICR_Less) |
|
|
|
if (resultForModulus == BICR_Less) { |
|
|
|
{ |
|
|
|
|
|
|
|
negative = !negative; |
|
|
|
negative = !negative; |
|
|
|
minuendDigits = other.digits; |
|
|
|
minuendDigits = other.digits; |
|
|
|
subtrahendDigits = digits; |
|
|
|
subtrahendDigits = digits; |
|
|
|
} |
|
|
|
} else { |
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
minuendDigits = digits; |
|
|
|
minuendDigits = digits; |
|
|
|
subtrahendDigits = other.digits; |
|
|
|
subtrahendDigits = other.digits; |
|
|
|
} |
|
|
|
} |
|
|
|
digits.length = minuendDigits.length; |
|
|
|
digits.length = minuendDigits.length; |
|
|
|
subtrahendDigits.length = minuendDigits.length; |
|
|
|
subtrahendDigits.length = minuendDigits.length; |
|
|
|
carry = 0; |
|
|
|
carry = 0; |
|
|
|
for (i = 0; i < digits.length; i += 1) |
|
|
|
for (i = 0; i < digits.length; i += 1) { |
|
|
|
{ |
|
|
|
|
|
|
|
nextDigit = int(minuendDigits[i]) - int(subtrahendDigits[i]) + carry; |
|
|
|
nextDigit = int(minuendDigits[i]) - int(subtrahendDigits[i]) + carry; |
|
|
|
if (nextDigit < 0) |
|
|
|
if (nextDigit < 0) { |
|
|
|
{ |
|
|
|
|
|
|
|
nextDigit += 10; |
|
|
|
nextDigit += 10; |
|
|
|
carry = -1; |
|
|
|
carry = -1; |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
|
|
|
|
carry = 0; |
|
|
|
carry = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
digits[i] = nextDigit; |
|
|
|
digits[i] = nextDigit; |
|
|
@ -490,170 +410,108 @@ private function _sub(BigInt other) |
|
|
|
TrimLeadingZeroes(); |
|
|
|
TrimLeadingZeroes(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Adds another value to the caller [`BigInt`]. |
|
|
|
* Adds `other` value to the caller `BigInt`. |
|
|
|
/// |
|
|
|
* |
|
|
|
/// If argument is `none`, then given method does nothing. |
|
|
|
* @param other Value to add. If `none` is given method does nothing. |
|
|
|
public function Add(BigInt other) { |
|
|
|
* @return Self-reference to allow for method chaining. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function BigInt Add(BigInt other) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (other == none) { |
|
|
|
if (other == none) { |
|
|
|
return self; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
if (negative == other.negative) { |
|
|
|
if (negative == other.negative) { |
|
|
|
_add(other); |
|
|
|
_add(other); |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
|
|
|
|
_sub(other); |
|
|
|
_sub(other); |
|
|
|
} |
|
|
|
} |
|
|
|
return self; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Adds another value to the caller [`BigInt`]. |
|
|
|
* Adds `other` value to the caller `BigInt`. |
|
|
|
public function AddInt(int other) { |
|
|
|
* |
|
|
|
|
|
|
|
* Cannot fail. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param other Value to add. |
|
|
|
|
|
|
|
* @return Self-reference to allow for method chaining. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function BigInt AddInt(int other) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local BigInt otherObject; |
|
|
|
local BigInt otherObject; |
|
|
|
|
|
|
|
|
|
|
|
otherObject = _.math.ToBigInt(other); |
|
|
|
otherObject = _.math.ToBigInt(other); |
|
|
|
Add(otherObject); |
|
|
|
Add(otherObject); |
|
|
|
_.memory.Free(otherObject); |
|
|
|
_.memory.Free(otherObject); |
|
|
|
return self; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Adds decimal representation of the number to the caller [`BigInt`]. |
|
|
|
* Adds `other` value to the caller `BigInt`. |
|
|
|
/// |
|
|
|
* |
|
|
|
/// If `none` or invalid decimal representation (digits only, possibly with leading sign) is given - |
|
|
|
* If invalid decimal representation (digits only, possibly with leading sign) |
|
|
|
/// does nothing. |
|
|
|
* is given - behavior is undefined. Otherwise cannot fail. |
|
|
|
public function AddDecimal(BaseText other) { |
|
|
|
* |
|
|
|
|
|
|
|
* @param other Value to add. If `none` is given, method does nothing. |
|
|
|
|
|
|
|
* @return Self-reference to allow for method chaining. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function BigInt AddDecimal(BaseText other) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local BigInt otherObject; |
|
|
|
local BigInt otherObject; |
|
|
|
|
|
|
|
|
|
|
|
if (other == none) { |
|
|
|
if (other == none) { |
|
|
|
return self; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
otherObject = _.math.MakeBigInt(other); |
|
|
|
otherObject = _.math.MakeBigInt(other); |
|
|
|
Add(otherObject); |
|
|
|
Add(otherObject); |
|
|
|
_.memory.Free(otherObject); |
|
|
|
_.memory.Free(otherObject); |
|
|
|
return self; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Adds decimal representation of the number to the caller [`BigInt`]. |
|
|
|
* Adds `other` value to the caller `BigInt`. |
|
|
|
/// |
|
|
|
* |
|
|
|
/// If invalid decimal representation (digits only, possibly with leading sign) is given - |
|
|
|
* If invalid decimal representation (digits only, possibly with leading sign) |
|
|
|
/// does nothing. |
|
|
|
* is given - behavior is undefined. Otherwise cannot fail. |
|
|
|
public function AddDecimal_S(string other) { |
|
|
|
* |
|
|
|
|
|
|
|
* @param other Value to add. |
|
|
|
|
|
|
|
* @return Self-reference to allow for method chaining. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function BigInt AddDecimal_S(string other) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local BigInt otherObject; |
|
|
|
local BigInt otherObject; |
|
|
|
|
|
|
|
|
|
|
|
otherObject = _.math.MakeBigInt_S(other); |
|
|
|
otherObject = _.math.MakeBigInt_S(other); |
|
|
|
Add(otherObject); |
|
|
|
Add(otherObject); |
|
|
|
_.memory.Free(otherObject); |
|
|
|
_.memory.Free(otherObject); |
|
|
|
return self; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Subtracts another value to the caller [`BigInt`]. |
|
|
|
* Subtracts `other` value to the caller `BigInt`. |
|
|
|
/// |
|
|
|
* |
|
|
|
/// If argument is `none`, then given method does nothing. |
|
|
|
* @param other Value to subtract. If `none` is given method does nothing. |
|
|
|
public function Subtract(BigInt other) { |
|
|
|
* @return Self-reference to allow for method chaining. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function BigInt Subtract(BigInt other) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (negative != other.negative) { |
|
|
|
if (negative != other.negative) { |
|
|
|
_add(other); |
|
|
|
_add(other); |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
|
|
|
|
_sub(other); |
|
|
|
_sub(other); |
|
|
|
} |
|
|
|
} |
|
|
|
return self; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Adds another value to the caller [`BigInt`]. |
|
|
|
* Subtracts `other` value to the caller `BigInt`. |
|
|
|
public function SubtractInt(int other) { |
|
|
|
* |
|
|
|
|
|
|
|
* Cannot fail. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param other Value to subtract. |
|
|
|
|
|
|
|
* @return Self-reference to allow for method chaining. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function BigInt SubtractInt(int other) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local BigInt otherObject; |
|
|
|
local BigInt otherObject; |
|
|
|
|
|
|
|
|
|
|
|
otherObject = _.math.ToBigInt(other); |
|
|
|
otherObject = _.math.ToBigInt(other); |
|
|
|
Subtract(otherObject); |
|
|
|
Subtract(otherObject); |
|
|
|
_.memory.Free(otherObject); |
|
|
|
_.memory.Free(otherObject); |
|
|
|
return self; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Subtracts decimal representation of the number to the caller [`BigInt`]. |
|
|
|
* Subtracts `other` value to the caller `BigInt`. |
|
|
|
/// |
|
|
|
* |
|
|
|
/// If `none` or invalid decimal representation (digits only, possibly with leading sign) is given - |
|
|
|
* If invalid decimal representation (digits only, possibly with leading sign) |
|
|
|
/// does nothing. |
|
|
|
* is given - behavior is undefined. Otherwise cannot fail. |
|
|
|
public function SubtractDecimal(BaseText other) { |
|
|
|
* |
|
|
|
|
|
|
|
* @param other Value to subtract. If `none`, method does nothing. |
|
|
|
|
|
|
|
* @return Self-reference to allow for method chaining. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function BigInt SubtractDecimal(BaseText other) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local BigInt otherObject; |
|
|
|
local BigInt otherObject; |
|
|
|
|
|
|
|
|
|
|
|
if (other == none) { |
|
|
|
if (other == none) { |
|
|
|
return self; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
otherObject = _.math.MakeBigInt(other); |
|
|
|
otherObject = _.math.MakeBigInt(other); |
|
|
|
Subtract(otherObject); |
|
|
|
Subtract(otherObject); |
|
|
|
_.memory.Free(otherObject); |
|
|
|
_.memory.Free(otherObject); |
|
|
|
return self; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Adds decimal representation of the number to the caller [`BigInt`]. |
|
|
|
* Subtracts `other` value to the caller `BigInt`. |
|
|
|
/// |
|
|
|
* |
|
|
|
/// If invalid decimal representation (digits only, possibly with leading sign) is given - |
|
|
|
* If invalid decimal representation (digits only, possibly with leading sign) |
|
|
|
/// does nothing. |
|
|
|
* is given - behavior is undefined. Otherwise cannot fail. |
|
|
|
public function SubtractDecimal_S(string other) { |
|
|
|
* |
|
|
|
|
|
|
|
* @param other Value to subtract. |
|
|
|
|
|
|
|
* @return Self-reference to allow for method chaining. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function BigInt SubtractDecimal_S(string other) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local BigInt otherObject; |
|
|
|
local BigInt otherObject; |
|
|
|
|
|
|
|
|
|
|
|
otherObject = _.math.MakeBigInt_S(other); |
|
|
|
otherObject = _.math.MakeBigInt_S(other); |
|
|
|
Subtract(otherObject); |
|
|
|
Subtract(otherObject); |
|
|
|
_.memory.Free(otherObject); |
|
|
|
_.memory.Free(otherObject); |
|
|
|
return self; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Checks if caller [`BigInt`] is negative. |
|
|
|
* Checks if caller `BigInt` is negative. Zero is not considered negative |
|
|
|
/// |
|
|
|
* number. |
|
|
|
/// Returns if stored value is negative and `false` otherwise. |
|
|
|
* |
|
|
|
/// Zero is not considered negative number. |
|
|
|
* @return `true` if stored value is negative (`< 0`) and `false` otherwise |
|
|
|
public function bool IsNegative() { |
|
|
|
* (`>= 0`). |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function bool IsNegative() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// Handle special case of zero first (it ignores `negative` flag) |
|
|
|
// Handle special case of zero first (it ignores `negative` flag) |
|
|
|
if (digits.length == 1 && digits[0] == 0) { |
|
|
|
if (digits.length == 1 && digits[0] == 0) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
@ -661,19 +519,12 @@ public function bool IsNegative() |
|
|
|
return negative; |
|
|
|
return negative; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Converts caller [`BigInt`] into [`int`] representation. |
|
|
|
* Converts caller `BigInt` into `int` representation. |
|
|
|
/// |
|
|
|
* |
|
|
|
/// In case stored value is outside `int`'s value range |
|
|
|
* In case stored value is outside `int`'s value range |
|
|
|
/// (`[-maxInt-1, maxInt] == [-2147483648; 2147483647]`), method returns either maximal or minimal |
|
|
|
* (`[-MaxInt-1, MaxInt] == [-2147483648; 2147483647]`), |
|
|
|
// possible value, depending on the [`BigInt`]'s sign. |
|
|
|
* method returns either maximal or minimal possible value, depending on |
|
|
|
public function int ToInt() { |
|
|
|
* the `BigInt`'s sign. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return `int` representation of the caller `BigInt`, clamped into available |
|
|
|
|
|
|
|
* `int` value range. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function int ToInt() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local int i; |
|
|
|
local int i; |
|
|
|
local int accumulator; |
|
|
|
local int accumulator; |
|
|
|
local int safeDigitsAmount; |
|
|
|
local int safeDigitsAmount; |
|
|
@ -681,19 +532,16 @@ public function int ToInt() |
|
|
|
if (digits.length <= 0) { |
|
|
|
if (digits.length <= 0) { |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
if (digits.length > DIGITS_IN_MAX_INT) |
|
|
|
if (digits.length > DIGITS_IN_MAX_INT) { |
|
|
|
{ |
|
|
|
|
|
|
|
if (negative) { |
|
|
|
if (negative) { |
|
|
|
return (-MaxInt - 1); |
|
|
|
return (-maxInt - 1); |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
return maxInt; |
|
|
|
return MaxInt; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// At most `DIGITS_IN_MAX_INT - 1` iterations |
|
|
|
// At most `DIGITS_IN_MAX_INT - 1` iterations |
|
|
|
safeDigitsAmount = Min(DIGITS_IN_MAX_INT - 1, digits.length); |
|
|
|
safeDigitsAmount = Min(DIGITS_IN_MAX_INT - 1, digits.length); |
|
|
|
for (i = safeDigitsAmount - 1; i >= 0; i -= 1) |
|
|
|
for (i = safeDigitsAmount - 1; i >= 0; i -= 1) { |
|
|
|
{ |
|
|
|
|
|
|
|
accumulator *= 10; |
|
|
|
accumulator *= 10; |
|
|
|
accumulator += digits[i]; |
|
|
|
accumulator += digits[i]; |
|
|
|
} |
|
|
|
} |
|
|
@ -704,12 +552,10 @@ public function int ToInt() |
|
|
|
return accumulator; |
|
|
|
return accumulator; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Adding `DIGITS_IN_MAX_INT - 1` will never lead to an overflow, but |
|
|
|
/// Adding `DIGITS_IN_MAX_INT - 1` will never lead to an overflow, but adding the next digit can, |
|
|
|
// adding the next digit can, so we need to handle it differently and more |
|
|
|
/// so we need to handle it differently and more carefully. |
|
|
|
// carefully. |
|
|
|
/// Assumes `digits.length <= DIGITS_IN_MAX_INT`. |
|
|
|
// Assumes `digits.length <= DIGITS_IN_MAX_INT`. |
|
|
|
private function int AddUnsafeDigitToInt(int accumulator) { |
|
|
|
private function int AddUnsafeDigitToInt(int accumulator) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local int unsafeDigit; |
|
|
|
local int unsafeDigit; |
|
|
|
local bool noOverflow; |
|
|
|
local bool noOverflow; |
|
|
|
|
|
|
|
|
|
|
@ -717,20 +563,17 @@ private function int AddUnsafeDigitToInt(int accumulator) |
|
|
|
return accumulator; |
|
|
|
return accumulator; |
|
|
|
} |
|
|
|
} |
|
|
|
unsafeDigit = digits[DIGITS_IN_MAX_INT - 1]; |
|
|
|
unsafeDigit = digits[DIGITS_IN_MAX_INT - 1]; |
|
|
|
// `MaxInt` stats with `2`, so if last/unsafe digit is either `0` or `1`, |
|
|
|
// `maxInt` stats with `2`, so if last/unsafe digit is either `0` or `1`, there is no overflow, |
|
|
|
// there is no overflow, otherwise - check rest of the digits |
|
|
|
// otherwise - check rest of the digits |
|
|
|
noOverflow = (unsafeDigit < 2); |
|
|
|
noOverflow = (unsafeDigit < 2); |
|
|
|
if (unsafeDigit == 2) |
|
|
|
if (unsafeDigit == 2) { |
|
|
|
{ |
|
|
|
// Include `maxInt` and `-maxInt-1` (minimal possible value) into an overflow too - this way |
|
|
|
// Include `MaxInt` and `-MaxInt-1` (minimal possible value) into |
|
|
|
// we still give a correct result, but do not have to worry about `int`-arithmetic error |
|
|
|
// an overflow too - this way we still give a correct result, but do |
|
|
|
|
|
|
|
// not have to worry about `int`-arithmetic error |
|
|
|
|
|
|
|
noOverflow = noOverflow |
|
|
|
noOverflow = noOverflow |
|
|
|
|| (negative && (accumulator > -ALMOST_MAX_INT - 1)) |
|
|
|
|| (negative && (accumulator > -ALMOST_MAX_INT - 1)) |
|
|
|
|| (!negative && (accumulator < ALMOST_MAX_INT)); |
|
|
|
|| (!negative && (accumulator < ALMOST_MAX_INT)); |
|
|
|
} |
|
|
|
} |
|
|
|
if (noOverflow) |
|
|
|
if (noOverflow) { |
|
|
|
{ |
|
|
|
|
|
|
|
if (negative) { |
|
|
|
if (negative) { |
|
|
|
accumulator -= unsafeDigit * LAST_DIGIT_ORDER; |
|
|
|
accumulator -= unsafeDigit * LAST_DIGIT_ORDER; |
|
|
|
} |
|
|
|
} |
|
|
@ -741,28 +584,18 @@ private function int AddUnsafeDigitToInt(int accumulator) |
|
|
|
} |
|
|
|
} |
|
|
|
// Handle overflow |
|
|
|
// Handle overflow |
|
|
|
if (negative) { |
|
|
|
if (negative) { |
|
|
|
return (-MaxInt - 1); |
|
|
|
return (-maxInt - 1); |
|
|
|
} |
|
|
|
} |
|
|
|
return MaxInt; |
|
|
|
return maxInt; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Converts caller [`BigInt`] into [`Text`] representation. |
|
|
|
* Converts caller `BigInt` into `Text` representation. |
|
|
|
public function Text ToText() { |
|
|
|
* |
|
|
|
|
|
|
|
* @return `Text` representation of the caller `BigInt`. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function Text ToText() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return ToText_M().IntoText(); |
|
|
|
return ToText_M().IntoText(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Converts caller [`BigInt`] into [`MutableText`] representation. |
|
|
|
* Converts caller `BigInt` into `MutableText` representation. |
|
|
|
public function MutableText ToText_M() { |
|
|
|
* |
|
|
|
|
|
|
|
* @return `MutableText` representation of the caller `BigInt`. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function MutableText ToText_M() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local int i; |
|
|
|
local int i; |
|
|
|
local MutableText result; |
|
|
|
local MutableText result; |
|
|
|
|
|
|
|
|
|
|
@ -776,13 +609,8 @@ public function MutableText ToText_M() |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Converts caller [`BigInt`] into [`string`] representation. |
|
|
|
* Converts caller `BigInt` into `string` representation. |
|
|
|
public function string ToString() { |
|
|
|
* |
|
|
|
|
|
|
|
* @return `string` representation of the caller `BigInt`. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function string ToString() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local int i; |
|
|
|
local int i; |
|
|
|
local string result; |
|
|
|
local string result; |
|
|
|
|
|
|
|
|
|
|
@ -795,16 +623,10 @@ public function string ToString() |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Restores [`BigInt`] from the [`BigIntData`] value. |
|
|
|
* Restores `BigInt` from the `BigIntData` value. |
|
|
|
/// |
|
|
|
* |
|
|
|
/// This method is created to make an efficient way to store [`BigInt`]. |
|
|
|
* This method is created to make an efficient way to store `BigInt` inside |
|
|
|
public function FromData(BigIntData data) { |
|
|
|
* local databases. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param data Data to read new caller `BigInt`'s value from. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function FromData(BigIntData data) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local int i; |
|
|
|
local int i; |
|
|
|
|
|
|
|
|
|
|
|
negative = data.negative; |
|
|
|
negative = data.negative; |
|
|
@ -817,16 +639,10 @@ public function FromData(BigIntData data) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/// Converts caller [`BigInt`]'s value into [`BigIntData`]. |
|
|
|
* Converts caller `BigInt`'s value into `BigIntData`. |
|
|
|
/// |
|
|
|
* |
|
|
|
/// This method is created to make an efficient way to store [`BigInt`]. |
|
|
|
* This method is created to make an efficient way to store `BigInt` inside |
|
|
|
public function BigIntData ToData() { |
|
|
|
* local databases. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Value of the caller `BigInt` in the `struct` form. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public function BigIntData ToData() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
local BigIntData result; |
|
|
|
local BigIntData result; |
|
|
|
|
|
|
|
|
|
|
|
result.negative = negative; |
|
|
|
result.negative = negative; |
|
|
@ -834,6 +650,5 @@ public function BigIntData ToData() |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
defaultproperties |
|
|
|
defaultproperties { |
|
|
|
{ |
|
|
|
|
|
|
|
} |
|
|
|
} |