How not to lose decimals when doing "longProperty1.divide (longProperty2)"?

1

What I want to do is very simple, I just do not know how to "do it right" in JavaFX:

I have two LongProperty ( num1 e num2 ) and a DoubleProperty ( resultado ) , where this DoubleProperty resultado must contain - always updated - the value of the division of num1 by num2 .

I can already do this with the code resultado.bind(num1.divide(num2)); , but the problem is that this way I lose the precision of the decimal places , and I need the decimal places.

From what I've noticed, the problem is that doing num1.divide(num2) the method divide " returns an LongBinding (because split variables are LongProperty s) instead of returning a DoubleBinding , and it seems like this LongBinding that deletes the decimal places.

I tried to make num1 and num2 also be DoubleProperty and make num1.divide(num2) ; and worked: the divide method returned a DoubleBinding that preserved the decimal places in resultado . But I want num1 and num2 to be LongProperty s, so how do I do it?

I've managed to get around the problem with a gambiarra that shows what I need:

import javafx.beans.binding.DoubleBinding;
import javafx.beans.binding.NumberBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleLongProperty;

public class DoubleBindingEmDivisaoDeLong {

    public static void main(String[] args) {
        teste1_divisaoPerdeAsCasasDecimais();
        teste2_divisaoMantemAsCasasDecimais();
    }

    private static void teste1_divisaoPerdeAsCasasDecimais() {
        final DoubleProperty resultado = new SimpleDoubleProperty(0.0);
        final LongProperty num1 = new SimpleLongProperty(45);
        final LongProperty num2 = new SimpleLongProperty(7);
        NumberBinding divide = num1.divide(num2); // O método divide Retorna um "LongBinding" (veja a linha abaixo para confirmar)
        System.out.println(divide);// Imprime: "LongBinding [invalid]"
        resultado.bind(divide);

        System.out.println(resultado.get()); // Imprime: "6.0" ao invés de "6.428571428571429" (perdeu as casas decimais)
    }

    private static void teste2_divisaoMantemAsCasasDecimais() {
        final DoubleProperty resultado = new SimpleDoubleProperty(0.0);
        final LongProperty num1 = new SimpleLongProperty(45);
        final LongProperty num2 = new SimpleLongProperty(7);

        final DoubleProperty num1Double = new SimpleDoubleProperty(0.0);
        num1Double.bind(num1);
        final DoubleProperty num2Double = new SimpleDoubleProperty(0.0);
        num2Double.bind(num2);

        DoubleBinding divide = num1Double.divide(num2Double); // O método divide Retorna um "DoubleBinding"
        resultado.bind(divide);

        System.out.println(resultado.get()); // Imprime "6.428571428571429" como desejado
    }
}
Note that in the code above, what works in test2 is the fact that I have created num1Double and num2Double which are DoubleProperty if they make bind in num1 and num2 respectively, and have done something equivalent to resultado.bind(num1Double.divide(num2Double)); , that is, a gambiarra for something that should be very simple and already provided in JavaFX.

So how do you do the "right way" in JavaFX?

    
asked by anonymous 16.09.2017 / 23:39

2 answers

1

I got a good answer on SOen here , below is a translation / adaptation of it:

  

Methods provided by LongProperty (and by others NumberExpression ) as divide(...) are just convenience methods; but you can create a custom binding that does what you want:

final DoubleProperty result = new SimpleDoubleProperty(0.0);
final LongProperty longProperty1 = new SimpleLongProperty(812323534);
final LongProperty longProperty2 = new SimpleLongProperty(956745323);
result.bind(Bindings.createDoubleBinding(() -> longProperty1.longValue() / (double) longProperty2.longValue(),
    longProperty1, longProperty2));
System.out.println(result.get());
longProperty1.set(612323534);
System.out.println(result.get());
     

Bindings is a utilitarian class to create bindings . Here I've created a custom binding that returns a double casting from the split of long s to double , but there is a loss of precision.      

The output of the above code is:

0.8490488685670847
0.6400068223798362

Through this response, I get a DoubleBiding created by createDoubleBinding (...) that will keep result always updated with the result of splitting longProperty1 by longProperty2 .

That is, when the value of any of these two variables is changed (either longProperty1 or longProperty2 ), the division will be reprocessed automatically and result will automatically update with the new result of the division.

See the example below:

final DoubleProperty result = new SimpleDoubleProperty(0.0);
final LongProperty longProperty1 = new SimpleLongProperty(45);
final LongProperty longProperty2 = new SimpleLongProperty(7);

result.bind(Bindings.createDoubleBinding(() -> longProperty1.longValue() / (double) longProperty2.longValue(),
            longProperty1, longProperty2));

System.out.println(result.get()); // imprime "6.428571428571429", que é 45 dividido por 7

longProperty1.set(100); // longProperty1 agora contém o valor 100
System.out.println(result.get()); // imprime "14.285714285714286", que é 100 dividido por 7

longProperty2.set(876); // longProperty2 agora contém o valor 876
System.out.println(result.get()); // imprime "0.1141552511415525", que é 100 dividido por 876

Note that decimal places are preserved as I need them, and even if the precision of the result is affected at the time of splitting, I can still store gigantic numbers ( long ) within of longProperty1 and longProperty2 without being affected, and it is not necessary to transform them into DoubleProperty s.

    
17.09.2017 / 23:45
1

I've honestly never used this Java FX API, but I've experienced the same "problem" in many different APIs and languages.

Basically, what seems to occur is that when you work with integer types, the division is whole as well.

Notice that I wrote "problem" in quotation marks above because it is more a feature than a bug. Some languages or APIs automatically upgrade from integer to decimal, others do not, with advantages and disadvantages for each approach.

In your case, I'd say changing% w / w% w / w% to your% w /% w /% w /% would be a reasonable way to solve the problem, in the sense that you're normalizing your variables using decimal types rather than mixing decimals and integers.

    
17.09.2017 / 01:53