简体   繁体   English

Java单位的测量库加法和减法返回不正确的值

[英]Java units of measurement library addition and subtraction returning incorrect values

I'm using the reference implementation of JSR363. 我正在使用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 = lengthFactory.create(5, Units.METRE.divide(100.0));
Quantity<Length> second = lengthFactory.create(3, Units.METRE);
System.out.println(second.add(first));

This prints 503.0 m. 这打印503.0米。 Clearly something is very wrong and this should be 3.05 m. 显然有些东西是非常错误的,这应该是3.05米。 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. 我发现很难相信这实际上是图书馆的一个错误,我希望有人可以告诉我我错过了什么。

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. 看起来在将Unit传递给QuantityFactory时使用multiply()divide()方法会产生奇怪的效果。 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 . 输出以下内容: 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 . 即使使用MetricPrefix ,它似乎是设置非基本SI单位的默认方法,它似乎生成非常​​不准确的Units Using the following: 使用以下内容:

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

outputs 10020.0 km which is nowhere near accurate. 输出10020.0 km ,这远不准确。 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. 输出12.0 m ,这显然是正确的答案。

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. 诚实地说,最好的解决方案是在创建Quantity不使用这些操作,并使用MetricPrefix枚举的内置getConverter()转换为其他测量单位。

The better way to create Quantities is to use Quantities.getQuantities() 创建Quantities的更好方法是使用Quantities.getQuantities()

Adding to the insight provided by Beryllium, I can confirm the reported behavior and have tracked down the problem to a bug in the reference implementation. 添加到Beryllium提供的洞察力,我可以确认报告的行为,并已将问题跟踪到参考实现中的错误。 I took the liberty of reporting the issue and my findings along with a proposed fix. 我冒昧地报告了这个问题和我的发现以及一个提议的解决方案。

Indeed, the method doubleValue(Unit<Q>) of NumberQuantity , which is used under the hood in conversion steps, erroneously computes the inverse transformation between units. 实际上, NumberQuantity的方法doubleValue(Unit<Q>)在转换步骤的引擎盖下使用,会错误地计算单位之间的逆变换。 This explains OP's observation that multiplication and division by constant factors appear to be reversed when applied as unit transformations. 这解释了OP的观察结果,当作为单位变换应用时,常数因子的乘法和除法似乎是相反的。

Since the default quantity factory exclusively returns objects of type NumberQuantity , all quantities created this way are affected. 由于默认数量工厂专门返回NumberQuantity类型的对象, NumberQuantity这种方式创建的所有数量都会受到影响。 However, other types like DoubleQuantity seem to work correctly. 但是,像DoubleQuantity这样的其他类型似乎可以正常工作。 As suggested in the answer by Beryllium, they can be created by means of Quantities.getQuantities(<value>, <unit>) . 正如Beryllium在答案中所建议的那样,它们可以通过Quantities.getQuantities(<value>, <unit>) The following code snippet demonstrates that conversion breaks for a NumberQuantity obtained from the default factory, but works correctly for a DoubleQuantity : 以下代码段演示了从默认工厂获取的NumberQuantity转换中断,但对DoubleQuantity正常工作:

package test.jsciunits;

import javax.measure.spi.ServiceProvider;
import javax.measure.Quantity;
import javax.measure.quantity.Length;
import javax.measure.spi.QuantityFactory;
import tec.units.ri.quantity.Quantities;
import static tec.units.ri.unit.Units.*;
import static tec.units.ri.unit.MetricPrefix.*;

public class JScienceUnits {
    public static void main(String[] args) {
        ServiceProvider provider = ServiceProvider.current();
        QuantityFactory<Length> lengthFactory = provider.getQuantityFactory(Length.class);

        Quantity<Length> q = lengthFactory.create(5.0, METRE);
        Quantity<Length> r = Quantities.getQuantity(5.0,  METRE);

        System.out.println("q = " + q + ", q.to(CENTI(METRE)) = " + q.to(CENTI(METRE)));
        System.out.println("r = " + r + ", r.to(CENTI(METRE)) = " + r.to(CENTI(METRE)));
    }
}

This produces 这产生了

q = 5.0 m, q.to(CENTI(METRE)) = 0.05 cm
r = 5.0 m, r.to(CENTI(METRE)) = 500.0 cm

where the second line shows a correct conversion result. 第二行显示正确的转换结果。

Thanks for the detailed description on how to reproduce the issue. 感谢有关如何重现该问题的详细说明。

The NumberQuantity class was reported to cause a similar issue by another developer (who explained his problem by email) So we're aware of things to improve and when the fix is complete, we'll issue a service release for the RI. 据报道, NumberQuantity类引起了另一个开发人员的类似问题(他通过电子邮件解释了他的问题)所以我们知道要改进的事情,当修复完成后,我们将为RI发布服务版本。

Regards, Werner 此致,Werner

修复了JSR 363 RI的1.0.1版。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM