#include-once

; Modified : 2022/03/03
; Info :
; This UDF allows to work with numbers (e.g. integer values) whose amount of digits is longer
; than allowed in the numeric representation.
;    Example :
;      $iInt32 = 2147483647          ; 2^31 - Highest Int32
;      $iInt64 = 9223372036854775807 ; 2^63 - Highest Int64
; For this purpose, numbers are converted and processed as strings.
; - Local Declaration Func __BigNum_Div_DivisorGreater14 -> $iTrm added

; #INDEX# =======================================================================================================================
; Title .........: BigNum
; AutoIt Version : 3.2.12.1
; Language ......: English
; Description ...: Perform calculations with big numbers
; ===============================================================================================================================

; #CURRENT# =====================================================================================================================
;_BigNum_Parse
;_BigNum_Add
;_BigNum_Sub
;_BigNum_Mul
;_BigNum_Div
;_BigNum_Pow
;_BigNum_SQRT
;_BigNum_n_Root
;_BigNum_Mod
;_BigNum_Round
;_BigNum_Compare
; ===============================================================================================================================

; #INTERNAL_USE_ONLY#============================================================================================================
;__BigNum_Swap
;__BigNum_CheckNegative
;__BigNum_DivAdd
;__BigNum_DivComp
;__BigNum_DivSub
;__BigNum_Div_DivisorGreater14
;__BigNum_Div_DivisorMaxLen14
;__BigNum_InsertDecimalSeparator
;__BigNum_StringIsDecimal
;__BigNum_IsValid
; ===============================================================================================================================

; #FUNCTION# ;====================================================================================
; Name...........: _BigNum_Parse
; Description ...: Parses a line using bigNums
; Syntax.........: _BigNum_Parse($sLine)
; Parameters ....: $sLine -  e.g. "-1-(2-4*3^(2*5))/(-2.5)"
;                  ^ : Power
;                  % : Mod
;                  / : Div
;                  * : Mul
;                  + : Add
;                  - : Sub
; Return values .: Success - Result
;                  Failure - ?
; Remarks .......:
; Author ........: eukalyptus
; ;===============================================================================================

Func _BigNum_Parse($sLine)
	$sLine = StringStripWS($sLine, 8)
	$sLine = StringRegExpReplace($sLine, "([\^%/*+-])", "$1#")
	Local $aReg = StringRegExp($sLine, "\(([^()]+)\)", 3)
	If IsArray($aReg) Then
		$sLine = StringRegExpReplace($sLine, "\([^()]+\)", Chr(1))
		For $i = 0 To UBound($aReg) - 1
			$sLine = StringReplace($sLine, Chr(1), _BigNum_Parse($aReg[$i]), 1)
		Next
		$sLine = _BigNum_Parse($sLine)
	EndIf
	Local $aOp[6][2] = [["\^", "_BigNum_Pow"],["%", "_BigNum_Mod"],["/", "_BigNum_Div"],["\*", "_BigNum_Mul"],["\+", "_BigNum_Add"],["-", "_BigNum_Sub"]]
	Local $iCnt = 0
	While $iCnt < 6
		$aReg = StringRegExp($sLine, "(-*[0-9.]+)\#*" & $aOp[$iCnt][0] & "\#*(-*[0-9.]+)", 1)
		If IsArray($aReg) Then
			$sLine = StringRegExpReplace($sLine, "-*[0-9.]+\#*" & $aOp[$iCnt][0] & "\#*-*[0-9.]+", Call($aOp[$iCnt][1], $aReg[0], $aReg[1]), 1)
		Else
			$iCnt += 1
		EndIf
	WEnd
	$sLine = StringReplace($sLine, "#", "")
	$sLine = StringReplace($sLine, "--", "+")
	If StringRegExp($sLine, "^\+[0-9.]+$") Then $sLine = StringReplace($sLine, "+", "")
	Return $sLine
EndFunc   ;==>_BigNum_Parse

