Sometimes its just fun to play with code.

Daestrum

Expert
Licensed User
Longtime User
I started playing around writing some code, purely to understand how CPUs actually multiply numbers and how they add numbers.

You might wonder why I did it as + and * are built into B4X.

Well lets just say the last test run I did took 87 seconds to multiply 2 binary numbers.

The fun part, one was a 500,000,000 bit number, the other was 187 bits long.

The add and multiply work exactly like the logic gates in the CPU silicon. It doesnt use add or multiply.

On smaller numbers the code is quite fast, it can multiply two 50,000 bit numbers in 11 seconds.

Just a fun experiment as to how CPUs actually work.

See post #6 for the corrected version.
 
Last edited:

rabbitBUSH

Well-Known Member
Licensed User
Longtime User
If you live as close to Greenwich as you do - are those 11 secs the same as the 11secs where I live - Boy That Is An idle moments project - worthy of a mathematical recreations bit in Scientific American.....
 

Daestrum

Expert
Licensed User
Longtime User
It was funny trying to check the results, as soon as you get above 200 bit numbers theres no easy way (online checkers etc) that can work with those sized numbers.

I have since broken the logic which I am trying to fix. (I started using char arrays)
 

Daestrum

Expert
Licensed User
Longtime User
Fixed it - heres the code
B4X:
#Region Project Attributes 
    #CommandLineArgs:
    #MergeLibraries: True 
    #JavaCompilerPath: 24, D:\jdk-24\bin\javac.exe
#End Region

Sub Process_Globals
    Dim mycopy As JavaObject
    Dim myzeroes As JavaObject
    Dim carryflag As Boolean = False
End Sub

Sub AppStart (Args() As String)
    mycopy.InitializeStatic("java.lang.System")
    myzeroes.InitializeStatic("java.util.Arrays")

    Dim sb,sb1 As StringBuilder
    sb.Initialize
    sb1.Initialize
    Dim start As Long = DateTime.now
    For digitmaker = 1 To 4096 * 16
                If Rnd(0,1000) > 500 Then
            sb.Append("1")
        Else
            sb.Append("0")
        End If
    Next
    For digitmaker = 1 To 4096 * 8
        If Rnd(0,1000) > 500 Then
            sb1.Append("1")
        Else
            sb1.Append("0")
        End If
    Next
    Log("Made string in " & ( DateTime.Now - start) & "ms")

    Dim la,lb As Int
    la=sb.As(JavaObject).RunMethod("length",Null)
    lb=sb1.As(JavaObject).RunMethod("length",Null)
    
    Dim arrayresult(la + lb + 1) As Char

    myzeroes.RunMethod("fill", Array(arrayresult, "0".As(Char)))
    
    Dim array1(la),array2(lb) As Char
    
    array1 = sb.As(JavaObject).RunMethodJO("reverse",Null).RunMethodJO("toString",Null).RunMethod("toCharArray",Null)
    array2 = sb1.As(JavaObject).RunMethodJO("reverse",Null).RunMethodJO("toString",Null).RunMethod("toCharArray",Null)

    Dim start As Long = DateTime.NOW    
    binary_multiply(array1,array2,False)
    Log($"mul Took ${(DateTime.now - start)}ms"$)

End Sub

Sub binary_multiply(array1x() As Char, array2x() As Char,quiet As Boolean)As Object

    Dim temp(array1x.Length + array2x.Length + 1) As Char
    'Log("temp array is : " & temp.Length)
    For Each thing In temp
        thing = "0"
    Next
    
    If array1x.Length <= array2x.length Then
        Dim longer() As Char = array2x
        Dim shorter() As Char = array1x
    Else
        Dim shorter() As Char = array2x
        Dim longer() As Char = array1x
    End If
    
    For loop1 = 0 To shorter.length - 1
        If shorter(loop1) = "1" Then
            Dim shifted(longer.length + 1) As Char
            shifted = arraycopy(longer, loop1)
            temp = doadd(temp,shifted)
        End If
    Next
    
    If Not(quiet) Then
        Dim finalBinary As String = ""

        For Each digit As Char In temp
            finalBinary = digit & finalBinary
        Next

        Return finalBinary
    End If
    Return temp
End Sub

Sub doadd(ar1() As Char, ar2() As Char) As Object
    
    Dim temp(ar1.Length) As Char 

    myzeroes.RunMethod("fill", Array(temp, "0".As(Char)))

    For xx = 0 To ar2.length-1
        temp(xx) = bitadd(ar2(xx),ar1(xx))
    Next
    For xx = ar2.Length To ar1.Length-1
        temp(xx) = bitadd(ar1(xx),"0")
    Next
    Return temp    
    
End Sub

Sub arraycopy(src() As Char,shift As Int) As Object
    Dim temp(src.Length + shift) As Char
    mycopy.RunMethod("arraycopy", Array(src, 0, temp, shift, src.Length))
    Return temp
End Sub

