'
' BIGINT
'
' A small library having support for so-called 'big integers',
' which are unsigned data types consisting of a maximum of
' 262144 bits = 32768 bytes.
' Compare this with a normal integer: 16 bits = 2 bytes!
'
' Actually, this version of BIGINT has support for:
' - String integers (max value = 32768x a 9)

' Have fun!
'
' -Neo Deus Ex Machina
'
'       X
'      XXX
'     X   X
'    XXX XXX
'
' HAR-SoftWare
'
' PS: This is the VB-Version

CONST LN.E = 2.718281828#
DEFLNG A-Z
'$DYNAMIC

FUNCTION SI.Log10&(StrInt AS STRING)
	SI.Log10& = LEN(StrInt) - 1
END FUNCTION

FUNCTION SI.IsEven(StrInt AS STRING) AS BOOLEAN
	a& = LEN(StrInt)
	IF a& = 0 THEN SI.IsEven = FALSE: EXIT FUNCTION
        char$ = MID$(StrInt, a&, 1)
        vals% = VAL(char$)
        IF vals% AND 1 THEN SI.IsEven = FALSE ELSE SI.IsEven = TRUE
END FUNCTION

FUNCTION SI.IsUnEven(StrInt AS STRING) AS BOOLEAN
	a& = LEN(StrInt)
	IF a& = 0 THEN SI.IsUnEven = FALSE: EXIT FUNCTION
        char$ = MID$(StrInt, a&, 1)
        vals% = VAL(char$)
        IF vals% AND 1 THEN SI.IsUnEven = TRUE ELSE SI.IsUnEven = FALSE
END FUNCTION

FUNCTION SI.IsEqual(StrInt AS STRING, StrInt2 AS STRING) AS BOOLEAN
        IF StrInt = StrInt2 THEN SI.IsEqual = TRUE ELSE SI.IsEqual = FALSE
END FUNCTION

FUNCTION SI.IsZero(StrInt AS STRING) AS BOOLEAN
	len1 = LEN(StrInt)
	FOR c = 1 TO len1
		IF MID$(StrInt, c, 1) <> "0" THEN
			SI.IsZero = FALSE
			EXIT FUNCTION
		END IF
	NEXT c
	SI.IsZero = TRUE
END FUNCTION

FUNCTION SI.IsGreater(StrInt AS STRING, StrInt2 AS STRING) AS BOOLEAN
	IF LEN(StrInt) > LEN(StrInt2) THEN
		SI.IsGreater = TRUE
		EXIT FUNCTION
	ELSEIF (LEN(StrInt) < LEN(StrInt2)) OR (StrInt = StrInt2) THEN
		SI.IsGreater = FALSE
		EXIT FUNCTION
	END IF
	leng& = LEN(StrInt)
	val1% = 0
	val2% = 0
	posi& = 1
        DO
		val1% = VAL(MID$(StrInt, posi&, 1))
		val2% = VAL(MID$(StrInt2, posi&, 1))
		posi& = posi& + 1
	LOOP UNTIL val1% <> val2%
        IF val1% > val2% THEN
        	SI.IsGreater = TRUE
        	EXIT FUNCTION
        ELSE
        	SI.IsGreater = FALSE
        END IF
END FUNCTION

FUNCTION SI.IsSmaller(StrInt AS STRING, StrInt2 AS STRING) AS BOOLEAN
	IF LEN(StrInt) < LEN(StrInt2) THEN
		SI.IsSmaller = TRUE
		EXIT FUNCTION
	ELSEIF (LEN(StrInt) > LEN(StrInt2)) OR (StrInt = StrInt2) THEN
		SI.IsSmaller = FALSE
		EXIT FUNCTION
	END IF
	leng& = LEN(StrInt)
	val1% = 0
	val2% = 0
	posi& = 1
        DO
		val1% = VAL(MID$(StrInt, posi&, 1))
		val2% = VAL(MID$(StrInt2, posi&, 1))
		posi& = posi& + 1
	LOOP UNTIL val1% <> val2%
        IF val1% < val2% THEN
        	SI.IsSmaller = TRUE
        	EXIT FUNCTION
        ELSE
        	SI.IsSmaller = FALSE
        END IF