; #FUNCTION# ;====================================================================================
;
; Name...........: _BigNum_Add
; Description ...: Addition $sX + $sY
; Syntax.........: _BigNum_Add($sX, $sY)
; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
;                  $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
; Return values .: Success - Result $sX + $sY
;                  Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber
; Author ........: Eukalyptus www.autoit.de
;
; ;===============================================================================================
Func _BigNum_Add($sX, $sY)
	If Not __BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0)
	Local $iNeg = __BigNum_CheckNegative($sX, $sY), $sNeg = ""
	Switch $iNeg
		Case 3
			$sNeg = "-"
		Case 1
			Return _BigNum_Sub($sY, $sX)
		Case 2
			Return _BigNum_Sub($sX, $sY)
	EndSwitch
	Local $iDec = __BigNum_StringIsDecimal($sX, $sY)
	Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = ""
	If $iLen < $iTmp Then $iLen = $iTmp
	For $i = 1 To $iLen Step 18
		$iTmp = Int(StringRight($sX, 18)) + Int(StringRight($sY, 18)) + $iCar
		$sX = StringTrimRight($sX, 18)
		$sY = StringTrimRight($sY, 18)
		If ($iTmp > 999999999999999999) Then
			$iTmp = StringRight($iTmp, 18)
			$sRet = $iTmp & $sRet
			$iCar = 1
		Else
			$iTmp = StringRight("000000000000000000" & $iTmp, 18)
			$sRet = $iTmp & $sRet
			$iCar = 0
		EndIf
	Next
	$sRet = StringRegExpReplace($iCar & $sRet, "^0+([^0]|0$)", "\1", 1)
	If $iDec > 0 Then $sRet = __BigNum_InsertDecimalSeparator($sRet, $iDec, $iDec)
	If $sRet = "0" Then $sNeg = ""
	Return $sNeg & $sRet
EndFunc   ;==>_BigNum_Add



; #FUNCTION# ;====================================================================================
;
; Name...........: _BigNum_Sub
; Description ...: Subtraction $sX - $sY
; Syntax.........: _BigNum_Sub($sX, $sY)
; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
;                  $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
; Return values .: Success - Result $sX - $sY
;                  Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber
; Author ........: Eukalyptus www.autoit.de
;
; ;===============================================================================================
Func _BigNum_Sub($sX, $sY)
	If Not __BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0)
	Local $iNeg = __BigNum_CheckNegative($sX, $sY), $bNeg = False
	Switch $iNeg
		Case 3
			Return _BigNum_Add("-" & $sX, $sY)
		Case 1
			Return "-" & _BigNum_Add($sX, $sY)
		Case 2
			Return _BigNum_Add($sX, $sY)
	EndSwitch
	Local $iDec = __BigNum_StringIsDecimal($sX, $sY)
	If _BigNum_Compare($sX, $sY) = -1 Then $bNeg = __BigNum_Swap($sX, $sY)
	Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = ""
	If $iLen < $iTmp Then $iLen = $iTmp
	For $i = 1 To $iLen Step 18
		$iTmp = Int(StringRight($sX, 18)) - Int(StringRight($sY, 18)) - $iCar
		$sX = StringTrimRight($sX, 18)
		$sY = StringTrimRight($sY, 18)
		If $iTmp < 0 Then
			$iTmp = 1000000000000000000 + $iTmp
			$iCar = 1
		Else
			$iCar = 0
		EndIf
		$sRet = StringRight("0000000000000000000" & $iTmp, 18) & $sRet
	Next
	$sRet = StringRegExpReplace($iCar & $sRet, "^0+([^0]|0$)", "\1", 1)
	If $iDec > 0 Then $sRet = __BigNum_InsertDecimalSeparator($sRet, $iDec, $iDec)
	If $bNeg = True And $sRet <> "0" Then
		Return "-" & $sRet
	Else
		Return $sRet
	EndIf
EndFunc   ;==>_BigNum_Sub



