2016-09-27 14 views
4

Я использую эталонную реализацию JSR363. Я пробовал много вариантов этого, но я приведу этот код в качестве примера.Java-единицы сложения и вычитания библиотек измерений, возвращающие неверные значения

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 м. Мне очень сложно поверить, что на самом деле это ошибка в библиотеке, и я надеюсь, что кто-то скажет мне, что мне не хватает.

+0

'CENTI (SI.METRE)' будет альтернативой. Разве нет форума JScience? –

+0

@JoopEggen То же самое происходит при использовании CENTI, я постараюсь искать форумы, но технически это не JScience. – zjuhasz

+0

Ищите новую версию библиотеки. Это, должно быть, не модульная версия, где кто-то серьезно ошибался. –

ответ

3

Изучив это немного, я смог воспроизвести эти странности. Похоже, что использование методов multiply() или divide() при передаче Unit в QuantityFactory имеет странные эффекты. В примере:

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

+0

Правильно, Quantities.getQuantity() не разделяет некоторые проблемы, обнаруженные в NumberQuantity на момент. Версия RI для DefaultFullFactory возвращает новый NumberQuantity. В то время как версия Java SE 8 uom-se нет. Он рассматривался там, но не сливался обратно в РИ. Приносим извинения за неудобства. Таким образом, если вы можете выбрать и запустить Java SE 8 или 9, попробуйте uom-se, он должен там работать ;-) –

2

Добавления к проницательности, предоставленной бериллий, я могу подтвердить заявленное поведение и выследил проблему с ошибкой в ​​эталонной реализации. Я взял на себя смелость reporting the issue и мои выводы вместе с предлагаемым исправлением.

Действительно, метод doubleValue(Unit<Q>) из NumberQuantity, который используется под капотом в шагах преобразования, ошибочно вычисляет обратное преобразование между единицами. Это объясняет наблюдение ФП, что умножение и деление на постоянные факторы оказываются обратимыми при применении в качестве единичных преобразований.

Поскольку фабрика по умолчанию только для объектов возвращает объекты типа NumberQuantity, все созданные таким образом количества влияют. Тем не менее, похоже, работают другие типы, такие как DoubleQuantity. Как было предложено в ответе Бериллием, они могут быть созданы с помощью 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

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

Класс QQantant был вызван аналогичной проблемой другим разработчиком (который объяснил свою проблему по электронной почте). Таким образом, мы осознаем, что нужно улучшить, и когда исправление будет завершено, мы выпустим сервис-релиз для RI.

Привет, Вернер

1

Фиксированный с выпуском 1.0.1 из JSR 363 RI.