END FUNCTION

FUNCTION SI.Add$(StrInt AS STRING, StrInt2 AS STRING)
	'
	' This functions adds two String ints to eachother and
	' returns the answer in a string int
	'

	'declare stuff
        DIM len1 AS LONG, len2 AS LONG, maxlen AS LONG
        DIM StrAns AS STRING, c AS LONG, char1 AS STRING, char2 AS STRING
        len1 = LEN(StrInt)
        len2 = LEN(StrInt2)

        'pick out maximum length of the strings
        IF len1<len2 THEN
        	maxlen = len2
        	StrAns = SPACE$(len2 + 1)
        ELSE
        	maxlen = len1
        	StrAns = SPACE$(len1 + 1)
        END IF

	'calculate StrInt + StrInt2
	over% = 0
	' PRINT maxlen
        FOR c = 1 TO maxlen
        	IF c <= LEN(StrInt) THEN char1 = MID$(StrInt, len1 - c + 1, 1) ELSE char1 = "0"
		IF c <= LEN(StrInt2) THEN char2 = MID$(StrInt2, len2 - c + 1, 1) ELSE char2 = "0"
		val1 = VAL(char1)
		val2 = VAL(char2)
		' print val1,val2
		ans$ = LTRIM$(STR$(val1 + val2 + over%))
		MID$(StrAns, LEN(StrAns) - c + 1, 1) = RIGHT$(ans$, 1)
		IF LEN(ans$) > 1 THEN
			over% = VAL(LEFT$(ans$, 1))
		ELSE
			over% = 0
		END IF
        NEXT c
        StrAns = LTRIM$(StrAns)
        IF over% > 0 THEN StrAns = LTRIM$(STR$(over%)) + StrAns
        IF SI.IsZero(StrAns) THEN StrAns = "0"
        SI.Add$ = StrAns
END FUNCTION


FUNCTION SI.Subtract$(StrInt AS STRING, StrInt2 AS STRING)
	'
	' This functions subtracts two String ints to eachother and
	' returns the answer in a string int
	'

	'declare stuff
	DIM len1 AS LONG, len2 AS LONG, maxlen AS LONG
        DIM StrAns AS STRING, c AS LONG, char1 AS STRING, char2 AS STRING
        len1 = LEN(StrInt)
        len2 = LEN(StrInt2)

        'if the length of StrInt2 > StrInt then the answer is negative -> not allowed
        IF SI.IsGreater(StrInt2, StrInt) THEN SI.Subtract$ = "0": EXIT FUNCTION

        'pick out maximum length of the strings
        IF len1<len2 THEN
        	maxlen = len2
        	StrAns = SPACE$(len2 + 1)
        ELSE
        	maxlen = len1
        	StrAns = SPACE$(len1 + 1)
        END IF

	'calculate StrInt - StrInt2
	over% = 0
	' PRINT maxlen
        FOR c = 1 TO maxlen
        	IF c <= LEN(StrInt) THEN char1 = MID$(StrInt, len1 - c + 1, 1) ELSE char1 = "0"
		IF c <= LEN(StrInt2) THEN char2 = MID$(StrInt2, len2 - c + 1, 1) ELSE char2 = "0"
		val1 = VAL(char1)
		val2 = VAL(char2)
		' print val1,val2
		ans$ = LTRIM$(STR$(10 + val1 - val2 + over%))
		MID$(StrAns, LEN(StrAns) - c + 1, 1) = RIGHT$(ans$, 1)
		IF LEN(ans$) > 1 THEN
			over% = 0
		ELSE
			over% = -1
		END IF
        NEXT c
        StrAns = LTRIM$(StrAns)
        'IF (over% = 0) AND (LEN(StrAns) > 1) THEN StrAns = RIGHT$(StrAns, LEN(StrAns) - 1)
        WHILE (LEFT$(StrAns, 1) = "0") AND (LEN(StrAns) > 1)
        	StrAns = RIGHT$(StrAns, LEN(StrAns) - 1)
        WEND
        SI.Subtract$ = StrAns
