Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

PB/DLL Big Number Multiplication

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • PB/DLL Big Number Multiplication

    'This was written in response to those who want to have results
    ' with greater than 18 significant digits. This is only a
    ' demonstration of the Multiplication algorithm.
    '
    ' I make no claim for this code being optimized.
    ' It is good enough for every day use.
    '
    'The program assumes positive, non-unicode string representations of numbers,
    ' including decimals. If you want to multiply signed numbers, then it is a
    ' simple task to determine the sign of the result.

    ' Enjoy,
    ' Ian Cairns
    Code:
    #COMPILE EXE
    #INCLUDE "Win32Api.Inc"
    DECLARE FUNCTION BigMultiply(BYVAL value1 AS STRING, BYVAL value2 AS STRING) AS STRING
    DECLARE SUB DecLeftFix(value AS LONG, carry AS LONG)
    GLOBAL numOffset AS LONG
    ' This global represents the offsets of the ASCII numeric codes.
    ' This will not work under unicode. The purpose was to speed up the program
    ' by bypassing conversions from ASCII code to String Representation of
    ' the character to the actual numeric value (ie. VAL(CHR$(<pointer-to-byte> )) ).
    FUNCTION PBMAIN
      STATIC Var1      AS STRING, _
             Var2      AS STRING, _
             VarResult AS STRING
    
      numOffset = 48 ' the digit 0 is at offset 48
      Var1 = "123456789.123456789"
      Var2 = "987654321.987654321"
      VarResult = BigMultiply(Var1, Var2)
      MSGBOX "Multiply: " + var1 + CHR$(13) + _
             "    With: " + var2 + CHR$(13) + _
             "  Equals: " + VarResult
    
    END FUNCTION
    '=========================================
    FUNCTION BigMultiply(BYVAL value1 AS STRING, BYVAL value2 AS STRING) AS STRING
      LOCAL v1      AS LONG, _
            v2      AS LONG, _
            carry   AS LONG, _
            index   AS LONG, _
            maxPos  AS LONG, _
            v1Len   AS LONG, _
            v2Len   AS LONG, _
            v1Ptr   AS BYTE PTR, _
            v2Ptr   AS BYTE PTR, _
            v1Reset AS DWORD, _
            op1     AS LONG, _
            op2     AS LONG, _
            decimal AS LONG, _
            test    AS LONG, _
            result  AS STRING
    
      decimal = 0  ' assume no decimals
      test = INSTR(-1, value1, ".")
      IF test > 0 THEN
        decimal = LEN(value1) - test
        value1 = REMOVE$(value1, ".")
      END IF
      v1Ptr = STRPTR(value1)
      v1Len = LEN(value1)
    
      test = INSTR(-1, value2, ".")
      IF test > 0 THEN
        decimal = decimal + LEN(value2) - test
        value2 = REMOVE$(value2, ".")
      END IF
      v2Ptr = STRPTR(value2)
      v2Len = LEN(value2)
    
      IF v1Len > v2Len THEN ' It is faster to multiply the longer string by the shorter string
        SWAP v1Ptr, v2Ptr
        SWAP v1Len, v2Len
      END IF
      DIM cArray(1:v1Len + v2Len) AS LOCAL LONG ' Allow for the maximum length of the result
      maxPos = 1                                ' Allow for a shorter result than the length of the array
      v1Reset = v1Ptr           ' The pointer will be reset for every digit of the multiplying factor
      v2Ptr = v2Ptr + v2Len - 1 ' Start multiplication from the right side of the string.
      FOR v2 = 1 TO v2Len
        op2 = @v2Ptr - numOffset ' Alternative for: op2 = VAL(CHR$(@v2Ptr))
        DECR v2Ptr
        v1Ptr = v1Reset + v1Len - 1 ' Reset pointer for another pass.
        FOR v1 = 1 TO v1Len
          op1 = @v1Ptr - numOffset  ' Alternative for: op1 = VAL(CHR$(@v1Ptr))
          DECR v1Ptr ' Move from the right to the left
          op1 = op1 * op2
          index = v2 + v1 - 1 ' Watch for powers of 10
          maxPos = MAX&(maxPos, index)
          cArray(index) = cArray(index) + op1
        NEXT v1
      NEXT v2
    ' Fixup the carries and create a result string
      result = ""
      FOR index = 1 TO maxPos + 1 ' Allow for a carry!
        CALL CarryFixup(cArray(index), carry)
        result = FORMAT$(cArray(index) ) + result
        IF carry > 0 THEN cArray(index+1) = cArray(index+1) + carry
      NEXT i
      IF decimal > 0 THEN
        result = LEFT$(result, LEN(result) - decimal ) + "." + RIGHT$(result, decimal)
        result = RTRIM$(result, ANY "0.")
      END IF
      result = LTRIM$(result, "0")
      IF result = "" THEN result = "0"
      FUNCTION = result
    END FUNCTION
    '=========================================
    SUB CarryFixup(value AS LONG, carry AS LONG)
      carry = 0
      IF value > 9 THEN
        carry = FIX(value/10)
        value = value - (carry * 10)
      END IF
    END SUB
    '=========================================
    ------------------
    [email protected]
    :) IRC :)
Working...
X