190 lines
5.6 KiB
Plaintext
190 lines
5.6 KiB
Plaintext
Structure decDigitFmt ;decimal digit format
|
|
Array Digit.b(0) ;contains each digit of number, right-most digit is index 0
|
|
digitCount.i ;zero based
|
|
sign.i ; {x < 0} = -1, {x = 0} = 0, {x > 0} = 1
|
|
EndStructure
|
|
|
|
Global zero_decDigitFmt.decDigitFmt ;represents zero in the decimal digit format
|
|
|
|
;converts string representation of integer into the digit format, number can include signus but no imbedded spaces
|
|
Procedure stringToDecDigitFmt(numString.s, *x.decDigitFmt)
|
|
Protected *c.Character, digitIdx, digitCount
|
|
If numString And *x
|
|
*c.Character = @numString
|
|
Repeat
|
|
Select *c\c
|
|
Case '0' To '9', '-', '+'
|
|
*c + SizeOf(Character)
|
|
Default
|
|
numString = Left(numString, *c - @numString)
|
|
Break
|
|
EndSelect
|
|
ForEver
|
|
*c = @numString
|
|
Select *c\c
|
|
Case '-'
|
|
*x\sign = -1
|
|
*c + SizeOf(Character)
|
|
Case '+'
|
|
*x\sign = 1
|
|
*c + SizeOf(Character)
|
|
Case '0' To '9'
|
|
*x\sign = 1
|
|
EndSelect
|
|
|
|
numString = LTrim(PeekS(*c), "0") ;remove leading zeroes
|
|
If numString = "" ;is true if equal to zero or if only a signus is present
|
|
CopyStructure(@zero_decDigitFmt, *x, decDigitFmt)
|
|
ProcedureReturn
|
|
EndIf
|
|
*c = @numString
|
|
|
|
digitCount = Len(PeekS(*c)) - 1
|
|
Dim *x\Digit(digitCount)
|
|
*x\digitCount = digitCount
|
|
|
|
digitIdx = 0
|
|
While *c\c
|
|
If *c\c >= '0' And *c\c <= '9'
|
|
*x\Digit(digitCount - digitIdx) = *c\c - '0'
|
|
digitIdx + 1
|
|
*c + SizeOf(Character)
|
|
Else
|
|
Break
|
|
EndIf
|
|
Wend
|
|
|
|
EndIf
|
|
EndProcedure
|
|
|
|
;converts digit format representation of integer into string representation
|
|
Procedure.s decDigitFmtToString(*x.decDigitFmt)
|
|
Protected i, number.s
|
|
If *x
|
|
If *x\sign = 0
|
|
number = "0"
|
|
Else
|
|
|
|
For i = *x\digitCount To 0 Step -1
|
|
number + Str(*x\Digit(i))
|
|
Next
|
|
number = LTrim(number, "0")
|
|
If *x\sign = -1
|
|
number = "-" + number
|
|
EndIf
|
|
EndIf
|
|
EndIf
|
|
|
|
ProcedureReturn number
|
|
EndProcedure
|
|
|
|
;handles only positive numbers and zero, negative numbers left as an exercise for the reader ;)
|
|
Procedure add_decDigitFmt(*a.decDigitFmt, *b.decDigitFmt, *sum.decDigitFmt, digitPos = 0) ;*sum contains the result of (*a ) * 10^digitPos + (*b)
|
|
Protected carry, i, newDigitCount, workingSum, a_dup.decDigitFmt
|
|
|
|
If *a And *b And *sum
|
|
|
|
If *a = *sum: CopyStructure(*a, @a_dup, decDigitFmt): *a = @a_dup: EndIf ;handle special case of *sum + *b = *sum
|
|
If *b <> *sum: CopyStructure(*b, *sum, decDigitFmt): EndIf ;handle general case of *a + *b = *sum and special case of *a + *sum = *sum
|
|
|
|
;calculate number of digits needed for sum and resize array of digits if necessary
|
|
newDigitCount = *a\digitCount + digitPos
|
|
If newDigitCount >= *sum\digitCount
|
|
If *sum\digitCount = newDigitCount And *sum\Digit(*sum\digitCount) <> 0
|
|
newDigitCount + 1
|
|
EndIf
|
|
|
|
If *sum\digitCount <> newDigitCount
|
|
*sum\digitCount = newDigitCount
|
|
Redim *sum\Digit(*sum\digitCount)
|
|
EndIf
|
|
EndIf
|
|
|
|
i = 0
|
|
Repeat
|
|
If i <= *a\digitCount
|
|
workingSum = *a\Digit(i) + *sum\Digit(digitPos) + carry
|
|
Else
|
|
workingSum = *sum\Digit(digitPos) + carry
|
|
EndIf
|
|
|
|
If workingSum > 9
|
|
carry = 1
|
|
workingSum - 10
|
|
Else
|
|
carry = 0
|
|
EndIf
|
|
*sum\Digit(digitPos) = workingSum
|
|
digitPos + 1
|
|
i + 1
|
|
Until i > *a\digitCount And carry = 0
|
|
|
|
If *a\sign <> 0 Or *sum\sign <> 0
|
|
*sum\sign = 1 ;only handle positive numbers and zero for now
|
|
EndIf
|
|
EndIf
|
|
EndProcedure
|
|
|
|
Procedure multiply_decDigitFmt(*a.decDigitFmt, *b.decDigitFmt, *product.decDigitFmt) ;*product contains the result of (*a) * (*b)
|
|
Protected i, digitPos, productSignus
|
|
Protected Dim multTable.decDigitFmt(9)
|
|
Protected NewList digitProduct.decDigitFmt()
|
|
|
|
If *a And *b And *product
|
|
If *a\sign = 0 Or *b\sign = 0
|
|
CopyStructure(zero_decDigitFmt, *product, decDigitFmt)
|
|
ProcedureReturn
|
|
EndIf
|
|
|
|
If *b\digitCount > *a\digitCount: Swap *a, *b: EndIf
|
|
|
|
;build multiplication table
|
|
CopyStructure(*a, @multTable(1), decDigitFmt): multTable(1)\sign = 1 ;always positive
|
|
For i = 2 To 9
|
|
add_decDigitFmt(*a, multTable(i - 1), multTable(i))
|
|
Next
|
|
|
|
;collect individual digit products for later summation; these could also be added as we go along
|
|
For i = 0 To *b\digitCount
|
|
AddElement(digitProduct())
|
|
digitProduct() = multTable(*b\Digit(i))
|
|
Next
|
|
|
|
;determine sign of product
|
|
If *a\sign <> *b\sign
|
|
productSignus = -1
|
|
Else
|
|
productSignus = 1
|
|
EndIf
|
|
|
|
digitPos = 0
|
|
CopyStructure(zero_decDigitFmt, *product, decDigitFmt)
|
|
ForEach digitProduct()
|
|
add_decDigitFmt(digitProduct(), *product, *product, digitPos)
|
|
digitPos + 1
|
|
Next
|
|
*product\sign = productSignus ;set sign of product
|
|
EndIf
|
|
EndProcedure
|
|
|
|
;handles only positive integer exponents or an exponent of zero, does not raise an error for 0^0
|
|
Procedure exponent_decDigitFmt(*a.decDigitFmt, exponent, *product.decDigitFmt)
|
|
Protected i, a_dup.decDigitFmt
|
|
If *a And *product And exponent >= 0
|
|
If *a = *product: CopyStructure(*a, @a_dup, decDigitFmt): *a = @a_dup: EndIf
|
|
stringToDecDigitFmt("1", *product)
|
|
For i = 1 To exponent: multiply_decDigitFmt(*product, *a, *product): Next
|
|
EndIf
|
|
EndProcedure
|
|
|
|
If OpenConsole()
|
|
Define a.decDigitFmt, product.decDigitFmt
|
|
|
|
stringToDecDigitFmt("2", a)
|
|
exponent_decDigitFmt(a, 64, a) ;2^64
|
|
multiply_decDigitFmt(a, a, product)
|
|
PrintN("The result of 2^64 * 2^64 is " + decDigitFmtToString(product))
|
|
Print(#crlf$ + #crlf$ + "Press ENTER to exit"): Input()
|
|
CloseConsole()
|
|
EndIf
|