; #FUNCTION# ;====================================================================================
;
; Name...........: _BigNum_Mul
; Description ...: Multiplication $sX * $sY
; Syntax.........: _BigNum_Mul($sX, $sY)
; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
;                  $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
; Return values .: Success - Result $sX * $sY
;                  Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber
; Author ........: Eukalyptus www.autoit.de
;
; ;===============================================================================================
Func _BigNum_Mul($sX, $sY)
	If Not __BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0)
	Local $iNeg = __BigNum_CheckNegative($sX, $sY), $sNeg = ""
	Local $iDec = __BigNum_StringIsDecimal($sX, $sY)
	Local $aX = StringRegExp($sX, '\A.{' & 6 - (Ceiling(StringLen($sX) / 6) * 6 - StringLen($sX)) & '}|.{6}+', 3)
	Local $aY = StringRegExp($sY, '\A.{' & 6 - (Ceiling(StringLen($sY) / 6) * 6 - StringLen($sY)) & '}|.{6}+', 3)
	Local $aRet[UBound($aX) + UBound($aY) - 1]
	For $j = 0 To UBound($aX) - 1
		For $i = 0 To UBound($aY) - 1
			$aRet[$j + $i] += $aX[$j] * $aY[$i]
		Next
	Next
	Local $sRet = "", $iCar = 0, $iTmp
	For $i = UBound($aRet) - 1 To 0 Step -1
		$aRet[$i] += $iCar
		$iCar = Floor($aRet[$i] / 1000000)
		$iTmp = Mod($aRet[$i], 1000000)
		If $iTmp <= 1000000 Then $iTmp = StringRight("000000" & $iTmp, 6)
		$sRet = $iTmp & $sRet
	Next
	If $iCar > 0 Then $sRet = $iCar & $sRet
	$sRet = StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1)
	If ($iNeg = 1 Or $iNeg = 2) And $sRet <> "0" Then $sNeg = "-"
	If $iDec > 0 Then $sRet = __BigNum_InsertDecimalSeparator($sRet, $iDec * 2, $iDec * 2)
	Return $sNeg & $sRet
EndFunc   ;==>_BigNum_Mul



; #FUNCTION# ;====================================================================================
;
; Name...........: _BigNum_Div
; Description ...: Division $sX / $sY
; Syntax.........: _BigNum_Div($sX, $sY, [$iD = 0])
; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
;                  $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
;                  $iD [optional] - Number of Decimalplaces; if -1 then $iD = StringLen($sX) + StringLen($sY)
; Return values .: Success - Result $sX / $sY
;                  Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber
; Author ........: Eukalyptus www.autoit.de
;
; ;===============================================================================================
Func _BigNum_Div($sX, $sY, $iD = -1)
	If Not __BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0)
	Local $iNeg = __BigNum_CheckNegative($sX, $sY), $sNeg = ""
	If $iD = -1 Then $iD = StringLen($sX) + StringLen($sY)
	Local $iDec = __BigNum_StringIsDecimal($sX, $sY), $sMod
	If $sX = 0 Or $sY = 0 Then Return "0"
	If $sY = "1" Then Return $sNeg & $sX
	While StringLeft($sX, 1) = "0"
		$sX = StringTrimLeft($sX, 1)
		$iDec += 1
	WEnd
	While StringLeft($sY, 1) = "0"
		$sY = StringTrimLeft($sY, 1)
		$iDec += 1
	WEnd
	Local $sRet = "", $iLnX = StringLen($sX), $iLnY = StringLen($sY), $iTmp, $iCnt, $sTmp, $iDe1 = 0
	If $iD > 0 Then $iDe1 += $iD
	If $iNeg = 1 Or $iNeg = 2 Then $sNeg = "-"
	$iTmp = _BigNum_Compare($sX, $sY)
	If $iTmp = -1 Then
		For $iCnt = $iLnX To $iLnY
			$sX &= 0
			$iDe1 += 1
		Next
	EndIf
	If $iTmp = 0 Then Return $sNeg & "1"
	If $iD = -1 Then $iD = $iDec * 2
	For $iCnt = 1 To $iD
		$sX &= "0"
	Next
	If $iLnY > 14 Then
		$sRet = __BigNum_Div_DivisorGreater14($sX, $sY, $sMod)
	Else
		$sRet = __BigNum_Div_DivisorMaxLen14($sX, $sY, $sMod)
	EndIf
	If $iDe1 > 0 Then $sRet = __BigNum_InsertDecimalSeparator($sRet, $iDe1, $iD)
	If $sRet = "0" Then
		Return "0"
	Else
		Return $sNeg & $sRet
	EndIf
EndFunc   ;==>_BigNum_Div


