Добавление и вычитание библиотеки единиц измерения Java, возвращающие неверные значения
Я использую эталонную реализацию 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 м. Мне очень трудно поверить, что это на самом деле ошибка в библиотеке, и я надеюсь, что кто-то может сказать мне, что мне не хватает.
4 ответа
Посмотрев немного, я смог воспроизвести эти странности. Похоже, что с помощью multiply()
или divide()
методы при прохождении Unit
в NumberFactory имеет странные эффекты. В примере:
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
, который, по-видимому, является методом по умолчанию для установки не базовых единиц СИ, кажется, генерирует крайне неточные 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
и преобразовать в другие единицы измерения с помощью встроенного getConverter()
из MetricPrefix
перечисления.
Лучший способ создать Quantities
это использовать Quantities.getQuantities()
В дополнение к пониманию, предоставленному Beryllium, я могу подтвердить сообщаемое поведение и отследить проблему до ошибки в эталонной реализации. Я взял на себя смелость сообщить о проблеме и своих выводах вместе с предлагаемым решением.
Действительно, метод doubleValue(Unit<Q>)
из NumberQuantity
, который используется под капотом на этапах преобразования, ошибочно вычисляет обратное преобразование между единицами. Это объясняет наблюдение OP, что умножение и деление на постоянные коэффициенты, по-видимому, обращаются вспять при применении в качестве преобразования единиц.
Поскольку фабрика количества по умолчанию возвращает исключительно объекты типа 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 вызвал похожую проблему у другого разработчика (который объяснил свою проблему по электронной почте). Поэтому мы знаем, что нужно улучшить, и когда исправление будет завершено, мы выпустим сервисный выпуск для RI.
С уважением, Вернер