Skip to content

Commit

Permalink
fix thread safe problem in SeriesCalculator
Browse files Browse the repository at this point in the history
  • Loading branch information
eobermuhlner committed Oct 7, 2019
1 parent 3a86c1c commit 1a66d35
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected SeriesCalculator(boolean calculateInPairs) {
* @param mathContext the {@link MathContext}
* @return the calculated result
*/
public BigDecimal calculate(BigDecimal x, MathContext mathContext) {
public synchronized BigDecimal calculate(BigDecimal x, MathContext mathContext) {
BigDecimal acceptableError = ONE.movePointLeft(mathContext.getPrecision() + 1);

PowerIterator powerIterator = createPowerIterator(x, mathContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
import java.util.function.Function;

Expand Down Expand Up @@ -428,9 +431,9 @@ public void testBernoulliNegative() {

@Test
public void testBernoulliUnlimited() {
BigDecimalMath.bernoulli(0, MathContext.UNLIMITED);
BigDecimalMath.bernoulli(1, MathContext.UNLIMITED);
BigDecimalMath.bernoulli(3, MathContext.UNLIMITED);
assertBigDecimal(toCheck(1), BigDecimalMath.bernoulli(0, MathContext.UNLIMITED), MC_CHECK_DOUBLE);
assertBigDecimal(toCheck(-1.0/2), BigDecimalMath.bernoulli(1, MathContext.UNLIMITED), MC_CHECK_DOUBLE);
assertBigDecimal(toCheck(1), BigDecimalMath.bernoulli(3, MathContext.UNLIMITED), MC_CHECK_DOUBLE);
}

@Test(expected = ArithmeticException.class)
Expand Down Expand Up @@ -1140,6 +1143,11 @@ public void testSinRandom() {
(x, mathContext) -> BigDecimalMath.sin(x, mathContext));
}

@Test
public void testSinRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testSinRandom());
}

@Test(expected = UnsupportedOperationException.class)
public void testSinUnlimitedFail() {
BigDecimalMath.sin(BigDecimal.valueOf(2), MathContext.UNLIMITED);
Expand All @@ -1165,6 +1173,12 @@ public void testAsinRandom() {
(x, mathContext) -> BigDecimalMath.asin(x, mathContext));
}

@Test
public void testAsinRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testAsinRandom());
}


@Test(expected = ArithmeticException.class)
public void testAsinGreaterOne() {
BigDecimalMath.asin(new BigDecimal("1.00001"), MC);
Expand Down Expand Up @@ -1210,6 +1224,12 @@ public void testCosRandom() {
(x, mathContext) -> BigDecimalMath.cos(x, mathContext));
}

@Test
public void testCosRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testCosRandom());
}


@Test(expected = UnsupportedOperationException.class)
public void testCosUnlimitedFail() {
BigDecimalMath.cos(BigDecimal.valueOf(2), MathContext.UNLIMITED);
Expand All @@ -1224,7 +1244,12 @@ public void testAcosRandom() {
Math::acos,
(x, mathContext) -> BigDecimalMath.acos(x, mathContext));
}


@Test
public void testAcosRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testAcosRandom());
}

@Test
public void testAcosMinusOne() {
for (int precision = 1; precision <= 2001; precision+=100) {
Expand Down Expand Up @@ -1270,6 +1295,11 @@ public void testTanRandom() {
(x, mathContext) -> BigDecimalMath.tan(x, mathContext));
}

@Test
public void testTanRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testTanRandom());
}

@Test(expected = UnsupportedOperationException.class)
public void testTanUnlimitedFail() {
BigDecimalMath.tan(BigDecimal.valueOf(2), MathContext.UNLIMITED);
Expand All @@ -1285,6 +1315,11 @@ public void testAtanRandom() {
(x, mathContext) -> BigDecimalMath.atan(x, mathContext));
}

@Test
public void testAtanRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testAtanRandom());
}

@Test(expected = ArithmeticException.class)
public void testAtan2ZeroZero() {
BigDecimalMath.atan2(BigDecimal.ZERO, BigDecimal.ZERO, MC);
Expand Down Expand Up @@ -1328,6 +1363,11 @@ public void testAtan2Random() {
});
}

@Test
public void testAtan2RandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testAtan2Random());
}

@Test(expected = UnsupportedOperationException.class)
public void testAtanUnlimitedFail() {
BigDecimalMath.atan(BigDecimal.valueOf(2), MathContext.UNLIMITED);
Expand Down Expand Up @@ -1361,7 +1401,12 @@ public void testSinhRandom() {
Math::sinh,
(x, mathContext) -> BigDecimalMath.sinh(x, mathContext));
}


@Test
public void testSinhRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testSinhRandom());
}