; #FUNCTION# ;====================================================================================
;
; Name...........: _BigNum_Pow
; Description ...: Exponentiation $n^$e
; Syntax.........: _BigNum_Pow($n [, $e = 2])
; Parameters ....: $n - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
;                  $e [optional] - Exponent (must be a positive 64-bit signed integer)
;                                  Default: $e = 2 means result = $nē
; Return values .: Success - Result $n^$e
;                  Failure - -1, sets @error to 1 if $n not valid StringNumber
;                            -1, sets @error to 2 if $e is not a positive Integer
; Author ........: jennicoattminusonlinedotde
; Date ..........: 9.12.09
; Remarks .......: Fractional exponents not allowed - use BigNum_n_root instead.
;                  _BigNum_Pow() offers a drastically better efficiency than looping _BigNum_Mul()
; Reference .....: http://en.wikipedia.org/wiki/Exponentiation_by_squaring
; ;===============================================================================================
Func _BigNum_Pow($n, $e = 2)
	$e = Number($e)
	If IsInt($e) = 0 Or $e < 0 Then Return SetError(2, 0, -1)
	;If $e < -2147483648 Or $e > 2147483647 Then Return SetError(-2, 0, -1)
	If Not __BigNum_IsValid($n, $n) Then Return SetError(1, 0, -1)

	Local $res = 1

	While $e
		;If BitAND($e, 1) Then  ; bitoperation is not faster !
		If Mod($e, 2) Then
			$res = _BigNum_Mul($res, $n)
			$e -= 1
		EndIf
		$n = _BigNum_Mul($n, $n)
		;$e = BitShift($e, 1)   ; bitoperation is not faster !
		$e /= 2
	WEnd

	Return $res
EndFunc   ;==>_BigNum_Pow


; #FUNCTION# ;====================================================================================
;
; Name...........: _BigNum_SQRT
; Description ...: Square Root (BigNum)
; Syntax.........: _BigNum_SQRT($n [, $p = -1])
; Parameters ....: $n - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
;                  $p [optional] - Precision (Number of Decimalplaces) (must be positive Integer)
;                            Default: $p = -1 means automatic precision (stringlen of integer part of $n)
; Return values .: Success - Result SQRT($n)
;                            @extended = Precicion of result (if $p set to automatic precision)
;                            @error = Number of Iterations
;                  Failure - -1, sets @error to -1 if $n not valid StringNumber
;                            -1, sets @error to -2 if $p is out of valid range
;                            -1, sets @error to -3 if time-out (>100 iterations)
; Author ........: jennicoattminusonlinedotde
; Date ..........: 8.12.09
; Remarks .......: use Precision param when u want to obtain the square root of a small number with the desired decimal places.
; References ....: http://www.merriampark.com/bigsqrt.htm
;                  "Newton's Method" - before: Heron of Alexandria
; ;===============================================================================================
Func _BigNum_SQRT($n, $p = -1)
	If Not __BigNum_IsValid($n, $n) Then Return SetError(-1, 0, -1)
	$p = Number($p)
	If IsInt($p) = 0 Or $p < -1 Then Return SetError(-2, 0, -1)
	Local $l = StringInStr($n, ".") - 1
	If $l = -1 Then $l = StringLen($n)
	If $p < 0 Then $p = $l
	Local $g = 1, $last

	For $i = 3 To $l Step 2
		$g = _BigNum_Mul($g, 10)
	Next

	For $i = 1 To 100
		$last = $g
		$g = _BigNum_Div(_BigNum_Add(_BigNum_Div($n, $g, $p), $g), 2, $p)
		If $last = $g Then Return SetError($i, $p, $g)
	Next
	Return SetError(-3, 0, -1)
EndFunc   ;==>_BigNum_SQRT



