B4J Question How to do division of two Ints as integer division instead of floating point division?

emexes

Expert
Licensed User
B4X:
Dim Temp As Int = NewX * 2 + 1
Dim Temp1 As Int = Temp * SrcWidth
Dim Temp2 As Int = (NewWidth * 2)
Temp = Temp1 / Temp2

decompiles to:

Java:
int var23 = var21 * 2 + 1;
int var24 = var23 * var17;
int var25 = var1 * 2;
int var10000 = (int)((double)var24 / (double)var25);

Is there any way to get the castings out of the division line, without using inline Java?
 
Last edited:

MicroDrie

Well-Known Member
Licensed User
We are now a lot of posts further but I think the second post is still the solution to have full control over an integer division. I realize that B4XPages is the contemporary development standard and that, given all previous posts, this challenge is would be a exception to the advice not to use Java but B4X program language.

The code below uses two variables and the result of the integer division of the two given integer variables is placed in a third variable, so what more would you ask for now that you are able to use your desired integer division?

B4X Inline integer division:
Public Sub Initialize
'    B4XPages.GetManager.LogEvents = True
    Me.As(JavaObject).RunMethod("startIntDiv", Array(7,3))
    Dim Value1 As Int = 4
    Dim Value2 As Int = 3
    Me.As(JavaObject).RunMethod("startIntDiv", Array(Value1, Value2))
End Sub

Private Sub send_ii(i As Int)
'    --- Show result Java integer division
    Log(i)
End Sub

#IF JAVA

    // result will be 7 / 3 = 2 and 4 / 3 = 1  
    public void startIntDiv(int value1, int value2){
        subIiEvent("send", IntDiv(value1, value2));
    }
   
    public void subIiEvent(String EventName,int values) {
        getBA().raiseEventFromUI(this, EventName.toLowerCase(BA.cul) + "_ii", values);
    }
#End If
 
Last edited:
Upvote 0

OliverA

Expert
Licensed User
Longtime User
We are now a lot of posts further but I think the second post is still the solution to have full control over an integer division.
The issue though is overhead. So now we got rid of the casting, but we introduce a function call and then an entry into the event queue for something as simple as needing a plain integer division (without casting). It would not hurt to put in a wish to have something like this in the B4X language (nudge @emexes for placing a wish) <maybe not, see below>
 
Last edited:
Upvote 0

kimstudio

Active Member
Licensed User
Longtime User
Another benchmarking article just for reference, this time on JVM:

Qoute: "
  • Back to the original question: can floating point division be faster than the integer one?
  • Amazingly yes! The benchmark shows that float division is ~30% faster than integer division (which is approximately the same speed as double division and both are 2x faster than long division)
"

Now I intend to just use int division in B4X way and not call inline java cause it may be slower, not mention the furthermore function calling overhead.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
(nudge @emexes for placing a wish)
Well, maybe not.

can floating point division be faster than the integer one?

I don't know, but it looks like casting in Java does not seem to detrimentally impact performance. Here is a not-quite-proper test of B4X casted division vs Java's integer division:

B4X:
	Dim jo As JavaObject = Me
	Dim start, stop, loopCount As Long
	loopCount = 10000000000
	Log($"Executing B4X's "integer" division ${loopCount} times"$)
	start = DateTime.Now
	b4xIntDiv(5, 7, loopCount)
	stop = DateTime.Now
	Log($"b4xIntDiv took ${stop-start} ticks to complete ${loopCount} operations"$)

	Log($"Executing Java's integer division ${loopCount} times"$)
	start = DateTime.Now
	jo.RunMethod("JavaIntDiv", Array(5, 7, loopCount))
	stop = DateTime.Now
	Log($"Java took ${stop-start} ticks to complete ${loopCount} operations"$)

B4X:
public Sub b4xIntDiv(a As Int, b As Int, loopCount As Long) As Int
	Dim result As Int
	Dim counter As Long
	Do While counter < loopCount
		result = a / b
		counter = counter + 1
	Loop
	Return result
End Sub

B4X:
#IF JAVA
    public static int JavaIntDiv (int a, int b, long loopCount){
	int result = 0;
	for (long counter=0; counter < loopCount; counter++) {
		result = a / b; // result will be 7 / 3 = 2 and 4 / 3 = 1
	}
    return result;
    }
#End If
Note: Slightly modified code from @MicroDrie

Results (note I had to really up the loop count to get some difference out of these two operations):
Executing B4X's "integer" division 10000000000 times
b4xIntDiv took 3780 ticks to complete 10000000000 operations
Executing Java's integer division 10000000000 times
JavaIntDiv took 3670 ticks to complete 10000000000 operations

I know there is the call overhead of the function call, counter incrementation, and counter comparison, but in the end, it looks like it's not worth mulling over B4X's implementation of division that uses casting vs Java's implementation of integer division as it pertains to the system I'm using. Maybe other (older?) systems see more of a difference.

Update: Forgot to include b4xIntDiv sub
 
Upvote 0

kimstudio

Active Member
Licensed User
Longtime User
@OliverA why I got this by copying your code in: (may share your project zip?)

Executing B4X's "integer" division 10000000000 times
b4xIntDiv took 2916 ticks to complete 10000000000 operations
Executing Java's integer division 10000000000 times
Java took 20918 ticks to complete 10000000000 operations
 
Upvote 0

kimstudio

Active Member
Licensed User
Longtime User
Same code, Java 8 is faster than Java 14?

Run on Java 8:

Executing B4X's "integer" division 10000000000 times
b4xIntDiv took 2319 ticks to complete 10000000000 operations
Result = 0
Executing Java's integer division 10000000000 times
Java took 2340 ticks to complete 10000000000 operations
Result = 0