END FUNCTION


FUNCTION SI.Multiply$(StrInt AS STRING, StrInt2 AS STRING)
	'
	' This functions multiplies two String ints to eachother and
	' returns the answer in a string int
	'

	'declare stuff
        DIM len1 AS LONG, len2 AS LONG, maxlen AS LONG
        DIM StrAns AS STRING, c AS LONG, char1 AS STRING, char2 AS STRING
        DIM TempAns AS STRING
        len1 = LEN(StrInt)
        len2 = LEN(StrInt2)

        'pick out maximum length of the strings
        IF len1<len2 THEN
        	maxlen = len2
        	' StrAns = SPACE$(len2 + 1)
        ELSE
        	maxlen = len1
        	' StrAns = SPACE$(len1 + 1)
        END IF
        StrAns = "0"

	'calculate StrInt + StrInt2
	over% = 0
	' PRINT maxlen
        FOR d = 1 TO len2
        	IF d>1 THEN
        		TempAns=STRING$(d-1,"0")
        	ELSE
        		TempAns=""
        	END IF
        	over% = 0
        	char2 = MID$(StrInt2, len2 - d + 1, 1)
		val2 = VAL(char2)
        	FOR c = 1 TO len1
        		char1 = MID$(StrInt, len1 - c + 1, 1)
        		'print char1;" ";char2
			val1 = VAL(char1)
                        ans$ = LTRIM$(STR$(val1 * val2 + over%))
                        'print ans$
			TempAns = RIGHT$(ans$, 1) + TempAns
			'print TempAns
			IF LEN(ans$) > 1 THEN
				over% = VAL(LEFT$(ans$, 1))
			ELSE
				over% = 0
			END IF
		NEXT c
		IF over% > 0 THEN TempAns = LTRIM$(STR$(over%)) + TempAns
		StrAns = SI.Add$(StrAns, TempAns)
		'PRINT StrAns
        NEXT d
        StrAns = LTRIM$(StrAns)
        IF SI.IsZero(StrAns) THEN StrAns = "0"
        SI.Multiply$ = StrAns
END FUNCTION

FUNCTION SI.Divide$(StrInt AS STRING, StrInt2 AS STRING)
	'
	' This functions divides two String ints to eachother and
	' returns the answer in a string int
	'

	'declare stuff
        DIM len1 AS LONG, len2 AS LONG, maxlen AS LONG
        DIM StrAns AS STRING, c AS LONG, char1 AS STRING, char2 AS STRING
        DIM TempD AS STRING, TempAns AS STRING, TempA AS STRING
        len1 = LEN(StrInt)
        len2 = LEN(StrInt2)

        'check if the division will be good
        IF SI.IsGreater(StrInt2, StrInt) THEN SI.Divide$ = "0": EXIT FUNCTION
        IF SI.IsZero(StrInt2) THEN
        	SI.Divide$ = "0"
        	EXIT FUNCTION
        END IF

        'pick out maximum length of the strings
        IF len1<len2 THEN
        	maxlen = len2
        	' StrAns = SPACE$(len2 + 1)
        ELSE
        	maxlen = len1
        	' StrAns = SPACE$(len1 + 1)
        END IF
        StrAns = ""

	'calculate StrInt / StrInt2
	over$ = ""
	charlen = len2 - 1
	' PRINT maxlen
	'endofloop = len1
	TempD = LEFT$(StrInt, charlen)
	inhowmuch$ = ""
	TempAns = ""
        FOR c = charlen + 1 TO len1
                TempD = TempD + MID$(StrInt, c, 1)
                'PRINT "D-String:",TempD
                inhowmuch$ = "0"
                inhowmuch$ = SI.SmallDivide$(TempD, StrInt2)
                'PRINT "I-String:",inhowmuch$
                TempAns = TempAns + inhowmuch$
                TempA = SI.Multiply$(inhowmuch$, StrInt2)
                TempD = SI.Subtract$(TempD, TempA)
                IF SI.IsZero(TempD) THEN TempD = ""
                'PRINT "S-String:",TempD
        NEXT c
        'StrAns = TempAns
        WHILE (LEN(TempAns) > 1) AND (LEFT$(TempAns, 1) = "0")
        	TempAns = RIGHT$(TempAns, LEN(TempAns) - 1)
        WEND
        StrAns = TempAns
        IF SI.IsZero(StrAns) THEN StrAns = "0"
        SI.Divide$ = StrAns