; #FUNCTION# ;====================================================================================
;
; Name...........: _BigNum_n_Root
; Description ...: $e-th Root of $n
; Syntax.........: _n_Root($n [, $e=2])
; Parameters ....: $n - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
;                  $e - [optional] Multiplicity of root (power, exponent) (must be a positive 64-bit signed integer > 0)
;                            Default: $e = 2 (=SQRT)
;                  $p - [optional] Precision (Number of desired Decimalplaces) (must be positive Integer)
;                            Default: $p = -1 means automatic precision (stringlen of integer part of $n)
; Return values .: Success - Result $e-root($n)
;                            @extended = Number of Iterations
;                  Failure - -1 and sets @error to 1 if $n not valid StringNumber
;                            -1 and sets @error to 2 if $e out of valid range
;                            -1 and sets @error to 3 if $p out of valid range
; Author ........: jennicoattminusonlinedotde
; Date ..........: 9.12.09
; References ....: derived from "Newton's Method"
; ;===============================================================================================
Func _BigNum_n_Root($n, $e = 2, $p = -1)
	If Not __BigNum_IsValid($n, $n) Then Return SetError(1, 0, -1)
	$e = Number($e)
	If IsInt($e) = 0 Or $e < 1 Then Return SetError(2, 0, -1)
	$p = Number($p)
	If IsInt($p) = 0 Or $p < -1 Then Return SetError(3, 0, -1)

	Local $l = StringInStr($n, ".") - 1
	If $l = -1 Then $l = StringLen($n)
	If $p < 0 Then $p = $l
	Local $g = 1, $last, $i = 0

	For $i = 3 To $l Step 2
		$g = _BigNum_Mul($g, 10)
	Next

	While 1
		$i += 1
		$last = $g
		$g = _BigNum_Div(_BigNum_Add(_BigNum_Div($n, _BigNum_Pow($g, $e - 1), $p), _BigNum_Mul($g, $e - 1)), $e, $p)
		If $last = $g Then Return SetExtended($i, $g)
	WEnd
EndFunc   ;==>_BigNum_n_Root



; #FUNCTION# ;====================================================================================
;
; Name...........: _BigNum_Mod
; Description ...: Modulo Mod($sX, $sY)
; Syntax.........: _BigNum_Mod($sX, $sY)
; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
;                  $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
; Return values .: Success - Result Mod($sX, $sY)
;                  Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber
; Author ........: Eukalyptus www.autoit.de
;
; ;===============================================================================================
Func _BigNum_Mod($sX, $sY)
	If Not __BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0)
	If $sY = 0 Or $sY = 1 Then Return "0"
	Local $sRes = $sX
	Local $iNeg = __BigNum_CheckNegative($sX, $sY)
	Local $iDec = __BigNum_StringIsDecimal($sX, $sY)
	If _BigNum_Compare($sX, $sY) < 0 Then Return $sRes
	Local $sRet = "", $iLnX = StringLen($sX), $iLnY = StringLen($sY)
	If $iLnY > 14 Then
		__BigNum_Div_DivisorGreater14($sX, $sY, $sRet)
	Else
		__BigNum_Div_DivisorMaxLen14($sX, $sY, $sRet)
	EndIf
	$sRet = __BigNum_InsertDecimalSeparator($sRet, $iDec, StringLen($sRet))
	If ($iNeg = 3 Or $iNeg = 1) And $sRet <> "0" Then $sRet = "-" & $sRet
	Return $sRet
EndFunc   ;==>_BigNum_Mod



; #FUNCTION# ;====================================================================================
;
; Name...........: _BigNum_Round
; Description ...: Round $sX to $iD Decimalplaces
; Syntax.........: _BigNum_Round($sX, $iD)
; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
;                  $iD - Number of Decimalplaces
; Return values .: Success - Result Round($sX, $iD)
;                  Failure - 0, sets @error to 1 if $sX not valid StringNumber
; Author ........: Eukalyptus www.autoit.de
;
; ;===============================================================================================
Func _BigNum_Round($sX, $iD)
	If Not __BigNum_IsValid($sX, $sX) Then Return SetError(1, 0, 0)
	Local $sTmp = 0, $sRet, $sRes = $sX
	Local $iNeg = __BigNum_CheckNegative($sX, $sTmp)
	Local $iDec = __BigNum_StringIsDecimal($sX, $sTmp)
	If $iD > $iDec Or $iDec = 0 Then Return $sRes
	$sTmp = StringLeft(StringRight($sX, $iDec - $iD), 1)
	$sRet = StringTrimRight($sRes, $iDec - $iD)
	If $sTmp >= 5 And $iD > 0 Then
		If $iNeg = 1 Then
			$sRet = _BigNum_Add($sRet, "-0." & StringFormat("%0" & String($iD) & "u", "1"))
		Else
			$sRet = _BigNum_Add($sRet, "0." & StringFormat("%0" & String($iD) & "u", "1"))
		EndIf
	ElseIf $sTmp >= 5 And $iD = 0 Then
		If $iNeg = 1 Then
			$sRet = _BigNum_Add($sRet, "-1")
		Else
			$sRet = _BigNum_Add($sRet, "1")
		EndIf
	Else
		If StringRight($sRet, 1) = "." Then $sRet = StringTrimRight($sRet, 1)
	EndIf
	Return $sRet
