Добавление и вычитание библиотеки единиц измерения 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

где вторая строка показывает правильный результат преобразования.

Исправлено с выпуском 1.0.1 JSR 363 RI.

Спасибо за подробное описание того, как воспроизвести проблему.

Сообщалось, что класс NumberQuantity вызвал похожую проблему у другого разработчика (который объяснил свою проблему по электронной почте). Поэтому мы знаем, что нужно улучшить, и когда исправление будет завершено, мы выпустим сервисный выпуск для RI.

С уважением, Вернер

Другие вопросы по тегам