zjuhasz zjuhasz - 2 months ago 17
Java Question

Java units of measurement library addition and subtraction returning incorrect values

I'm using the reference implementation of JSR363. I've tried many variations of this but I'll give this code as an example.

ServiceProvider provider = ServiceProvider.current();
QuantityFactory<Length> lengthFactory = provider.getQuantityFactory(Length.class);
Quantity<Length> first = factory.create(5, Units.METRE.divide(100.0));
Quantity<Length> second = factory.create(3, Units.METRE);
System.out.println(second.add(first));


This prints 503.0 m. Clearly something is very wrong and this should be 3.05 m. I find it very hard to believe that this is actually a bug with the library and I'm hoping someone can tell me what I'm missing.

Answer

After looking into this a bit I've been able to reproduce the oddities in question. It appears that using the multiply() or the divide() methods when passing a Unit into a QuantityFactory has strange effects. In example:

Quantity firstQuant = quantFactory.create(10.0,Units.METRE)
Quantity secondQuant = quantFactory.create(20.0,Units.METRE.divide(10.0))
System.out.println(secondQuant.add(firstQuant))

outputs the following: 20.5 dm. Even when using MetricPrefix, which seems to be the default method of setting non base SI units, it seems to generate extremely inaccurate Units. Using the following:

Quantity secondQuant = quantFactory.create(20.0,MetricPrefix.KILO(Units.METRE))

outputs 10020.0 km which is nowhere near accurate. However, the following:

Quantity firstQuant = quantFactory.create(10.0,Units.METRE)
Quantity secondQuant = quantFactory.create(20.0,Units.METRE)
System.out.println(secondQuant.divide(10.0).add(firstQuant))

outputs 12.0 m, which is obviously the correct answer.

In honesty the best solution is to simply not use those operations in the creation of the Quantity and to convert to other units of measurement using the built in getConverter() of MetricPrefix enums.

The better way to create Quantities is to use Quantities.getQuantities()