B4J Question B4J vs Java Calculation

Johan Schoeman

Expert
Licensed User
Longtime User
I have this string in a text file:

B4X:
448.12024391174316,262.125

A Java project that I am trying to convert to B4J as well as my B4J project both logs this correctly (let call it an X and Y value separated by a ","

In both the B4J and Java projects the following applies:
B4X:
    width = 1280   'declared as an int
    height = 720   'declared as an int
    minusheight = height / 1.65    'declared as Double
    minuswidth = width / 2.5    'declared as Double
    devide = height / 300    'declared as Double

The confusing part is this:

B4J code:
        Dim c As ComplexNumber
        c.Initialize((s.substring2(0, comaindex) - minuswidth) / devide, _
        (s.substring2(comaindex + 1, s.length()) - minusheight) / devide)
        X.add(c)

        Log("c.re = " & c.re)
        Log("c.im = " & c.im)

Java code:
            ComplexNumber c = new ComplexNumber((Double.valueOf(s.substring(0, comaindex)) - minuswidth) / devide,
                    (Double.valueOf(s.substring(comaindex + 1, s.length())) - minusheight) / devide);
            X.add(c);
            BA.Log("c.re = " + (Double.valueOf(s.substring(0, comaindex)) - minuswidth) / devide);
            BA.Log("c.im = " + (Double.valueOf(s.substring(comaindex + 1, s.length())) - minusheight) / devide);

With the same initial value (x = 448.12024391174316 and y = 262.125) the calculation results are as follows:
B4J re value = -26.616565036773686
B4J im value = -72.59943181818183

Java re value = -31.93987804412842
Java im value = -87.11931818181819

With my calculator I calculate the results of re and im to be the same as that of the B4J code.

What is happening here? Why the difference?
 
Solution
the B4J code and inline java code yields different answers for Re and Im. The inline java code yields the correct answers. The B4J code does not.

You can make the B4J results match the Java results by forcing emulating integer division using Floor() :
B4X:
width = 1280
height = 720
minusheight = height / 1.65
minuswidth = width / 2.5
devide = Floor(height / 300)
  
time = 0.0f
Log output:
Waiting for debugger to connect...
Program started.
s = 448.12024391174316,262.125
B4J Re = -31.93987804412842
B4J Im = -87.11931818181819
Java Re = -31.93987804412842
Java Im = -87.11931818181819

emexes

Expert
Licensed User
Why the difference?

For a start, the Java code is returning the initializing expressions directly, whereas the B4J code is logging the components of c.

Presumably they should be the same, assuming that the X.Add(c) has no effect on c.

Also, it might be useful wise to also Log the inputs for both code examples, to be sure, to be sure.

I could test it better if I knew where to find the ComplexNumber library or class. Closest I found is:

https://www.b4x.com/android/forum/threads/math-complex-number-library.67742/
 
Last edited:
Upvote 0

Johan Schoeman

Expert
Licensed User
Longtime User
For a start, the Java code is returning the initializing expressions directly, whereas the B4J code is logging the components of c.

Presumably they should be the same, assuming that the X.Add(c) has no effect on c.

Also, it'd be useful to verify that the inputs are the same for both code examples.

I could test it better if I knew where to find the ComplexNumber library or class. Closest I found is:

https://www.b4x.com/android/forum/threads/math-complex-number-library.67742/
The problem is not in the Complex class. It is the calculations using the x an y input values that are different. The Complex class just sets Re and Im and do nothing more. As said, the calculations yield different results and that is what I am trying to understand.

Even when I log just the calcs (before assigning them to a Complex class) they are not the same. Does the Double.valueOf(xxxx) maybe had something to do with the difference in calc results?
 
Upvote 0

Johan Schoeman

Expert
Licensed User
Longtime User
For a start, the Java code is returning the initializing expressions directly, whereas the B4J code is logging the components of c.

Presumably they should be the same, assuming that the X.Add(c) has no effect on c.

Also, it might be useful wise to also Log the inputs for both code examples, to be sure, to be sure.

I could test it better if I knew where to find the ComplexNumber library or class. Closest I found is:

https://www.b4x.com/android/forum/threads/math-complex-number-library.67742/
For what it might be worth - the Complex class is as follows:
Complex number (Java):
public class ComplexNumber {
    public double re, im;

    public ComplexNumber(double a, double b) {
        re=a;
        im=b;
    }
}
 
Upvote 0

Johan Schoeman

Expert
Licensed User
Longtime User
B4J code:
        Dim c As ComplexNumber
        c.Initialize((s.substring2(0, comaindex) - minuswidth) / devide, _
        (s.substring2(comaindex + 1, s.length()) - minusheight) / devide)
        X.add(c)

        Log("c.re = " & c.re)
        Log("c.im = " & c.im)

Also the spurious () of s.length() doesn't instil confidence of a successful copy-paste.
I have logged it in both B4J and Java and the split of the input strings (and doubles) into x and y values are correct. Even when I log the doubles created from the split of the input string.
 
Upvote 0

emexes

Expert
Licensed User
I broke it down into smaller steps:
B4X:
Dim width As Int = 1280   'declared as an int
Dim height As Int = 720   'declared as an int
Dim minusheight As Double = height / 1.65    'declared as Double
Dim minuswidth As Double = width / 2.5    'declared as Double
Dim devide As Double = height / 300    'declared as Double

Dim s As String = "448.12024391174316,262.125"

Dim comaindex As Int = s.IndexOf(",")

Dim s1 As String = s.substring2(0, comaindex)
Dim s2 As String = s.substring2(comaindex + 1, s.Length())

Dim re As Double = (s1 - minuswidth) / devide
Dim im As Double = (s2 - minusheight) / devide

Log(s1)
Log(s2)
Log(re)
Log(im)
Log output:
Waiting for debugger to connect...
Program started.
448.12024391174316
262.125
-26.616565036773686
-72.59943181818183
Program terminated (StartMessageLoop was not called).
which looks as expected. Maybe doing same with Java will identify the problem.
 
Last edited:
Upvote 0

emexes

Expert
Licensed User
I have logged it in both B4J and Java and the split of the input strings (and doubles) into x and y values are correct. Even when I log the doubles created from the split of the input string.

Sounds like you beat me to it. ?

In which case: that is an interesting problem. Maybe Java casts differently.
 
Upvote 0

Johan Schoeman

Expert
Licensed User
Longtime User
I broke it down into smaller steps:

B4X:
Dim width As Int = 1280   'declared as an int
Dim height As Int = 720   'declared as an int
Dim minusheight As Double = height / 1.65    'declared as Double
Dim minuswidth As Double = width / 2.5    'declared as Double
Dim devide As Double = height / 300    'declared as Double

Dim s As String = "448.12024391174316,262.125"

Dim comaindex As Int = s.IndexOf(",")

Dim s1 As String = s.substring2(0, comaindex)
Dim s2 As String = s.substring2(comaindex + 1, s.Length())

Dim re As Double = (s1 - minuswidth) / devide
Dim im As Double = (s2 - minusheight) / devide

Log(s1)
Log(s2)
Log(re)
Log(im)

which worked as expected. Maybe doing same with Java will identify the problem.
My laptop is not on at present. What is the values that you have logged with your code? The B4J values that I have posted or the Java values?
 
Upvote 0

Johan Schoeman

Expert
Licensed User
Longtime User
I broke it down into smaller steps:
B4X:
Dim width As Int = 1280   'declared as an int
Dim height As Int = 720   'declared as an int
Dim minusheight As Double = height / 1.65    'declared as Double
Dim minuswidth As Double = width / 2.5    'declared as Double
Dim devide As Double = height / 300    'declared as Double

Dim s As String = "448.12024391174316,262.125"

Dim comaindex As Int = s.IndexOf(",")

Dim s1 As String = s.substring2(0, comaindex)
Dim s2 As String = s.substring2(comaindex + 1, s.Length())

Dim re As Double = (s1 - minuswidth) / devide
Dim im As Double = (s2 - minusheight) / devide

Log(s1)
Log(s2)
Log(re)
Log(im)
Log output:
Waiting for debugger to connect...
Program started.
448.12024391174316
262.125
-26.616565036773686
-72.59943181818183
Program terminated (StartMessageLoop was not called).
which looks as expected. Maybe doing same with Java will identify the problem.
Your log output is not the same as the Java output. It is the same as what I calculate in my B4J project but not the same as that of the working Java project.
 
Upvote 0

emexes

Expert
Licensed User
The problem is that a division that has two int components eg height / 300 will be done using integer math rather than real math.
Fixed by either changing the second line from int to double, or by changing the fifth line by either adding a (double) cast or changing 300 to 300.0 eg:

Java:
int width = 1280;   //declared as an int
int height = 720;   //declared as an int
double minusheight = height / 1.65;    //declared as Double
double minuswidth = width / 2.5;    //declared as Double
double devide = height / 300.0;    //declared as Double

String s = "448.12024391174316,262.125";

int comaindex = s.indexOf(",");

String s1 = s.substring(0, comaindex);
String s2 = s.substring(comaindex + 1, s.length());

double re = (Double.valueOf(s1) - minuswidth) / devide;
double im = (Double.valueOf(s2) - minusheight) / devide;

System.out.println(s1);
System.out.println(s2);
System.out.println(re);
System.out.println(im);
Output:
E:\UTIL>c:\java\jdk-14.0.1\bin\java.exe test
448.12024391174316
262.125
-26.616565036773686
-72.59943181818183
 
Last edited:
Upvote 0

Johan Schoeman

Expert
Licensed User
Longtime User
Fixed by either changing the first two lines from ints to doubles, or adding (double) casts to the next three lines eg:
Java:
int width = 1280;   //declared as an int
int height = 720;   //declared as an int
double minusheight = (double) height / 1.65;    //declared as Double
double minuswidth = (double) width / 2.5;    //declared as Double
double devide = (double) height / 300;    //declared as Double

String s = "448.12024391174316,262.125";

int comaindex = s.indexOf(",");

String s1 = s.substring(0, comaindex);
String s2 = s.substring(comaindex + 1, s.length());

double re = (Double.valueOf(s1) - minuswidth) / devide;
double im = (Double.valueOf(s2) - minusheight) / devide;

System.out.println(s1);
System.out.println(s2);
System.out.println(re);
System.out.println(im);
Output:
E:\UTIL>c:\java\jdk-14.0.1\bin\java.exe test
448.12024391174316
262.125
-26.616565036773686
-72.59943181818183
The result is still the same as my B4J project. It does not match the Java project. Give a minute or so and will upload my B4J project where I have added inline Java code. The inline Java code yields the correct result as per the Java project but B4J reports the incorrect values. It is mind boggling.
 
Upvote 0

Johan Schoeman

Expert
Licensed User
Longtime User
The problem is that a division that has two int components eg height / 300 will be done using integer math rather than real math.
Fixed by either changing the second line from int to double, or adding (double) cast to the fifth line eg:
Java:
int width = 1280;   //declared as an int
int height = 720;   //declared as an int
double minusheight = height / 1.65;    //declared as Double
double minuswidth = width / 2.5;    //declared as Double
double devide = (double) height / 300;    //declared as Double

String s = "448.12024391174316,262.125";

int comaindex = s.indexOf(",");

String s1 = s.substring(0, comaindex);
String s2 = s.substring(comaindex + 1, s.length());

double re = (Double.valueOf(s1) - minuswidth) / devide;
double im = (Double.valueOf(s2) - minusheight) / devide;

System.out.println(s1);
System.out.println(s2);
System.out.println(re);
System.out.println(im);
Output:
E:\UTIL>c:\java\jdk-14.0.1\bin\java.exe test
448.12024391174316
262.125
-26.616565036773686
-72.59943181818183
Look what the B4J and the inline Java code logs in the attached project. I have added a break point on line 119 of the B4J project so that only the calcs of first line from the text file (String s = "448.12024391174316,262.125") is used to compare the calcs. See the B4J log.

B4X:
WARNING: package com.sun.javafx.embed.swing.oldimpl not in javafx.swing
Waiting for debugger to connect...
Program started.
s = 448.12024391174316,262.125
B4J Re = -26.616565036773686
B4J Im = -72.59943181818183
Java Re = -31.93987804412842
Java Im = -87.11931818181819
 

Attachments

  • b4jFourierEmbed.zip
    72.2 KB · Views: 214
Upvote 0

Johan Schoeman

Expert
Licensed User
Longtime User
On a positive note: at least we are 100% agreed about this. ?
Just to be sure the first string is the same....but getting the same result i.e B4J and Java calcs are different
 

Attachments

  • b4jFourierEmbed.zip
    72.2 KB · Views: 159
Upvote 0

emexes

Expert
Licensed User
Fixed by forcing the division to be real rather than integer:
Java:
String s = "448.12024391174316,262.125";
int width = 1280;
int height = 720;
Double minusheight = height / 1.65;
double minuswidth = width / 2.5;
double devide = height / 300.0;
int comaind

comaindex = s.indexOf(",");
Double aa = (Double.valueOf(s.substring(0, comaindex)) - minuswidth) / devide;
Double bb = (Double.valueOf(s.substring(comaindex + 1, s.length())) - minusheight) / devide;
BA.Log("Java Re = " + aa);
BA.Log("Java Im = " + bb);
Log output:
Waiting for debugger to connect...
Program started.
s = 448.12024391174316,262.125
B4J Re = -26.616565036773686
B4J Im = -72.59943181818183
Java Re = -26.616565036773686
Java Im = -72.59943181818183
 
Upvote 0

emexes

Expert
Licensed User
Fixed by forcing the division to be real rather than integer:
although I think adding the .0 casts the 300 to a float rather than a double, and so maybe the division is only done to float (single) precision too ?
so if you want to be *really* sure of what's going on, use a (double) cast instead :cool:
 
Upvote 0

Johan Schoeman

Expert
Licensed User
Longtime User
Fixed by forcing the division to be real rather than integer:
Java:
String s = "448.12024391174316,262.125";
int width = 1280;
int height = 720;
Double minusheight = height / 1.65;
double minuswidth = width / 2.5;
double devide = height / 300.0;
int comaind

comaindex = s.indexOf(",");
Double aa = (Double.valueOf(s.substring(0, comaindex)) - minuswidth) / devide;
Double bb = (Double.valueOf(s.substring(comaindex + 1, s.length())) - minusheight) / devide;
BA.Log("Java Re = " + aa);
BA.Log("Java Im = " + bb);
Log output:
Waiting for debugger to connect...
Program started.
s = 448.12024391174316,262.125
B4J Re = -26.616565036773686
B4J Im = -72.59943181818183
Java Re = -26.616565036773686
Java Im = -72.59943181818183
Nope. You need to match the Java project values. Not what we are calculating. See what the inline java code is logging vs the B4J code:

B4J re value = -26.616565036773686
B4J im value = -72.59943181818183

Java re value = -31.93987804412842
Java im value = -87.11931818181819

We need to match the values of the Java code.
 
Upvote 0
Top