diff --git a/src/main/java/tech/units/indriya/function/DefaultNumberSystem.java b/src/main/java/tech/units/indriya/function/DefaultNumberSystem.java index af9b2cd1..c670043a 100644 --- a/src/main/java/tech/units/indriya/function/DefaultNumberSystem.java +++ b/src/main/java/tech/units/indriya/function/DefaultNumberSystem.java @@ -247,10 +247,10 @@ public Number reciprocal(Number number) { return ((RationalNumber) number).reciprocal(); } if(number instanceof Double) { - return RationalNumber.of((double)number).reciprocal(); + return RationalNumber.of(number.doubleValue()).reciprocal(); } if(number instanceof Float) { - return RationalNumber.of(number.doubleValue()).reciprocal(); + return RationalNumber.of(number.floatValue()).reciprocal(); } throw unsupportedNumberType(number); } @@ -615,7 +615,7 @@ private BigDecimal toBigDecimal(Number number) { return BigDecimal.valueOf(number.longValue()); } if(number instanceof Double || number instanceof Float) { - return BigDecimal.valueOf(number.doubleValue()); + return new BigDecimal(number.toString()); } if(number instanceof RationalNumber) { throw unexpectedCodeReach(); @@ -668,7 +668,7 @@ private Number addWideAndNarrow( } if(narrow instanceof Double || narrow instanceof Float) { - return ((BigDecimal) wide).add(BigDecimal.valueOf(narrow.doubleValue()), Calculus.MATH_CONTEXT); + return ((BigDecimal) wide).add(new BigDecimal(narrow.toString()), Calculus.MATH_CONTEXT); } if(narrow instanceof RationalNumber) { @@ -685,23 +685,23 @@ private Number addWideAndNarrow( if(narrow instanceof Double || narrow instanceof Float) { //converting to BigDecimal, because especially fractional addition is sensitive to precision loss - return BigDecimal.valueOf(wide.doubleValue()) - .add(BigDecimal.valueOf(narrow.doubleValue())); + return new BigDecimal(wide.toString()) + .add(new BigDecimal(narrow.toString())); } if(narrow instanceof RationalNumber) { //TODO[220] can we do better than that, eg. by converting BigDecimal to RationalNumber - return BigDecimal.valueOf(wide.doubleValue()) + return new BigDecimal(wide.toString()) .add(((RationalNumber) narrow).bigDecimalValue()); } if(narrow instanceof BigInteger) { - return BigDecimal.valueOf(wide.doubleValue()) + return new BigDecimal(wide.toString()) .add(new BigDecimal((BigInteger) narrow)); } // at this point we know, that 'narrow' is one of {(Atomic)Long, (Atomic)Integer, Short, Byte} - return BigDecimal.valueOf(wide.doubleValue()) + return new BigDecimal(wide.toString()) .add(BigDecimal.valueOf(narrow.longValue())); } @@ -748,7 +748,7 @@ private Number multiplyWideAndNarrow( } if(narrow instanceof Double || narrow instanceof Float) { - return ((BigDecimal) wide).multiply(BigDecimal.valueOf(narrow.doubleValue()), Calculus.MATH_CONTEXT); + return ((BigDecimal) wide).multiply(new BigDecimal(narrow.toString()), Calculus.MATH_CONTEXT); } if(narrow instanceof RationalNumber) { @@ -765,23 +765,28 @@ private Number multiplyWideAndNarrow( if(narrow instanceof Double || narrow instanceof Float) { // not converting to BigDecimal, because fractional multiplication is not sensitive to precision loss - return wide.doubleValue() * narrow.doubleValue(); + if (wide instanceof Float && narrow instanceof Float) { + // return float if both are floats + return wide.floatValue() * narrow.floatValue(); + } else { + return wide.doubleValue() * narrow.doubleValue(); + } } if(narrow instanceof RationalNumber) { //TODO[220] can we do better than that, eg. by converting BigDecimal to RationalNumber - return BigDecimal.valueOf(wide.doubleValue()) + return new BigDecimal(wide.toString()) .multiply(((RationalNumber) narrow).bigDecimalValue()); } if(narrow instanceof BigInteger) { - return BigDecimal.valueOf(wide.doubleValue()) + return new BigDecimal(wide.toString()) .multiply(new BigDecimal((BigInteger) narrow)); } // at this point we know, that 'narrow' is one of {(Atomic)Long, (Atomic)Integer, Short, Byte} - return BigDecimal.valueOf(wide.doubleValue()) - .multiply(BigDecimal.valueOf(narrow.longValue())); + return new BigDecimal(wide.toString()) + .multiply(BigDecimal.valueOf(narrow.longValue())); } @@ -821,7 +826,7 @@ private int compareWideVsNarrow( } if(narrow instanceof Double || narrow instanceof Float) { - return ((BigDecimal) wide).compareTo(BigDecimal.valueOf(narrow.doubleValue())); + return ((BigDecimal) wide).compareTo(new BigDecimal(narrow.toString())); } if(narrow instanceof RationalNumber) { @@ -837,22 +842,23 @@ private int compareWideVsNarrow( // at this point we know, that wide is one of {Double, Float} if(narrow instanceof Double || narrow instanceof Float) { - return Double.compare(wide.doubleValue(), narrow.doubleValue()); + return new BigDecimal(wide.toString()) + .compareTo(new BigDecimal(narrow.toString())); } if(narrow instanceof RationalNumber) { //TODO[220] can we do better than that, eg. by converting BigDecimal to RationalNumber - return BigDecimal.valueOf(wide.doubleValue()) + return new BigDecimal(wide.toString()) .compareTo(((RationalNumber) narrow).bigDecimalValue()); } if(narrow instanceof BigInteger) { - return BigDecimal.valueOf(wide.doubleValue()) + return new BigDecimal(wide.toString()) .compareTo(new BigDecimal((BigInteger) narrow)); } // at this point we know, that 'narrow' is one of {(Atomic)Long, (Atomic)Integer, Short, Byte} - return BigDecimal.valueOf(wide.doubleValue()) + return new BigDecimal(wide.toString()) .compareTo(BigDecimal.valueOf(narrow.longValue())); } diff --git a/src/main/java/tech/units/indriya/function/RationalNumber.java b/src/main/java/tech/units/indriya/function/RationalNumber.java index d39092ca..5e313e72 100644 --- a/src/main/java/tech/units/indriya/function/RationalNumber.java +++ b/src/main/java/tech/units/indriya/function/RationalNumber.java @@ -123,6 +123,18 @@ public static RationalNumber of(double number) { return of(decimalValue); } + /** + * Returns a {@code RationalNumber} that represents the given float + * {@code number}, with an accuracy equivalent to {@code new BigDecimal(Float.toString(number))}. + * + * @param number + */ + public static RationalNumber of(float number) { + // smh why does Java not have BigDecimal.valueOf(float) ?! + final BigDecimal decimalValue = new BigDecimal(Float.toString(number)); + return of(decimalValue); + } + /** * Returns a {@code RationalNumber} that represents the given BigDecimal decimalValue. * diff --git a/src/test/java/tech/units/indriya/function/DoubleMultiplyConverterTest.java b/src/test/java/tech/units/indriya/function/DoubleMultiplyConverterTest.java index 0600a407..7377504c 100644 --- a/src/test/java/tech/units/indriya/function/DoubleMultiplyConverterTest.java +++ b/src/test/java/tech/units/indriya/function/DoubleMultiplyConverterTest.java @@ -52,6 +52,13 @@ public void testConvertMethod() { assertEquals(-200, converter.convert(-100), 0.1); } + @Test + public void testConvertMethodFloat() { + assertEquals(200, converter.convert(100f), 0.1); + assertEquals(0, converter.convert(0f)); + assertEquals(-200, converter.convert(-100f), 0.1); + } + @Test public void testEqualityOfTwoLogConverter() { assertNotNull(converter); diff --git a/src/test/java/tech/units/indriya/function/UnitConverterTest.java b/src/test/java/tech/units/indriya/function/UnitConverterTest.java index 9032e6f8..17ef919f 100644 --- a/src/test/java/tech/units/indriya/function/UnitConverterTest.java +++ b/src/test/java/tech/units/indriya/function/UnitConverterTest.java @@ -78,6 +78,24 @@ public void testQuantity() { assertEquals(targetUnit, quantResult1.getUnit()); } + @Test + public void testQuantityDouble() { + Quantity quantLength1 = Quantities.getQuantity(1.56, sourceUnit); + Quantity quantResult1 = quantLength1.to(targetUnit); + assertNotNull(quantResult1); + assertNumberEquals(156, quantResult1.getValue(), 1E-12); + assertEquals(targetUnit, quantResult1.getUnit()); + } + + @Test + public void testQuantityFloat() { + Quantity quantLength1 = Quantities.getQuantity(1.56f, sourceUnit); + Quantity quantResult1 = quantLength1.to(targetUnit); + assertNotNull(quantResult1); + assertNumberEquals(156, quantResult1.getValue(), 1E-12); + assertEquals(targetUnit, quantResult1.getUnit()); + } + @Test public void testKelvinToCelsius() { Quantity sut = Quantities.getQuantity(273.15d, KELVIN).to(CELSIUS); @@ -86,6 +104,14 @@ public void testKelvinToCelsius() { assertNumberEquals(0, sut.getValue(), 1E-12); } + @Test + public void testKelvinToCelsiusFloat() { + Quantity sut = Quantities.getQuantity(273.15f, KELVIN).to(CELSIUS); + assertNotNull(sut); + assertEquals(CELSIUS, sut.getUnit()); + assertNumberEquals(0, sut.getValue(), 1E-12); + } + @Test public void testConverterTo() { assertEquals(KILOGRAM.getConverterTo(KILO(GRAM)), KILO(GRAM).getConverterTo(KILOGRAM));