@Test
public void testAsinhRandom() {
assertRandomCalculation(
Expand All @@ -1372,6 +1417,11 @@ public void testAsinhRandom() {
(x, mathContext) -> BigDecimalMath.asinh(x, mathContext));
}

@Test
public void testAsinhRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testAsinhRandom());
}

@Test(expected = UnsupportedOperationException.class)
public void testAsinhUnlimitedFail() {
BigDecimalMath.asinh(BigDecimal.valueOf(2), MathContext.UNLIMITED);
Expand All @@ -1391,6 +1441,11 @@ public void testAcoshRandom() {
(x, mathContext) -> BigDecimalMath.acosh(x, mathContext));
}

@Test
public void testAcoshRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testAcoshRandom());
}

@Test(expected = UnsupportedOperationException.class)
public void testAcoshUnlimitedFail() {
BigDecimalMath.acosh(BigDecimal.valueOf(2), MathContext.UNLIMITED);
Expand All @@ -1410,6 +1465,11 @@ public void testAtanhRandom() {
(x, mathContext) -> BigDecimalMath.atanh(x, mathContext));
}

@Test
public void testAtanhRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testAtanhRandom());
}

@Test(expected = ArithmeticException.class)
public void testAtanhFailOne() {
BigDecimalMath.atanh(BigDecimal.ONE, MC);
Expand Down Expand Up @@ -1446,6 +1506,11 @@ public void testAcothRandom() {
(x, mathContext) -> BigDecimalMath.acoth(x, mathContext));
}

@Test
public void testAcothRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testAcothRandom());
}

@Test(expected = UnsupportedOperationException.class)
public void testAcothUnlimitedFail() {
BigDecimalMath.acoth(BigDecimal.valueOf(2), MathContext.UNLIMITED);
Expand All @@ -1465,6 +1530,11 @@ public void testCoshRandom() {
(x, mathContext) -> BigDecimalMath.cosh(x, mathContext));
}

@Test
public void testCoshRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testCoshRandom());
}

@Test(expected = UnsupportedOperationException.class)
public void testCoshUnlimitedFail() {
BigDecimalMath.cosh(BigDecimal.valueOf(2), MathContext.UNLIMITED);
Expand All @@ -1480,6 +1550,11 @@ public void testTanhRandom() {
(x, mathContext) -> BigDecimalMath.tanh(x, mathContext));
}

@Test
public void testTanhRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testTanhRandom());
}

@Test(expected = UnsupportedOperationException.class)
public void testTanhUnlimitedFail() {
BigDecimalMath.tanh(BigDecimal.valueOf(2), MathContext.UNLIMITED);
Expand All @@ -1505,6 +1580,11 @@ public void testCothRandom() {
(x, mathContext) -> BigDecimalMath.coth(x, mathContext));
}

@Test
public void testCothRandomMultiThreaded() throws Throwable {
runMultiThreaded(() -> testCothRandom());
}

@Test(expected = UnsupportedOperationException.class)
public void testCothUnlimitedFail() {
BigDecimalMath.coth(BigDecimal.valueOf(2), MathContext.UNLIMITED);
Expand Down Expand Up @@ -1730,8 +1810,8 @@ private void assertPrecisionCalculation(BigDecimal expected, Function<MathContex
private static interface Function3<T1, T2, T3, R> {
R apply(T1 t1, T2 t2, T3 t3);
}
private void assertRandomCalculation(int count, String functionName, Function<Random, Double> xFunction, Function<Double, Double> doubleFunction, BiFunction<BigDecimal, MathContext, BigDecimal> calculation) {

void assertRandomCalculation(int count, String functionName, Function<Random, Double> xFunction, Function<Double, Double> doubleFunction, BiFunction<BigDecimal, MathContext, BigDecimal> calculation) {
Random random = new Random(1);

for (int i = 0; i < count; i++) {
Expand Down Expand Up @@ -1861,7 +1941,40 @@ public static Exception assertThrows(Class<? extends Exception> exceptionClass,
return result;
}

private static BigDecimal toCheck(double value) {
private static void runMultiThreaded(Runnable runnable) throws Throwable {
Callable<Void> callable = () -> {
runnable.run();
return null;
};

int n = 100;

AtomicReference<Throwable> exception = new AtomicReference<>();
CountDownLatch countDownLatch = new CountDownLatch(n);
for (int i = 0; i < n; i++) {
final int id = i;
Thread thread = new Thread(() -> {
System.out.println("STARTED " + id);
try {
callable.call();
} catch (Throwable e) {
System.out.println("EXCEPTION " + e);
exception.set(e);
} finally {
System.out.println("FINISHED " + id);
countDownLatch.countDown();
}
});
thread.start();
}
countDownLatch.await();

if (exception.get() != null) {
throw exception.get();
}
}

private static BigDecimal toCheck(double value) {
long longValue = (long) value;
if (value == (double)longValue) {
return BigDecimal.valueOf(longValue);
Expand Down

0 comments on commit 1a66d35

Please sign in to comment.