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 版本中修复。
我正在使用 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 版本中修复。