END FUNCTION

FUNCTION SI.SmallDivide$(StrInt AS STRING, StrInt2 AS STRING)
        ' first check if the division is ok
        IF SI.IsGreater(StrInt2, StrInt) = TRUE THEN
        	SI.SmallDivide$ = "0"
        	EXIT FUNCTION
        END IF
        IF StrInt = StrInt2 THEN
        	SI.SmallDivide$ = "1"
        	EXIT FUNCTION
        END IF

        over$ = StrInt
        times$ = "0"
        DO
        	over$ = SI.Subtract(over$, StrInt2)
        	times$ = SI.Add(times$, "1")
        LOOP UNTIL over$ = "0"
        IF SI.Multiply$(times$, StrInt2) <> StrInt THEN
        	SI.SmallDivide$ = SI.Subtract$(times$, "1")
        ELSE
        	SI.SmallDivide$ = times$
        END IF
END FUNCTION

FUNCTION SI.Mod$(StrInt AS STRING, StrInt2 AS STRING)
	'calculates StrInt MOD StrInt2
        SI.Mod$ = SI.Subtract$(StrInt, SI.Multiply$(SI.Divide$(StrInt, StrInt2), StrInt2))
END FUNCTION

FUNCTION SI.ShiftLeft$(StrInt AS STRING, Positions AS LONG)
	IF NOT(SI.IsZero(StrInt)) THEN SI.ShiftLeft$ = StrInt + STRING$(Positions, "0") ELSE SI.ShiftLeft$ = "0"
END FUNCTION

FUNCTION SI.ShiftRight$(StrInt AS STRING, Positions AS LONG)
	IF LEN(StrInt) <= Positions THEN
		SI.ShiftRight$ = "0"
		EXIT FUNCTION
	END IF
        SI.ShiftRight$ = LEFT$(StrInt, LEN(StrInt) - Positions)
END FUNCTION

FUNCTION SI.Power$(StrInt AS STRING, StrInt2 AS STRING)
	' calculates StrInt ^ StrInt2
	DIM Remind AS STRING
	DIM Pow AS STRING
	DIM BaseN AS STRING

	'some criteria
	IF SI.IsZero(StrInt2) THEN SI.Power$ = "1" : EXIT FUNCTION
	IF StrInt2 = "1" THEN SI.Power$ = StrInt : EXIT FUNCTION

	Pow = StrInt2
	BaseN = StrInt
	Remind = "1"
	DO
		IF SI.IsUnEven(Pow) THEN		'uneven
			Remind = SI.Multiply$(Remind, BaseN)
			Pow = SI.Subtract$(Pow, "1")
		END IF
		Pow = SI.Divide$(Pow,"2")
		BaseN = SI.Multiply$(BaseN, BaseN)
	LOOP UNTIL Pow = "1"
	SI.Power$ = SI.Multiply$(Remind, BaseN)
END FUNCTION