EndFunc   ;==>_BigNum_Round



; #FUNCTION# ;====================================================================================
;
; Name...........: _BigNum_Compare
; Description ...: Compares $sX $sY
; Syntax.........: _BigNum_Compare($sX, $sY)
; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
;                  $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
; Return values .: Success - Return:
;                  |0  - $sX and $sY are equal
;                  |1  - $sX is greater than $sY
;                  |-1 - $sX is less than $sY
;                  Failure - sets @error to 1 if $sX/$sY not valid StringNumber
; Author ........:  eXirrah
;
; ;===============================================================================================
Func _BigNum_Compare($sX, $sY) ;Algorithm No.2
	Local $iNeg = __BigNum_CheckNegative($sX, $sY)
	Switch $iNeg
		Case 1 ; sX = negative
			Return -1
		Case 2 ; sY = negative
			Return 1
		Case 3 ; both negative
			__BigNum_Swap($sX, $sY)
	EndSwitch
	__BigNum_CompEqualizeLength($sX, $sY)
	Return StringCompare($sX, $sY)
EndFunc   ;==>_BigNum_Compare





; #INTERNAL_USE_ONLY#============================================================================================================



#Region Internal Functions

Func __BigNum_CompEqualizeLength(ByRef $sX, ByRef $sY)
	Local $iXDotPos = StringInStr($sX, ".")
	Local $iYDotPos = StringInStr($sY, ".")
	Local $iXLen = StringLen($sX)
	Local $iYLen = StringLen($sY)
	Local $iLeading, $iTrailing
	;Calculation leading and trailing zeroes
	If $iXDotPos == 0 And $iYDotPos <> 0 Then
		$iLeading = $iXLen - ($iYDotPos - 1)
		$iTrailing = -1 * ($iYLen - $iYDotPos)
		$sX &= "."
	ElseIf $iXDotPos <> 0 And $iYDotPos == 0 Then
		$iLeading = ($iXDotPos - 1) - $iYLen
		$iTrailing = $iXLen - $iXDotPos
		$sY &= "."
	ElseIf $iXDotPos == 0 And $iYDotPos == 0 Then
		$iLeading = $iXLen - $iYLen
	Else
		$iLeading = $iXDotPos - $iYDotPos
		$iTrailing = ($iXLen - $iXDotPos) - ($iYLen - $iYDotPos)
	EndIf
	;adding leading and trailing zeroes
	If $iLeading < 0 Then
		$sX = __BigNum_CompStringAddZeroes($sX, -1 * $iLeading, 0, 0)
	ElseIf $iLeading > 0 Then
		$sY = __BigNum_CompStringAddZeroes($sY, $iLeading, 0, 0)
	EndIf
	If $iTrailing < 0 Then
		$sX = __BigNum_CompStringAddZeroes($sX, -1 * $iTrailing, 1, 0)
	ElseIf $iTrailing > 0 Then
		$sY = __BigNum_CompStringAddZeroes($sY, $iTrailing, 1, 0)
	EndIf
EndFunc   ;==>__BigNum_CompEqualizeLength

Func __BigNum_CompStringAddZeroes($sString, $iCount, $bTrailing = 0, $bToLength = 1)
	;$bToLength is set when the user wants to add the nescessary amount
	;of zeroes to the string so it is with length $iCount (Default)
	If $bToLength Then
		$iCount -= StringLen($sString)
	EndIf
	Local $i = 0
	Local $s = ""
	While $i < $iCount
		$s &= "0"
		$i += 1
	WEnd
	;$bTrailing is set when the user wants the zeroes to be added at the
	;right side of the string. By defaut zeroes are added at the left side of the string
	If $bTrailing Then
		Return $sString & $s
	EndIf
	Return $s & $sString
EndFunc   ;==>__BigNum_CompStringAddZeroes


Func __BigNum_Swap(ByRef $sX, ByRef $sY)
	Local $sSwap = $sX
	$sX = $sY
	$sY = $sSwap
	Return True
EndFunc   ;==>__BigNum_Swap

