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

Java units of measurement library addition and subtraction returning incorrect values

我正在使用 JSR363 的参考实现。我已经尝试了很多变体,但我将以这段代码为例。

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));

这会打印出 503.0 米。显然有些地方出了问题,这应该是 3.05 m。我发现很难相信这实际上是图书馆的一个错误,我希望有人能告诉我我错过了什么。

在仔细研究之后,我已经能够重现所讨论的奇怪之处。似乎在将 Unit 传递到 QuantityFactory 时使用 multiply()divide() 方法会产生奇怪的效果。例如:

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))

输出以下内容:20.5 dm。即使使用 MetricPrefix,这似乎是设置非基本 SI 单位的默认方法,它似乎也会生成极其不准确的 Units。使用以下内容:

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

输出 10020.0 km 远不准确。但是,以下内容:

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))

输出12.0 m,显然是正确答案。

老实说,最好的解决方案是在创建 Quantity 时简单地不使用这些操作,并使用 MetricPrefix 的内置 getConverter() 转换为其他测量单位枚举。

创建 Quantities 的更好方法是使用 Quantities.getQuantities()

加上 Beryllium 提供的洞察力,我可以确认所报告的行为并将问题追踪到参考实现中的错误。我冒用了 reporting the issue 和我的发现以及建议的修复。

确实,NumberQuantity 的方法 doubleValue(Unit<Q>) 在转换步骤中使用,错误地计算了单位之间的逆变换。这解释了 OP 的观察结果,即当应用于单位转换时,常数因子的乘法和除法似乎是相反的。

由于默认数量工厂仅 returns 类型 NumberQuantity 对象,因此以这种方式创建的所有数量都会受到影响。但是,DoubleQuantity 等其他类型似乎可以正常工作。正如 Beryllium 在回答中所建议的那样,可以通过 Quantities.getQuantities(<value>, <unit>) 创建它们。以下代码片段演示了从默认工厂获得的 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)));
    }
}

这会产生

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

其中第二行显示正确的转换结果。

感谢您提供有关如何重现问题的详细说明。

NumberQuantity class 被另一位开发人员报告(他通过电子邮件解释了他的问题)导致了类似的问题所以我们知道需要改进的地方和修复完成后,我们将为 RI 发布服务版本。

此致, 维尔纳

已在 JSR 363 RI 的 1.0.1 版本中修复。