Sub printshifted(s() As Char)As String
    Dim res As String = ""
    For Each thing As Char In s
        If thing = "1" Then 
            res = res & "1"
        Else
            res = res & "0"    
        End If
    Next
    If res.Length <> s.Length Then Log("Size error")
    Return res
End Sub

Sub bitadd(v As Char,v1 As Char) As Char
    If v <> "1" Then v = "0"
    
    If carryflag Then
        If v = "0" And v1 = "0" Then
            carryflag = False :     Return "1"
        End If
        If (v = "1" And v1 = "0") Or (v = "0" And v1 = "1") Then
            carryflag = True :    Return "0"
        End If
        If v = "1" And v1 = "1" Then
            carryflag = True : Return "1"
        End If
    Else
        If v = "0" And v1 = "0" Then
            carryflag = False : Return "0"
        End If
        If (v = "1" And v1 = "0") Or (v = "0" And v1 = "1") Then
            carryflag = False : Return "1"
        End If
        If v = "1" And v1 = "1" Then
            carryflag = True : Return "0"
        End If
    End If
    Return "x"
End Sub
 

Daestrum

Expert
Licensed User
Longtime User
Just noticed the code may have a bug in it (nothing bad just logic error), looking at it now.
 

Daestrum

Expert
Licensed User
Longtime User
Corrected optimised code (plus it does it in pure java too - to see speed increase)

B4X:
'Non-UI application (console / server application)
#Region Project Attributes
    #CommandLineArgs:
    #MergeLibraries: True
    #JavaCompilerPath: 24, D:\jdk-24\bin\javac.exe
#End Region

Sub Process_Globals
    Dim mycopy As JavaObject
    Dim myzeroes As JavaObject
    Dim carryflag As Boolean = False
    Dim justOne() As Char = Array As Char("1")
End Sub

Sub AppStart (Args() As String)
    mycopy.InitializeStatic("java.lang.System")
    myzeroes.InitializeStatic("java.util.Arrays")

    Dim sb,sb1 As StringBuilder
    sb.Initialize
    sb1.Initialize
    Dim start As Long = DateTime.now
    For digitmaker = 1 To 64000
        If Rnd(0,1000) > 500 Then
            sb.Append("1")
        Else
            sb.Append("0")
        End If
    Next
    For digitmaker = 1 To 32000
        If Rnd(0,1000) > 500 Then
            sb1.Append("1")
        Else
            sb1.Append("0")
        End If
    Next
    'sb.Append("111010")
    'sb1.Append("111")
    'Log(sb.ToString)
    'Log(sb1.ToString)
    Log("Made string in " & ( DateTime.Now - start) & "ms")
    Dim la,lb As Int
    la=sb.As(JavaObject).RunMethod("length",Null)
    lb=sb1.As(JavaObject).RunMethod("length",Null)
  
    Dim arrayresult(la + lb + 1) As Char

    myzeroes.RunMethod("fill", Array(arrayresult, "0".As(Char)))
  
    Dim array1(la),array2(lb) As Char
  
    array1 = sb.As(JavaObject).RunMethodJO("reverse",Null).RunMethodJO("toString",Null).RunMethod("toCharArray",Null)
    array2 = sb1.As(JavaObject).RunMethodJO("reverse",Null).RunMethodJO("toString",Null).RunMethod("toCharArray",Null)

    Log($"multiplying  ${array1.length} bits by ${array2.length} bits"$)
    Log("B4J code version")
    Dim b4janswer As String = binary_multiply(array1,array2,False)
    Dim start As Long = DateTime.NOW
    printshifted(binary_multiply(array1,array2,True))
    Log($"mul Took ${(DateTime.now - start)}ms"$)
    'java version
    Dim b(array1.length),b1(array2.length) As Byte
    For aa = 0 To array1.Length -1
        If array1(aa) = "1" Then
            b(aa) = 1
        Else
            b(aa) = 0
        End If
    Next
    For aa = 0 To array2.Length -1
        If array2(aa) = "1" Then
            b1(aa) = 1
        Else
            b1(aa) = 0
        End If
    Next
    Me.as(JavaObject).RunMethod("setcarryclear",Null)
    Log("pure java version")
    Dim javaanswer As String = printshiftedbyte(Me.as(JavaObject).RunMethod("multiply",Array(b, b1)))
    Dim start As Long = DateTime.NOW
    printshiftedbyte(Me.as(JavaObject).RunMethod("multiply",Array(b, b1)))
    Log($"mul Took ${(DateTime.now - start)}ms"$)

    If b4janswer = javaanswer Then
        Log("Matched"    )
    Else
        'Log(b4janswer)
        'Log(javaanswer)
    End If
End Sub