Func __BigNum_Div_DivisorGreater14($sX, $sY, ByRef $sM)
	$sM = "0"
	If $sY = "1" Then Return $sX
	If $sX = "0" Or $sY = "0" Or $sX = "" Or $sY = "" Then Return "0"

	Local $iLnY = StringLen($sY), $bRed = False
	Local $sRet = "", $sRem = StringLeft($sX, $iLnY), $iTrm, $sTmp = "", $sTm2 = "", $iCnt, $iLen = 1
	$sX = StringTrimLeft($sX, $iLnY)
	Do
		If __BigNum_DivComp($sRem, $sY) = -1 Then
			$sTmp = StringLeft($sX, 1)
			$sRem &= $sTmp
			$sX = StringTrimLeft($sX, 1)
			If StringLen($sTmp) > 0 Then $iLen += 1
		EndIf
		$sTmp = $sY
		$sTm2 = "0"
		If __BigNum_DivComp($sRem, $sY) >= 0 Then
			For $iCnt = 1 To 9
				$sTm2 = $sTmp
				$sTmp = __BigNum_DivAdd($sTmp, $sY)
				If __BigNum_DivComp($sRem, $sTmp) < 0 Then ExitLoop
			Next
		Else
			$iCnt = 0
		EndIf

		If StringLen($sX) = 0 Then $bRed = True
		$sM = $sRem
		$sRem = __BigNum_DivSub($sRem, $sTm2)
		If $iCnt > 0 Then $sM = $sRem
		$sRet &= StringFormat("%0" & String($iLen) & "u", $iCnt)
		$iTrm = $iLnY - StringLen($sRem)
		$sTmp = StringLeft($sX, $iTrm)
		$sX = StringTrimLeft($sX, $iTrm)
		$iLen = StringLen($sTmp)
		$sRem &= $sTmp
	Until $bRed
	$sM = StringRegExpReplace($sM, "^0+([^0]|0$)", "\1", 1)

	Return StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1)
EndFunc   ;==>__BigNum_Div_DivisorGreater14

Func __BigNum_Div_DivisorMaxLen14($sX, $sY, ByRef $sM)
	$sM = "0"
	If $sY = "1" Then Return $sX
	If $sX = "0" Or $sY = "0" Or $sX = "" Or $sY = "" Then Return "0"

	Local $sRet = "", $iRem = StringLeft($sX, 15), $iTmp = 0, $iTrm = 6, $iLen
	$sX = StringTrimLeft($sX, 15)
	$iTmp = Floor($iRem / $sY)
	$sRet &= $iTmp

	$iRem -= $iTmp * $sY
	While StringLen($sX) > 0
		$iTrm = 15 - StringLen($iRem)
		$iTmp = StringLeft($sX, $iTrm)
		$iLen = StringLen($iTmp)
		$iRem &= $iTmp
		$sX = StringTrimLeft($sX, $iTrm)
		$iTmp = Floor($iRem / $sY)
		$iTmp = StringRight("000000000000000" & $iTmp, $iLen)

		$sRet &= $iTmp
		$iRem -= $iTmp * $sY
	WEnd
	$sM = String($iRem)

	Return StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1)
EndFunc   ;==>__BigNum_Div_DivisorMaxLen14

Func __BigNum_DivComp($sX, $sY)
	$sX = StringRegExpReplace($sX, "^0+([^0]|0$)", "\1", 1)
	$sY = StringRegExpReplace($sY, "^0+([^0]|0$)", "\1", 1)
	Local $iLnX = StringLen($sX), $iLnY = StringLen($sY)
	If $iLnX < $iLnY Then
		Return -1
	ElseIf $iLnX > $iLnY Then
		Return 1
	Else
		If $sX < $sY Then
			Return -1
		ElseIf $sX > $sY Then
			Return 1
		Else
			Return 0
		EndIf
	EndIf
EndFunc   ;==>__BigNum_DivComp

Func __BigNum_DivAdd($sX, $sY)
	Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = ""
	If $iLen < $iTmp Then $iLen = $iTmp
	For $i = 1 To $iLen Step 18
		$iTmp = Int(StringRight($sX, 18)) + Int(StringRight($sY, 18)) + $iCar
		$sX = StringTrimRight($sX, 18)
		$sY = StringTrimRight($sY, 18)
		If ($iTmp > 999999999999999999) Then
			$sRet = StringRight($iTmp, 18) & $sRet
			$iCar = 1
		Else
			$iTmp = StringRight("000000000000000000" & $iTmp, 18)
			$sRet = $iTmp & $sRet
			$iCar = 0
		EndIf
	Next
	$sRet = StringRegExpReplace($iCar & $sRet, "^0+([^0]|0$)", "\1", 1)
	Return $sRet
