diff --git a/apfloat-calc/src/main/java/org/apfloat/calc/ApfloatCalculatorImpl.java b/apfloat-calc/src/main/java/org/apfloat/calc/ApfloatCalculatorImpl.java index 37c7bc0..b26b6d5 100644 --- a/apfloat-calc/src/main/java/org/apfloat/calc/ApfloatCalculatorImpl.java +++ b/apfloat-calc/src/main/java/org/apfloat/calc/ApfloatCalculatorImpl.java @@ -39,7 +39,7 @@ /** * Arbitrary precision calculator implementation. * - * @version 1.11.0 + * @version 1.13.0 * @author Mikko Tommila */ @@ -1305,7 +1305,7 @@ public void setInputPrecision(Long inputPrecision) private Number fixedOrArbitraryPrecision(java.util.function.Function fixedPrecisionFunction, java.util.function.Function arbitraryPrecisionFunction, Number x) { Apcomplex z = (Apcomplex) x; - return (getInputPrecision() != null && z.real().signum() == 0 && z.imag().signum() == 0 ? fixedPrecisionFunction.apply(z) : arbitraryPrecisionFunction.apply(z)); + return (getInputPrecision() != null && z.isZero() ? fixedPrecisionFunction.apply(z) : arbitraryPrecisionFunction.apply(z)); } private FixedPrecisionApcomplexHelper fixedPrecisionApcomplexHelper = new FixedPrecisionApcomplexHelper(Apfloat.INFINITE); diff --git a/apfloat/src/main/java/org/apfloat/Apcomplex.java b/apfloat/src/main/java/org/apfloat/Apcomplex.java index 9a447a1..fd5f31b 100644 --- a/apfloat/src/main/java/org/apfloat/Apcomplex.java +++ b/apfloat/src/main/java/org/apfloat/Apcomplex.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2002-2023 Mikko Tommila + * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -44,7 +44,7 @@ * @see Apfloat * @see ApcomplexMath * - * @version 1.12.0 + * @version 1.13.0 * @author Mikko Tommila */ @@ -414,6 +414,20 @@ public long size() return Math.max(real().size(), imag().size()); } + /** + * Returns if this number is zero. + * + * @return If this number is zero. + * + * @since 1.13.0 + */ + + public boolean isZero() + throws ApfloatRuntimeException + { + return real().signum() == 0 && imag().signum() == 0; + } + /** * Returns if this number has an integer value. Note that this does not * necessarily mean that this object is an instance of {@link Apint}. @@ -504,9 +518,9 @@ public Apcomplex multiply(Apcomplex z) public Apcomplex divide(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { - throw new ArithmeticException(real().signum() == 0 && imag().signum() == 0 ? "Zero divided by zero" : "Division by zero"); + throw new ArithmeticException(isZero() ? "Zero divided by zero" : "Division by zero"); } Apfloat tmpReal, @@ -773,8 +787,7 @@ public long longValueExact() public long equalDigits(Apcomplex z) throws ApfloatRuntimeException { - if (real().signum() == 0 && imag().signum() == 0 && - z.real().signum() == 0 && z.imag().signum() == 0) + if (isZero() && z.isZero()) { // Both are zero return Apfloat.INFINITE; diff --git a/apfloat/src/main/java/org/apfloat/ApcomplexMath.java b/apfloat/src/main/java/org/apfloat/ApcomplexMath.java index 4511fc4..d441213 100644 --- a/apfloat/src/main/java/org/apfloat/ApcomplexMath.java +++ b/apfloat/src/main/java/org/apfloat/ApcomplexMath.java @@ -150,7 +150,7 @@ public static Apcomplex pow(Apcomplex z, long n) { if (n == 0) { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { throw new ArithmeticException("Zero to power zero"); } @@ -269,7 +269,7 @@ public static Apcomplex root(Apcomplex z, long n, long k) { throw new ArithmeticException("Zeroth root"); } - else if (z.real().signum() == 0 && z.imag().signum() == 0) + else if (z.isZero()) { if (n < 0) { @@ -349,7 +349,7 @@ public static Apcomplex inverseRoot(Apcomplex z, long n) public static Apcomplex inverseRoot(Apcomplex z, long n, long k) throws ArithmeticException, ApfloatRuntimeException { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { throw new ArithmeticException("Inverse root of zero"); } @@ -612,7 +612,7 @@ else if (n == 0x80000000) { throw new ApfloatRuntimeException("Maximum array size exceeded"); } - else if (z.real().signum() == 0 && z.imag().signum() == 0) + else if (z.isZero()) { if (n < 0) { @@ -655,8 +655,7 @@ else if (z.real().signum() == 0 && z.imag().signum() == 0) public static Apcomplex agm(Apcomplex a, Apcomplex b) throws ApfloatRuntimeException { - if (a.real().signum() == 0 && a.imag().signum() == 0 || - b.real().signum() == 0 && b.imag().signum() == 0) // Would not converge quadratically + if (a.isZero() || b.isZero()) // Would not converge quadratically { return Apcomplex.ZEROS[a.radix()]; } @@ -908,7 +907,7 @@ else if (w.real().signum() >= 0 && w.imag().signum() == 0) private static Apcomplex rawLog(Apcomplex z) throws ApfloatRuntimeException { - assert (z.real().signum() != 0 || z.imag().signum() != 0); // Infinity + assert (!z.isZero()); // Infinity Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()); @@ -2427,7 +2426,7 @@ public static Apcomplex pochhammer(Apcomplex z, Apcomplex n) int radix = z.radix(); long precision = Math.min(z.precision(), n.precision()); Apint one = Apint.ONES[radix]; - if (n.real().signum() == 0 && n.imag().signum() == 0) + if (n.isZero()) { return one.precision(precision); } @@ -2745,7 +2744,7 @@ public static Apcomplex hypergeometricU(Apcomplex a, Apcomplex b, Apcomplex z) public static Apcomplex erf(Apcomplex z) throws ApfloatRuntimeException { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { return z; } @@ -2769,7 +2768,7 @@ public static Apcomplex erf(Apcomplex z) static Apcomplex erfFixedPrecision(Apcomplex z) throws ApfloatRuntimeException { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { return z; } @@ -2878,7 +2877,7 @@ static Apcomplex erfiFixedPrecision(Apcomplex z) public static Apcomplex fresnelS(Apcomplex z) throws ApfloatRuntimeException { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { return z; } @@ -2925,7 +2924,7 @@ public static Apcomplex fresnelS(Apcomplex z) public static Apcomplex fresnelC(Apcomplex z) throws ApfloatRuntimeException { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { return z; } @@ -3040,7 +3039,7 @@ public static Apcomplex expIntegralEi(Apcomplex z) public static Apcomplex logIntegral(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { return z; } diff --git a/apfloat/src/main/java/org/apfloat/ApfloatHelper.java b/apfloat/src/main/java/org/apfloat/ApfloatHelper.java index 2ad0d14..51ab4ea 100644 --- a/apfloat/src/main/java/org/apfloat/ApfloatHelper.java +++ b/apfloat/src/main/java/org/apfloat/ApfloatHelper.java @@ -413,16 +413,16 @@ private static void checkPowPrecision(long targetPrecision) private static Apcomplex checkPowBasic(Apcomplex z, Apcomplex w, long targetPrecision) throws ArithmeticException, ApfloatRuntimeException { - if (w.real().signum() == 0 && w.imag().signum() == 0) + if (w.isZero()) { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { throw new ArithmeticException("Zero to power zero"); } return new Apcomplex(new Apfloat(1, Apfloat.INFINITE, z.radix())); } - else if (z.real().signum() == 0 && z.imag().signum() == 0) + else if (z.isZero()) { if (w.real().signum() <= 0) { diff --git a/apfloat/src/main/java/org/apfloat/BesselHelper.java b/apfloat/src/main/java/org/apfloat/BesselHelper.java index 76a0428..92915d0 100644 --- a/apfloat/src/main/java/org/apfloat/BesselHelper.java +++ b/apfloat/src/main/java/org/apfloat/BesselHelper.java @@ -106,7 +106,7 @@ private Apcomplex besselI(Apcomplex ν) private Apcomplex besselFirstKind(Apcomplex ν, boolean negate) throws ArithmeticException, ApfloatRuntimeException { - if (ν.isInteger() && z.real().signum() == 0 && z.imag().signum() == 0) + if (ν.isInteger() && z.isZero()) { return (ν.real().signum() == 0 ? Apint.ONES[radix] : z); } @@ -119,7 +119,7 @@ private Apcomplex besselFirstKind(Apcomplex ν, boolean negate) private Apcomplex besselY() throws ArithmeticException, ApfloatRuntimeException { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { throw new ArithmeticException("Bessel Y of zero"); } @@ -134,7 +134,7 @@ private Apcomplex besselY() private Apcomplex besselK() throws ArithmeticException, ApfloatRuntimeException { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { throw new ArithmeticException("Bessel K of zero"); } @@ -178,7 +178,7 @@ private Apcomplex besselSecondKind(BiFunction f result = f.apply(ν, z); - if (result.real().signum() == 0 && result.imag().signum() == 0) // The result shouldn't be exactly zero, it means full loss of significant digits + if (result.isZero()) // The result shouldn't be exactly zero, it means full loss of significant digits { precisionLoss = workingPrecision; } diff --git a/apfloat/src/main/java/org/apfloat/FixedPrecisionApcomplexHelper.java b/apfloat/src/main/java/org/apfloat/FixedPrecisionApcomplexHelper.java index 7471c78..dc859b8 100644 --- a/apfloat/src/main/java/org/apfloat/FixedPrecisionApcomplexHelper.java +++ b/apfloat/src/main/java/org/apfloat/FixedPrecisionApcomplexHelper.java @@ -281,7 +281,7 @@ public Apfloat norm(Apcomplex z) public Apcomplex acos(Apcomplex z) throws ApfloatRuntimeException { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { // Zero always has infinite precision so when zero input causes nonzero output special care must be taken return halfPi(z.radix()); @@ -300,7 +300,7 @@ public Apcomplex acos(Apcomplex z) public Apcomplex acosh(Apcomplex z) throws ApfloatRuntimeException { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { // Zero always has infinite precision so when zero input causes nonzero output special care must be taken return valueOf(new Apcomplex(Apfloat.ZEROS[z.radix()], halfPi(z.radix()))); diff --git a/apfloat/src/main/java/org/apfloat/HurwitzZetaHelper.java b/apfloat/src/main/java/org/apfloat/HurwitzZetaHelper.java index 1cf0678..8d9d63f 100644 --- a/apfloat/src/main/java/org/apfloat/HurwitzZetaHelper.java +++ b/apfloat/src/main/java/org/apfloat/HurwitzZetaHelper.java @@ -48,7 +48,7 @@ public static Apcomplex zeta(Apcomplex s, Apcomplex a) { throw new ArithmeticException("Zeta of first argument one"); } - if (s.real().signum() == 0 && s.imag().signum() == 0 && a.real().signum() == 0 && a.imag().signum() == 0) + if (s.isZero() && a.isZero()) { Apint two = new Apint(2, radix); return new Aprational(one, two); @@ -56,7 +56,7 @@ public static Apcomplex zeta(Apcomplex s, Apcomplex a) long precision = Math.min(s.precision(), a.precision()); if (a.isInteger() && a.real().signum() <= 0) { - if (s.real().signum() < 0 || s.real().signum() == 0 && s.imag().signum() == 0) + if (s.real().signum() < 0 || s.isZero()) { // Use recurrence formula: zeta(s, a) = a^-s + zeta(s, a + 1) Apcomplex t = Apcomplex.ZERO; diff --git a/apfloat/src/main/java/org/apfloat/HypergeometricHelper.java b/apfloat/src/main/java/org/apfloat/HypergeometricHelper.java index 868ff1b..1777043 100644 --- a/apfloat/src/main/java/org/apfloat/HypergeometricHelper.java +++ b/apfloat/src/main/java/org/apfloat/HypergeometricHelper.java @@ -203,7 +203,7 @@ public Apcomplex transform(Apcomplex s, Apcomplex c, Apcomplex base1, Apcomplex term2 = pow(base2, exp2).multiply(pow(base3, exp3)).divide(gamma(g3).multiply(gamma(g4)).multiply(gamma(c2))).multiply(evaluate(a2, b2, c2, z)); } Apcomplex d = term1.subtract(term2); - long precisionLoss = (d.real().signum() == 0 && d.imag().signum() == 0 ? workingPrecision : targetPrecision - d.precision()); + long precisionLoss = (d.isZero() ? workingPrecision : targetPrecision - d.precision()); if (retry && precisionLoss > 1) // Allow a precision loss of 1 (which happens often), otherwise retry with increased precision { throw new RetryException(precisionLoss); @@ -287,7 +287,7 @@ public Apcomplex value(Hypergeometric2F1Helper helper) @Override public boolean isApplicable(Apcomplex z) { - return z.real().signum() != 0 || z.imag().signum() != 0; + return !z.isZero(); } @Override @@ -365,7 +365,7 @@ public Apcomplex value(Hypergeometric2F1Helper helper) @Override public boolean isApplicable(Apcomplex z) { - return z.real().signum() != 0 || z.imag().signum() != 0; + return !z.isZero(); } @Override @@ -502,7 +502,7 @@ else if (br.compareTo(n) > 0) Apfloat n1 = n.add(Apint.ONES[radix]); Apcomplex[] pochhammer = Arrays.stream(a).map(ai -> ApcomplexMath.pochhammer(ai, n1)).toArray(Apcomplex[]::new); result = ApcomplexMath.product(pochhammer); - if (result.real().signum() != 0 || result.imag().signum() != 0) + if (!result.isZero()) { Apfloat n2 = n.add(new Apint(2, radix)); Apcomplex[] gamma = Arrays.stream(b).map(n1::add).map(this::ensureGammaPrecision).map(ApcomplexMath::gamma).toArray(Apcomplex[]::new); @@ -558,7 +558,7 @@ private Apcomplex hypergeometricPFQ() } if (a.length > b.length + 1L) { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { return new Apfloat(1, targetPrecision, radix); } @@ -797,7 +797,7 @@ private Apcomplex checkResult() { throw new ArithmeticException("Division by zero"); } - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { return new Apfloat(1, targetPrecision, radix); } @@ -856,7 +856,7 @@ private Apcomplex evaluate(Apcomplex[] a, Apcomplex[] b, Apcomplex z) numerator = numerator.multiply(a[j]); a[j] = a[j].add(one); } - if (numerator.real().signum() == 0 && numerator.imag().signum() == 0) + if (numerator.isZero()) { return s; // It was a polynomial } @@ -871,9 +871,9 @@ private Apcomplex evaluate(Apcomplex[] a, Apcomplex[] b, Apcomplex z) t = numerator.divide(denominator); s = s.add(t); maxSScale = Math.max(maxSScale, s.scale()); - } while (i.compareTo(minN) <= 0 || divergentSeries && checkDivergence(o, t) || s.real().signum() == 0 && s.imag().signum() == 0 || s.scale() - t.scale() <= workingPrecision); // Subtraction might overflow + } while (i.compareTo(minN) <= 0 || divergentSeries && checkDivergence(o, t) || s.isZero() || s.scale() - t.scale() <= workingPrecision); // Subtraction might overflow - precisionLoss = (s.real().signum() == 0 && s.imag().signum() == 0 ? extendedPrecision : maxSScale - s.scale()); // Loss due to scale of s reduced from its peak (loss off most significant digits) + precisionLoss = (s.isZero() ? extendedPrecision : maxSScale - s.scale()); // Loss due to scale of s reduced from its peak (loss off most significant digits) if (workingPrecision - s.precision() > 1) // Often the precision is reduced by 1 { precisionLoss = Util.ifFinite(precisionLoss, precisionLoss + workingPrecision - s.precision()); // Loss due to accumulation (loss off least significant digits) diff --git a/apfloat/src/main/java/org/apfloat/IncompleteGammaHelper.java b/apfloat/src/main/java/org/apfloat/IncompleteGammaHelper.java index 2da1613..9e544a0 100644 --- a/apfloat/src/main/java/org/apfloat/IncompleteGammaHelper.java +++ b/apfloat/src/main/java/org/apfloat/IncompleteGammaHelper.java @@ -233,7 +233,7 @@ private static class RetryException public static Apcomplex gamma(Apcomplex a, Apcomplex z) { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { if (a.real().signum() <= 0) { @@ -248,9 +248,7 @@ public static Apcomplex gamma(Apcomplex a, Apcomplex z) public static Apcomplex gamma(Apcomplex a, Apcomplex z0, Apcomplex z1) { - if (a.real().signum() == 0 && a.imag().signum() == 0 && - z0.real().signum() == 0 && z0.imag().signum() == 0 && - z1.real().signum() == 0 && z1.imag().signum() == 0) + if (a.isZero() && z0.isZero() && z1.isZero()) { throw new ArithmeticException("Gamma of zero"); } @@ -260,11 +258,11 @@ public static Apcomplex gamma(Apcomplex a, Apcomplex z0, Apcomplex z1) } checkPrecision(a, z0, z1); - if (z0.real().signum() == 0 && z0.imag().signum() == 0) + if (z0.isZero()) { return lowerGamma(a, z1, null).getValue(); } - if (z1.real().signum() == 0 && z1.imag().signum() == 0) + if (z1.isZero()) { return lowerGamma(a, z0, null).getValue().negate(); } @@ -590,13 +588,13 @@ private static ContinuedFractionResult continuedFraction(Sequence s, int radix, bn = s.b(n).precision(workingPrecision); d = d.multiply(an).add(bn); d = ApfloatHelper.ensurePrecision(d, workingPrecision); - if (d.real().signum() == 0 && d.imag().signum() == 0) + if (d.isZero()) { d = tiny(bn, workingPrecision); } c = bn.add(an.divide(c)); c = ApfloatHelper.ensurePrecision(c, workingPrecision); - if (c.real().signum() == 0 && c.imag().signum() == 0) + if (c.isZero()) { c = tiny(bn, workingPrecision); } @@ -617,7 +615,7 @@ private static ContinuedFractionResult continuedFraction(Sequence s, int radix, private static Apcomplex tiny(Apcomplex z, long workingPrecision) { - if (z.real().signum() == 0 && z.imag().signum() == 0) + if (z.isZero()) { z = new Apfloat(1, workingPrecision, z.radix()); } diff --git a/apfloat/src/main/java/org/apfloat/ZetaHelper.java b/apfloat/src/main/java/org/apfloat/ZetaHelper.java index 4de6c4a..43360f6 100644 --- a/apfloat/src/main/java/org/apfloat/ZetaHelper.java +++ b/apfloat/src/main/java/org/apfloat/ZetaHelper.java @@ -54,7 +54,7 @@ public static Apcomplex zeta(Apcomplex s) { return Apcomplex.ZEROS[radix]; } - if (s.real().signum() == 0 && s.imag().signum() == 0) + if (s.isZero()) { return new Aprational(one, two).negate(); } diff --git a/apfloat/src/test/java/org/apfloat/ApcomplexTest.java b/apfloat/src/test/java/org/apfloat/ApcomplexTest.java index 02acc6e..0d59a7f 100644 --- a/apfloat/src/test/java/org/apfloat/ApcomplexTest.java +++ b/apfloat/src/test/java/org/apfloat/ApcomplexTest.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2002-2023 Mikko Tommila + * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -38,7 +38,7 @@ import junit.framework.TestSuite; /** - * @version 1.12.0 + * @version 1.13.0 * @author Mikko Tommila */ @@ -68,6 +68,7 @@ public static TestSuite suite() suite.addTest(new ApcomplexTest("testPrecision")); suite.addTest(new ApcomplexTest("testScale")); suite.addTest(new ApcomplexTest("testSize")); + suite.addTest(new ApcomplexTest("testIsZero")); suite.addTest(new ApcomplexTest("testIsInteger")); suite.addTest(new ApcomplexTest("testNegate")); suite.addTest(new ApcomplexTest("testAdd")); @@ -447,6 +448,18 @@ public static void testSize() assertEquals("0 size", 0, a.size()); } + public static void testIsZero() + { + Apcomplex a = new Apcomplex("(1, 1)"); + assertFalse("(1, 1)", a.isZero()); + a = new Apcomplex("(1.5, 0)"); + assertFalse("(1.5, 0)", a.isZero()); + a = new Apcomplex("(0, 1)"); + assertFalse("(0, 1)", a.isZero()); + a = new Apcomplex("0"); + assertTrue("0", a.isZero()); + } + public static void testIsInteger() { Apcomplex a = new Apcomplex("(1, 1)");