Sub binary_multiply(array1x() As Char, array2x() As Char,quiet As Boolean)As Object

    Dim temp(array1x.Length + array2x.Length) As Char 'was +1

    myzeroes.RunMethod("fill", Array(temp, "0".As(Char)))
  
    If array1x.Length <= array2x.length Then
        Dim longer() As Char = array2x
        Dim shorter() As Char = array1x
    Else
        Dim shorter() As Char = array2x
        Dim longer() As Char = array1x
    End If
  
    For loop1 = 0 To shorter.length - 1
        If shorter(loop1) = "1" Then
            Dim shifted(longer.length + 1) As Char
            shifted = arraycopy(longer, loop1)
            'Log(printshifted(shifted))
            temp = doadd(temp,shifted)
        End If
    Next
  
    If Not(quiet) Then
        Dim finalBinary As String = ""

        For Each digit As Char In temp
            finalBinary = digit & finalBinary
        Next

        Return finalBinary
    End If
    Return temp
End Sub

Sub doadd(ar1() As Char, ar2() As Char) As Object
  
    Dim temp(ar1.Length) As Char

    myzeroes.RunMethod("fill", Array(temp, "0".As(Char)))

    For xx = 0 To ar2.length-1
        temp(xx) = bitadd(ar2(xx),ar1(xx))
    Next
    For xx = ar2.Length To ar1.Length-1
        temp(xx) = bitadd(ar1(xx),"0")
    Next
    Return temp
  
End Sub

Sub arraycopy(src() As Char,shift As Int) As Object
    Dim temp(src.Length + shift) As Char
    mycopy.RunMethod("arraycopy", Array(src, 0, temp, shift, src.Length))
    Return temp
End Sub

Sub printshifted(s() As Char)As String
    Dim res As String = ""
    For Each thing As Char In s
        If thing = "1" Then
            res = "1" & res
        Else
            res = "0" & res
        End If
    Next
    If res.Length <> s.Length Then Log("Size error")
    Do While res.StartsWith("00")
        res = res.SubString(1)
    Loop
    Return res
End Sub

Sub printshiftedbyte(s() As Byte)As String
    Dim res As String = ""
    For Each thing As Byte In s
        If thing = 1 Then
            res = "1" & res
        Else
            res = "0" & res
        End If
    Next
    If res.Length <> s.Length Then Log("Size error")
    Do While res.StartsWith("00")
        res = res.SubString(1)
    Loop
    Return res
End Sub
Sub bitadd(v As Char,v1 As Char) As Char
    If v <> "1" Then v = "0"

    If carryflag Then
        If v = "0" And v1 = "0" Then
            carryflag = False
            Return "1"
        Else If v = "1" And v1 = "1" Then
            Return "1"
        Else
            Return "0"
        End If
    Else
        If v = "0" And v1 = "0" Then
            Return "0"
        Else If v = "1" And v1 = "1" Then
            carryflag = True
            Return "0"
        Else
            Return "1"
        End If
    End If
End Sub

Sub compliment(vc() As Char) As Object
    Dim temp(vc.length) As Char
    Dim temp1(vc.Length) As Char

    For xx = 0 To vc.Length -1
            temp(xx) = IIf(vc(xx)="1","0","1")
    Next
    temp1 = doadd(temp,justOne)
    Return temp1
End Sub

#If java
import java.util.Arrays;
import java.lang.System;

public static boolean carryflag = false;

public static byte bitadds(byte x, byte y){
//System.out.println("x= "+ x + " y= "+y+" carry = " + carryflag);
    if (carryflag)
    {
        if (x==0 && y==0) {carryflag=false; return 1;}
        else if (x==1 && y==1) {return 1;}
        else {return 0;}
    }
    else
    {
        if (x==0 && y==0) {return 0;}
        else if (x==1 && y==1) {carryflag = true; return 0;}
        else {return 1;}
    }
}

public static byte[] doAdd(byte[] ar1, byte[] ar2) {
    byte[] temp = new byte[ar1.length];

    Arrays.fill(temp, (byte) 0);

    for (int xx = 0; xx < ar2.length; xx++) {
        temp[xx] = bitadds(ar2[xx], ar1[xx]);
    }
    for (int xx = ar2.length; xx < ar1.length; xx++) {
        temp[xx] = bitadds(ar1[xx], (byte) 0);
    }
    return temp;
}

public static byte[] multiply(byte[] ar1, byte[] ar2){
    byte[] temp = new byte[ar1.length + ar2.length];

    Arrays.fill(temp, (byte) 0);
  
    byte[] longer, shorter;
  
    if (ar1.length <= ar2.length) {
        longer = ar2;
        shorter = ar1;
    } else {
        longer = ar1;
        shorter = ar2;
    }

    for (int loop1 = 0; loop1 < shorter.length; loop1++) {
        if (shorter[loop1] == 1) {
            byte[] shifted = new byte[longer.length + loop1];
            System.arraycopy(longer, 0, shifted, loop1, longer.length);
            temp = doAdd(temp, shifted);
        }
    }
    return temp;
}
public static void setcarryclear(){
    carryflag = false;
}
#End If

64000 bit number * 32000 bit number
B4J = 19568ms
Java = 6433ms

To be fair , in release mode the gap is tiny < 500ms, so hats off to Erel for translating B4J to java so well.
 
Last edited:
Top