EndFunc   ;==>__BigNum_DivAdd

Func __BigNum_DivSub($sX, $sY)
	Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = ""
	If $iLen < $iTmp Then $iLen = $iTmp
	For $i = 1 To $iLen Step 18
		$iTmp = Int(StringRight($sX, 18)) - Int(StringRight($sY, 18)) - $iCar
		$sX = StringTrimRight($sX, 18)
		$sY = StringTrimRight($sY, 18)
		If $iTmp < 0 Then
			$iTmp = 1000000000000000000 + $iTmp
			$iCar = 1
		Else
			$iCar = 0
		EndIf
		$sRet = StringRight("0000000000000000000" & $iTmp, 18) & $sRet
	Next
	$sRet = StringRegExpReplace($iCar & $sRet, "^0+([^0]|0$)", "\1", 1)
	Return $sRet
EndFunc   ;==>__BigNum_DivSub

Func __BigNum_IsValid($sX, $sY)
	If StringRegExp($sX, "[^0-9.-]") Or StringRegExp($sY, "[^0-9.-]") Then Return False
	Return True
EndFunc   ;==>__BigNum_IsValid

Func __BigNum_InsertDecimalSeparator($sX, $iDec, $iD = 18)
	If $iD = 0 And $iDec = 0 Then Return $sX
	Local $sRet = StringRegExpReplace(StringRight(StringFormat("%0" & String($iDec) & "u", "") & $sX, $iDec), "0+$", "\1", 1)
	$sX = StringTrimRight($sX, $iDec)
	If $sX = "" Then $sX = "0"
	$sRet = StringLeft($sRet, $iD)
	If $sRet = "" Or $sRet = "0" Then Return $sX
	Return $sX & "." & $sRet
EndFunc   ;==>__BigNum_InsertDecimalSeparator

Func __BigNum_StringIsDecimal(ByRef $sX, ByRef $sY)
	If StringLeft($sX, 1) = "." Then $sX = "0" & $sX
	If StringLeft($sY, 1) = "." Then $sY = "0" & $sY
	Local $iPsX = StringInStr($sX, ".", 0, 1) - 1, $iPsY = StringInStr($sY, ".", 0, 1) - 1
	$sX = StringRegExpReplace($sX, "\D", "")
	$sY = StringRegExpReplace($sY, "\D", "")
	Local $iLnX = StringLen($sX), $iLnY = StringLen($sY)
	If $iPsX <= 0 Then $iPsX = $iLnX
	If $iPsY <= 0 Then $iPsY = $iLnY
	If $iLnX - $iPsX > $iLnY - $iPsY Then
		For $iCnt = $iLnY - $iPsY To $iLnX - $iPsX - 1
			$sY &= "0"
		Next
		Return $iLnX - $iPsX
	ElseIf $iLnX - $iPsX < $iLnY - $iPsY Then
		For $iCnt = $iLnX - $iPsX To $iLnY - $iPsY - 1
			$sX &= "0"
		Next
		Return $iLnY - $iPsY
	EndIf
	Return $iLnX - $iPsX
EndFunc   ;==>__BigNum_StringIsDecimal

Func __BigNum_CheckNegative(ByRef $sX, ByRef $sY)
	Local $bNgX = False, $bNgY = False
	While StringLeft($sX, 1) = "-"
		$bNgX = Not $bNgX
		$sX = StringTrimLeft($sX, 1)
	WEnd
	While StringLeft($sY, 1) = "-"
		$bNgY = Not $bNgY
		$sY = StringTrimLeft($sY, 1)
	WEnd
	$sX = StringRegExpReplace($sX, "^0+([^0]|0$)", "\1", 1)
	$sY = StringRegExpReplace($sY, "^0+([^0]|0$)", "\1", 1)
	If $sX = "" Then $sX = "0"
	If $sY = "" Then $sY = "0"
	If $bNgX = True And $bNgY = True Then
		Return 3
	ElseIf $bNgX = True And $bNgY = False Then
		Return 1
	ElseIf $bNgX = False And $bNgY = True Then
		Return 2
	Else
		Return 0
	EndIf
EndFunc   ;==>__BigNum_CheckNegative
#EndRegion Internal Functions