From 0c0f87da838e3406ac88394c45ced037c0180f87 Mon Sep 17 00:00:00 2001 From: iTitus Date: Tue, 10 Nov 2020 22:16:56 +0100 Subject: [PATCH 1/3] fully switch to BigRational --- .../math/function/PowerSeriesCalculator.java | 2 +- .../math/number/BigDecimalConstants.java | 12 ++ .../ititus/math/number/BigRational.java | 162 ++++++++++++++++-- .../ititus/math/number/BigRationalMath.java | 19 ++ .../ititus/si/quantity/AbstractQuantity.java | 14 -- .../github/ititus/si/quantity/Constants.java | 21 +-- .../github/ititus/si/quantity/Quantity.java | 90 ++++++++-- .../ititus/si/quantity/QuantityImpl.java | 39 ++--- .../quantity/type/ElectricPermittivity.java | 3 +- .../ititus/si/quantity/type/Frequency.java | 8 +- .../github/ititus/si/quantity/type/Pace.java | 8 +- .../github/ititus/si/quantity/type/Speed.java | 8 +- .../github/ititus/si/quantity/type/Time.java | 8 +- .../si/quantity/value/BigRationalValue.java | 127 ++++++++++++++ .../si/quantity/value/QuantityValue.java | 70 ++++++++ .../github/ititus/si/unit/AlternateUnit.java | 5 +- .../io/github/ititus/si/unit/BaseUnit.java | 5 +- .../github/ititus/si/unit/CompoundUnit.java | 5 +- .../github/ititus/si/unit/ConvertedUnit.java | 5 +- .../io/github/ititus/si/unit/PrefixUnit.java | 10 +- .../java/io/github/ititus/si/unit/Unit.java | 93 +++++++++- .../java/io/github/ititus/si/unit/Units.java | 10 +- .../si/unit/converter/CompoundConverter.java | 4 +- .../si/unit/converter/IdentityConverter.java | 4 +- .../converter/MultiplicationConverter.java | 22 +-- .../si/unit/converter/UnitConverter.java | 6 +- .../github/ititus/assertions/Assertions.java | 10 -- .../ititus/assertions/CustomAssertions.java | 15 ++ .../assertions/QuantityValueAssert.java | 94 ++++++++++ .../ititus/assertions/QuantityValues.java | 36 ++++ .../math/number/BigRationalExpTests.java | 2 +- .../math/number/BigRationalLnTests.java | 2 +- .../math/number/BigRationalSinTests.java | 2 +- .../ititus/si/quantity/type/ForceTest.java | 7 +- .../ititus/si/quantity/type/LengthTest.java | 10 +- .../ititus/si/quantity/type/MassTest.java | 8 +- 36 files changed, 799 insertions(+), 147 deletions(-) create mode 100644 src/main/java/io/github/ititus/math/number/BigDecimalConstants.java delete mode 100644 src/main/java/io/github/ititus/si/quantity/AbstractQuantity.java create mode 100644 src/main/java/io/github/ititus/si/quantity/value/BigRationalValue.java create mode 100644 src/main/java/io/github/ititus/si/quantity/value/QuantityValue.java delete mode 100644 src/test/java/io/github/ititus/assertions/Assertions.java create mode 100644 src/test/java/io/github/ititus/assertions/CustomAssertions.java create mode 100644 src/test/java/io/github/ititus/assertions/QuantityValueAssert.java create mode 100644 src/test/java/io/github/ititus/assertions/QuantityValues.java diff --git a/src/main/java/io/github/ititus/math/function/PowerSeriesCalculator.java b/src/main/java/io/github/ititus/math/function/PowerSeriesCalculator.java index 7c16c4c..1cfb5b6 100644 --- a/src/main/java/io/github/ititus/math/function/PowerSeriesCalculator.java +++ b/src/main/java/io/github/ititus/math/function/PowerSeriesCalculator.java @@ -135,7 +135,7 @@ protected BigRational getCoefficient(BigInteger n) { return BigRationalConstants.ZERO; } - return BigRational.of(BigInteger.ONE, n); + return BigRational.ofInv(n); } } diff --git a/src/main/java/io/github/ititus/math/number/BigDecimalConstants.java b/src/main/java/io/github/ititus/math/number/BigDecimalConstants.java new file mode 100644 index 0000000..4641504 --- /dev/null +++ b/src/main/java/io/github/ititus/math/number/BigDecimalConstants.java @@ -0,0 +1,12 @@ +package io.github.ititus.math.number; + +import java.math.BigDecimal; + +public final class BigDecimalConstants { + + public static final BigDecimal TWO = new BigDecimal(2); + public static final BigDecimal ONE_OVER_TWO = new BigDecimal("0.5"); + + private BigDecimalConstants() { + } +} diff --git a/src/main/java/io/github/ititus/math/number/BigRational.java b/src/main/java/io/github/ititus/math/number/BigRational.java index 5476f2a..e0fd8d7 100644 --- a/src/main/java/io/github/ititus/math/number/BigRational.java +++ b/src/main/java/io/github/ititus/math/number/BigRational.java @@ -86,12 +86,140 @@ public static BigRational of(BigDecimal d) { int scale = d.scale(); BigInteger scalar = BigInteger.TEN.pow(Math.abs(scale)); - if (scale <= 0) { - of(unscaled.multiply(scalar)); + if (scale < 0) { + return of(unscaled.multiply(scalar)); } return of(unscaled, scalar); } + public static BigRational ofInv(int n) { + return of(n).inverse(); + } + + public static BigRational ofInv(long n) { + return of(n).inverse(); + } + + public static BigRational ofInv(BigInteger n) { + return of(n).inverse(); + } + + public static BigRational ofInv(float f) { + return of(f).inverse(); + } + + public static BigRational ofInv(double d) { + return of(d).inverse(); + } + + public static BigRational ofInv(BigDecimal d) { + return of(d).inverse(); + } + + public static BigRational ofExp(int scale, int exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(int scale, long exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(int scale, BigInteger exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(long scale, int exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(long scale, long exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(long scale, BigInteger exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(BigInteger scale, int exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(BigInteger scale, long exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(BigInteger scale, BigInteger exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(float scale, int exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(float scale, long exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(float scale, BigInteger exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(double scale, int exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(double scale, long exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(double scale, BigInteger exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(BigDecimal scale, int exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(BigDecimal scale, long exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational ofExp(BigDecimal scale, BigInteger exponent) { + return of(scale).multiply(BigRationalConstants.TEN.pow(exponent)); + } + + public static BigRational of(int numerator, int denominator) { + return of(BigIntegerMath.of(numerator), BigIntegerMath.of(denominator)); + } + + public static BigRational of(int numerator, long denominator) { + return of(BigIntegerMath.of(numerator), BigIntegerMath.of(denominator)); + } + + public static BigRational of(int numerator, BigInteger denominator) { + return of(BigIntegerMath.of(numerator), denominator); + } + + public static BigRational of(long numerator, int denominator) { + return of(BigIntegerMath.of(numerator), BigIntegerMath.of(denominator)); + } + + public static BigRational of(long numerator, long denominator) { + return of(BigIntegerMath.of(numerator), BigIntegerMath.of(denominator)); + } + + public static BigRational of(long numerator, BigInteger denominator) { + return of(BigIntegerMath.of(numerator), denominator); + } + + public static BigRational of(BigInteger numerator, int denominator) { + return of(numerator, BigIntegerMath.of(denominator)); + } + + public static BigRational of(BigInteger numerator, long denominator) { + return of(numerator, BigIntegerMath.of(denominator)); + } + @SuppressWarnings("Duplicates") public static BigRational of(BigInteger numerator, BigInteger denominator) { if (denominator.equals(BigInteger.ZERO)) { @@ -117,22 +245,6 @@ public static BigRational of(BigInteger numerator, BigInteger denominator) { if (r.equals(MINUS_ONE)) { return MINUS_ONE; - } else if (r.equals(TWO)) { - return TWO; - } else if (r.equals(THREE)) { - return THREE; - } else if (r.equals(FOUR)) { - return FOUR; - } else if (r.equals(TEN)) { - return TEN; - } else if (r.equals(ONE_OVER_TWO)) { - return ONE_OVER_TWO; - } else if (r.equals(ONE_OVER_THREE)) { - return ONE_OVER_THREE; - } else if (r.equals(THREE_OVER_FOUR)) { - return THREE_OVER_FOUR; - } else if (r.equals(FIVE_OVER_FOUR)) { - return FIVE_OVER_FOUR; } return r; @@ -295,6 +407,20 @@ public BigRational pow(BigInteger exponent) { return BigRationalMath.pow(this, exponent); } + public BigRational pow(BigDecimal exponent) { + if (exponent.signum() == 0) { + return ONE; + } else if (isZero()) { + return ZERO; + } else if (exponent.equals(BigDecimal.ONE)) { + return this; + } else if (exponent.equals(BigDecimalConstants.TWO)) { + return squared(); + } + + return BigRationalMath.pow(this, exponent); + } + public BigRational pow(BigRational exponent) { if (exponent.isZero()) { return ONE; diff --git a/src/main/java/io/github/ititus/math/number/BigRationalMath.java b/src/main/java/io/github/ititus/math/number/BigRationalMath.java index 448c954..31f9d6f 100644 --- a/src/main/java/io/github/ititus/math/number/BigRationalMath.java +++ b/src/main/java/io/github/ititus/math/number/BigRationalMath.java @@ -4,6 +4,7 @@ import io.github.ititus.math.time.DurationFormatter; import io.github.ititus.math.time.StopWatch; +import java.math.BigDecimal; import java.math.BigInteger; import java.time.Duration; @@ -40,6 +41,24 @@ public static BigRational pow(BigRational base, BigInteger exponent) { return r; } + public static BigRational pow(BigRational base, BigDecimal exponent) { + if (base.isOne() || exponent.signum() == 0) { + return ONE; + } else if (base.isZero()) { + return ZERO; + } else if (exponent.equals(BigDecimal.ONE)) { + return base; + } else if (exponent.signum() < 0) { + return pow(base, exponent.negate()).inverse(); + } + + if (exponent.equals(BigDecimalConstants.ONE_OVER_TWO)) { + return base.sqrt(); + } + + return exp(BigRational.of(exponent).multiply(ln(base))); + } + public static BigRational pow(BigRational base, BigRational exponent) { if (base.isOne() || exponent.isZero()) { return ONE; diff --git a/src/main/java/io/github/ititus/si/quantity/AbstractQuantity.java b/src/main/java/io/github/ititus/si/quantity/AbstractQuantity.java deleted file mode 100644 index 4a54213..0000000 --- a/src/main/java/io/github/ititus/si/quantity/AbstractQuantity.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.github.ititus.si.quantity; - -import io.github.ititus.si.quantity.type.QuantityType; - -public abstract class AbstractQuantity> implements Quantity { - - @Override - public String toString() { - return "Quantity{" + - "value=" + getValue() + - ", unit=" + getUnit() + - '}'; - } -} diff --git a/src/main/java/io/github/ititus/si/quantity/Constants.java b/src/main/java/io/github/ititus/si/quantity/Constants.java index ae06de9..c137251 100644 --- a/src/main/java/io/github/ititus/si/quantity/Constants.java +++ b/src/main/java/io/github/ititus/si/quantity/Constants.java @@ -2,6 +2,7 @@ import io.github.ititus.si.quantity.type.*; +import static io.github.ititus.math.number.BigRational.ofExp; import static io.github.ititus.si.unit.Units.*; public final class Constants { @@ -9,22 +10,22 @@ public final class Constants { /* Defined (exact) constants */ // Length - public static final Quantity SPEED_OF_LIGHT = METRES_PER_SECOND.get(299_792_458.0); + public static final Quantity SPEED_OF_LIGHT = METRES_PER_SECOND.get(299_792_458); // Mass - public static final Quantity PLANCK_CONSTANT = JOULE.multiply(SECOND).get(6.626_070_15e-34); + public static final Quantity PLANCK_CONSTANT = JOULE.multiply(SECOND).get(ofExp(662_607_015, -42)); // Time - public static final Quantity HYPERFINE_TRANSITION_FREQUENCY_OF_CAESIUM = HERTZ.get(9_192_631_770.0); + public static final Quantity HYPERFINE_TRANSITION_FREQUENCY_OF_CAESIUM = HERTZ.get(9_192_631_770L); // Electric Current - public static final Quantity ELEMENTARY_CHARGE = COULOMB.get(1.602_176_634e-19); + public static final Quantity ELEMENTARY_CHARGE = COULOMB.get(ofExp(1_602_176_634, -28)); // Thermodynamic Temperature - public static final Quantity BOLTZMANN_CONSTANT = JOULE.divide(KELVIN).get(1.380_649_76e-23); + public static final Quantity BOLTZMANN_CONSTANT = JOULE.divide(KELVIN).get(ofExp(1_380_649_76, -31)); // Amount of Substance - public static final Quantity AVOGADRO_CONSTANT = MOLE.inverse().get(6.022_140_76e23); + public static final Quantity AVOGADRO_CONSTANT = MOLE.inverse().get(ofExp(6_022_140_76, 15)); // Luminous Intensity public static final Quantity LUMINOUS_EFFICACY_OF_540_THZ_RADIATION = LUMEN_PER_WATT.get(683); @@ -33,15 +34,15 @@ public final class Constants { /* Measured constants */ public static final Quantity GRAVITATIONAL_CONSTANT = - METRE.pow(3).divide(KILOGRAM.multiply(SECOND.pow(2))).get(6.674_30e-11); + METRE.pow(3).divide(KILOGRAM.multiply(SECOND.pow(2))).get(ofExp(667_430, -16)); public static final Quantity VACUUM_ELECTRIC_PERMITTIVITY = - FARAD_PER_METRE.get(8.854_187_812_8e-12); + FARAD_PER_METRE.get(ofExp(88_541_878_128L, -22)); public static final Quantity VACUUM_MAGNETIC_PERMEABILITY = - HENRY_PER_METRE.get(1.256_637_062_12e-6); + HENRY_PER_METRE.get(ofExp(125_663_706_212L, -17)); - public static final Quantity ELECTRON_MASS = KILOGRAM.get(9.109_383_701_5e-31); + public static final Quantity ELECTRON_MASS = KILOGRAM.get(ofExp(91_093_837_015L, -41)); private Constants() { } diff --git a/src/main/java/io/github/ititus/si/quantity/Quantity.java b/src/main/java/io/github/ititus/si/quantity/Quantity.java index 34fc951..6f5afd4 100644 --- a/src/main/java/io/github/ititus/si/quantity/Quantity.java +++ b/src/main/java/io/github/ititus/si/quantity/Quantity.java @@ -1,15 +1,20 @@ package io.github.ititus.si.quantity; +import io.github.ititus.math.number.BigRational; import io.github.ititus.si.quantity.type.QuantityType; +import io.github.ititus.si.quantity.value.QuantityValue; import io.github.ititus.si.unit.Unit; +import java.math.BigDecimal; +import java.math.BigInteger; + public interface Quantity> { - static > Quantity of(double value, Unit unit) { + static > Quantity of(QuantityValue value, Unit unit) { return new QuantityImpl<>(value, unit); } - double getValue(); + QuantityValue getValue(); Unit getUnit(); @@ -30,35 +35,98 @@ default > Quantity as(Unit unit) { } default Quantity add(Quantity qty) { - return getUnit().get(getValue() + qty.convertTo(getUnit()).getValue()); + return getUnit().get(getValue().add(qty.convertTo(getUnit()).getValue())); } default Quantity negate() { - return getUnit().get(-getValue()); + return getUnit().get(getValue().negate()); } default Quantity subtract(Quantity qty) { return add(qty.negate()); } + default Quantity multiply(int n) { + return multiply(QuantityValue.of(n)); + } + + default Quantity multiply(long n) { + return multiply(QuantityValue.of(n)); + } + + default Quantity multiply(BigInteger n) { + return multiply(QuantityValue.of(n)); + } + + default Quantity multiply(float f) { + return multiply(QuantityValue.of(f)); + } + default Quantity multiply(double d) { - return getUnit().get(getValue() * d); + return multiply(QuantityValue.of(d)); + } + + default Quantity multiply(BigDecimal d) { + return multiply(QuantityValue.of(d)); + } + + default Quantity multiply(BigRational r) { + return multiply(QuantityValue.of(r)); + } + + default Quantity multiply(QuantityValue value) { + return getUnit().get(getValue().multiply(value)); + } + + default Quantity multiply(Quantity qty) { + return getUnit().multiply(qty.getUnit()).get(getValue().multiply(qty.getValue())); } - Quantity multiply(Quantity qty); + default Quantity inverse() { + return getUnit().inverse().get(getValue().inverse()); + } - Quantity inverse(); + default Quantity divide(int n) { + return divide(BigRational.of(n)); + } + + default Quantity divide(long n) { + return divide(BigRational.of(n)); + } + + default Quantity divide(BigInteger n) { + return divide(QuantityValue.of(n)); + } + + default Quantity divide(float f) { + return divide(QuantityValue.of(f)); + } default Quantity divide(double d) { - return getUnit().get(getValue() / d); + return divide(QuantityValue.of(d)); + } + + default Quantity divide(BigDecimal d) { + return divide(QuantityValue.of(d)); + } + + default Quantity divide(BigRational r) { + return divide(QuantityValue.of(r)); + } + + default Quantity divide(QuantityValue value) { + return getUnit().get(getValue().divide(value)); } default Quantity divide(Quantity qty) { return multiply(qty.inverse()); } - Quantity pow(int n); - - Quantity root(int n); + default Quantity pow(int n) { + return getUnit().pow(n).get(getValue().pow(n)); + } + default Quantity root(int n) { + return getUnit().root(n).get(getValue().root(n)); + } } diff --git a/src/main/java/io/github/ititus/si/quantity/QuantityImpl.java b/src/main/java/io/github/ititus/si/quantity/QuantityImpl.java index 5dfc32b..ab85122 100644 --- a/src/main/java/io/github/ititus/si/quantity/QuantityImpl.java +++ b/src/main/java/io/github/ititus/si/quantity/QuantityImpl.java @@ -1,22 +1,23 @@ package io.github.ititus.si.quantity; import io.github.ititus.si.quantity.type.QuantityType; +import io.github.ititus.si.quantity.value.QuantityValue; import io.github.ititus.si.unit.Unit; import java.util.Objects; -final class QuantityImpl> extends AbstractQuantity { +final class QuantityImpl> implements Quantity { - private final double value; + private final QuantityValue value; private final Unit unit; - QuantityImpl(double value, Unit unit) { + QuantityImpl(QuantityValue value, Unit unit) { this.value = value; this.unit = unit; } @Override - public double getValue() { + public QuantityValue getValue() { return value; } @@ -39,26 +40,6 @@ public > Quantity as(T type) { return new QuantityImpl<>(value, unit.as(type)); } - @Override - public Quantity multiply(Quantity qty) { - return new QuantityImpl<>(value * qty.getValue(), unit.multiply(qty.getUnit())); - } - - @Override - public Quantity inverse() { - return new QuantityImpl<>(1 / value, unit.inverse()); - } - - @Override - public Quantity pow(int n) { - return new QuantityImpl<>(Math.pow(value, n), unit.pow(n)); - } - - @Override - public Quantity root(int n) { - return new QuantityImpl<>(Math.pow(value, 1.0 / n), unit.root(n)); - } - @Override public boolean equals(Object o) { if (this == o) { @@ -68,11 +49,19 @@ public boolean equals(Object o) { return false; } QuantityImpl quantity = (QuantityImpl) o; - return Double.compare(quantity.value, value) == 0 && unit.equals(quantity.unit); + return value.equals(quantity.value) && unit.equals(quantity.unit); } @Override public int hashCode() { return Objects.hash(value, unit); } + + @Override + public String toString() { + return "Quantity{" + + "value=" + value + + ", unit=" + unit + + '}'; + } } diff --git a/src/main/java/io/github/ititus/si/quantity/type/ElectricPermittivity.java b/src/main/java/io/github/ititus/si/quantity/type/ElectricPermittivity.java index 1ebf490..6771fa0 100644 --- a/src/main/java/io/github/ititus/si/quantity/type/ElectricPermittivity.java +++ b/src/main/java/io/github/ititus/si/quantity/type/ElectricPermittivity.java @@ -8,6 +8,7 @@ public final class ElectricPermittivity extends AbstractQuantityType FARAD_PER_METRE); + super(TIME.pow(4).multiply(ELECTRIC_CURRENT.pow(2)).divide(LENGTH.pow(3).multiply(MASS)), + () -> FARAD_PER_METRE); } } diff --git a/src/main/java/io/github/ititus/si/quantity/type/Frequency.java b/src/main/java/io/github/ititus/si/quantity/type/Frequency.java index 0dce0d4..7c7cfe0 100644 --- a/src/main/java/io/github/ititus/si/quantity/type/Frequency.java +++ b/src/main/java/io/github/ititus/si/quantity/type/Frequency.java @@ -9,11 +9,11 @@ public final class Frequency extends AbstractQuantityType { public static final Frequency FREQUENCY = new Frequency(); - public static Quantity asFrequency(Quantity