Run on Java 14:

Executing B4X's "integer" division 10000000000 times
b4xIntDiv took 4676 ticks to complete 10000000000 operations
Result = 0
Executing Java's integer division 10000000000 times
Java took 21005 ticks to complete 10000000000 operations
Result = 0
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User

Attachments

  • TestJavaOutputIntDiv.zip
    1.3 KB · Views: 44
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Run on Java 14:
I was using JDK 11.0.1

Another run:
Executing B4X's "integer" division 10000000000 times
b4xIntDiv took 4007 ticks to complete 10000000000 operations
Executing Java's integer division 10000000000 times
Java took 3995 ticks to complete 10000000000 operations

Looks like JDK 14.0.1 is slowing something down...
Executing B4X's "integer" division 10000000000 times
b4xIntDiv took 4023 ticks to complete 10000000000 operations
Executing Java's integer division 10000000000 times
Java took 29658 ticks to complete 10000000000 operations

JDK 16.0.1 did not improve anything (that's the only other one I have):
Executing B4X's "integer" division 10000000000 times
b4xIntDiv took 4962 ticks to complete 10000000000 operations
Executing Java's integer division 10000000000 times
Java took 28013 ticks to complete 10000000000 operations

I should have tested this before pushing for a change in B4X. Looks like Java integer division took a nosedive after JDK 11.

Update: All JDK editions are OpenJDK. I don't know if Oracle's JDK would have some sort of optimizations to "fix" this issue...
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
I got (but I did modify code a little) on java 22


Executing B4X's "integer" division 10000000000 times
b4xIntDiv took 3060 ticks to complete 10000000000 operations
Executing Java's integer division 10000000000 times
Java took 2708 ticks to complete 10000000000 operations
Program terminated (StartMessageLoop was not called).
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
As nothing was done with the result (yes openjdk 22)
B4X:
#IF JAVA

public static void JavaIntDiv (int a, int b, long loopCount){
    int result = 0;
    long lc = 0;
    while (lc++ < loopCount){
        result = a / b; // result will be 7 / 3 = 2 and 4 / 3 = 1
        }

    }
#End If
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
while (lc++ < loopCount){
Wow. That's it! Using a for loop in JDK 14/16 seems to be a show-stopper <see below>

Executing B4X's "integer" division 10000000000 times
b4xIntDiv took 4882 ticks to complete 10000000000 operations
Executing Java's integer division 10000000000 times
Java took 25584 ticks to complete 10000000000 operations
Executing Java's integer division (while loop) 10000000000 times
Java (while loop) took 4393 ticks to complete 10000000000 operations
 
Last edited:
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
Executing B4X's "integer" division 10000000000 times
b4xIntDiv took 3042 ticks to complete 10000000000 operations
Executing Java's integer division 10000000000 times
Java took 14510 ticks to complete 10000000000 operations


@kimstudio good catch - if the value was used/returned the times shoot up.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
if the value was used/returned the times shoot up.
Same here, so B4X's way is the way to go (and something is bonkers with JDK above 11)
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
ignore this post - I tried something and it never worked (I previously posted the code here)
 
Last edited:
Upvote 0

QSerg

Member
Then use inline java as other already mentioned.
Andreas.
Do you honestly believe that using in-line Java is quicker/simpler/more robust than use int() function? It came back again and again to the same point - why I have to cater for all this cr... stuff from the beginning? If you know such underwater stones then you can deal with them in numerous ways, but again why they have to be here in the first place? And no-one discard performance issue either.
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
I suspected that the times posted for B4X divisions were too small.
As @kimstudio suggested for the Java routine, the optimizer figured that nothing was happening.
I added two simple lines to make the loops work harder. I also reduced the loop size by 100, because I was impatient.

'Executing B4X's "integer" division 100000000 times
'b4xIntDiv took 363 ticks To complete 100000000 operations
'Executing Java's integer division 100000000 times
'Java took 116 ticks To complete 100000000 operations

The Java computation are 3x faster than the B4X code on my machine.
However, a call to Java for individual values might be slower.
I'll test that next.

B4X:
Sub Button1_Click
    xui.MsgboxAsync("Hello World!", "B4X")
  
    Dim jo As JavaObject = Me
    Dim start, stop, loopCount As Long
    loopCount = 100000000
    Log($"Executing B4X's "integer" division ${loopCount} times"$)
    start = DateTime.Now
    b4xIntDiv(5, 7, loopCount)
    stop = DateTime.Now
    Log($"b4xIntDiv took ${stop-start} ticks to complete ${loopCount} operations"$)

    Log($"Executing Java's integer division ${loopCount} times"$)
    start = DateTime.Now
    jo.RunMethod("JavaIntDiv", Array(5, 7, loopCount))
    stop = DateTime.Now
    Log($"Java took ${stop-start} ticks to complete ${loopCount} operations"$)
End Sub

'Executing B4X's "integer" division 100000000 times
'b4xIntDiv took 363 ticks To complete 100000000 operations
'Executing Java's integer division 100000000 times
'Java took 116 ticks To complete 100000000 operations


public Sub b4xIntDiv(a As Int, b As Int, loopCount As Long) As Int
    Dim result As Int
    Dim counter As Long
    Do While counter < loopCount
        a = a + 1    '<== added this
        b = b + 1    '<== added this
        result = a / b
        counter = counter + 1
    Loop
    Return result
End Sub

#IF JAVA
    public static int JavaIntDiv (int a, int b, long loopCount){
    int result = 0;
    for (long counter=0; counter < loopCount; counter++) {
        a++;     '<== added this
        b++;     '<== added this
        result = a / b;
    }
    return result;
    }
#End If
 
Upvote 0
Top