1
0

not final but im lazy

This commit is contained in:
2024-10-02 23:13:14 +03:00
parent 26ce772cd0
commit 072f536fd8
4 changed files with 89 additions and 166 deletions

View File

@@ -1,5 +1,11 @@
package ru.lionarius;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiConsumer;
import java.util.function.Function;
@@ -30,7 +36,7 @@ public class IntegralCalculator {
* @param progressCallback A callback function to track progress. Can be null.
* @throws IllegalArgumentException if the accuracy is less than or equal to zero.
*/
public IntegralCalculator(double accuracy, BiConsumer<Long, Long> progressCallback) {
public IntegralCalculator(double accuracy, final BiConsumer<Long, Long> progressCallback) {
if (accuracy <= 0.0)
throw new IllegalArgumentException("accuracy must be a positive number");
@@ -61,17 +67,23 @@ public class IntegralCalculator {
* Calculates the definite integral of the specified function over a given interval
* using the trapezoidal rule.
*
* @param function The function to integrate.
* @param lowerBound The lower bound of the integration interval.
* @param upperBound The upper bound of the integration interval.
* @param function The function to integrate.
* @param lower The lower bound of the integration interval.
* @param upper The upper bound of the integration interval.
* @return The estimated value of the definite integral.
* @throws NullPointerException if the function is null.
*/
public double calculate(Function<Double, Double> function, double lowerBound, double upperBound) {
public double calculate(final Function<Double, Double> function, double lower, double upper, ExecutorService executor, int parallelism) throws ExecutionException, InterruptedException {
if (function == null)
throw new NullPointerException("function cannot be null");
if (lowerBound == upperBound) {
if (executor == null)
throw new NullPointerException("executor cannot be null");
if (parallelism <= 0)
throw new IllegalArgumentException("parallelism must be a positive number");
if (lower == upper) {
this.callProgressCallback(0, 1);
this.callProgressCallback(1, 1);
@@ -79,24 +91,54 @@ public class IntegralCalculator {
}
var invert = false;
if (lowerBound > upperBound) {
if (lower > upper) {
invert = true;
var temp = lowerBound;
lowerBound = upperBound;
upperBound = temp;
var temp = lower;
lower = upper;
upper = temp;
}
final var lowerBound = lower;
final var upperBound = upper;
var n = (long) Math.ceil((upperBound - lowerBound) / this.accuracy);
var h = (upperBound - lowerBound) / n;
this.callProgressCallback(0, n);
var sum = (function.apply(lowerBound) + function.apply(upperBound)) / 2;
for (var i = 1L; i < n; i++) {
sum += function.apply(lowerBound + h * i);
var remainder = n % parallelism;
var partitionSize = n / parallelism;
var currentStart = 0L;
this.callProgressCallback(i, n);
var sum = (function.apply(lowerBound) + function.apply(upperBound)) / 2;
final var futures = new ArrayList<Future<Double>>();
final var total = new AtomicLong(0);
for (var i = 0; i < parallelism; i++) {
final var start = currentStart;
final var end = currentStart + partitionSize + (remainder > 0 ? 1 : 0);
if (remainder > 0)
remainder--;
currentStart = end;
futures.add(executor.submit(() -> {
var prevSteps = 0;
var steps = 0;
var partitionSum = 0.0;
for (var j = start; j < end; j++) {
partitionSum += function.apply(lowerBound + h * j);
steps++;
var progress = total.incrementAndGet();
progressCallback.accept(progress, n);
}
return partitionSum;
}));
}
for (var future : futures) {
sum += future.get();
}
sum *= h;

View File

@@ -1,5 +1,7 @@
package ru.lionarius;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.function.Function;
public class Main {
@@ -8,47 +10,42 @@ public class Main {
var lowerBound = 0.0;
var upperBound = 1.0;
double[] accuracies = {0.001, 0.00001, 0.0000001, 0.000000001, 0.000000001};
var threads = new Thread[accuracies.length];
var executor = Executors.newCachedThreadPool();
for (final var accuracy : accuracies) {
var calculator = new IntegralCalculator(
accuracy,
(current, total) -> {
if (current % (total / 15) != 0)
return;
System.out.printf(
"[%s] Progress: %.2f%%%n",
Thread.currentThread().getName(),
(current * 100.0 / total)
);
}
);
for (var i = 0; i < accuracies.length; i++) {
final var accuracy = accuracies[i];
var thread = new Thread(() -> {
var calculator = new IntegralCalculator(
accuracy,
(current, total) -> {
if (current % (total / 15) != 0)
return;
System.out.printf(
"[%s] Progress: %.2f%%%n",
Thread.currentThread().getName(),
(current * 100.0 / total)
);
}
);
var startTime = System.nanoTime();
var startTime = System.nanoTime();
double value = 0;
try {
value = calculator.calculate(function, lowerBound, upperBound, executor, 12);
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
var value = calculator.calculate(function, lowerBound, upperBound);
var totalTime = System.nanoTime() - startTime;
var totalTime = System.nanoTime() - startTime;
System.out.printf(
"[%s] Calculated value: %.15f | Accuracy: %e | Time: %.9fms%n",
Thread.currentThread().getName(),
value,
accuracy,
totalTime / 1_000_000.0
);
});
threads[i] = thread;
thread.start();
System.out.printf(
"[%s] Calculated value: %.15f | Accuracy: %e | Time: %.9fms%n",
Thread.currentThread().getName(),
value,
accuracy,
totalTime / 1_000_000.0
);
}
try {
for (var thread : threads)
thread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
executor.shutdown();
}
}

View File

@@ -1,21 +0,0 @@
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import ru.lionarius.AreaCalculator;
class AreaCalculatorTests {
private final AreaCalculator areaCalculator = new AreaCalculator();
@Test
void circleArea() {
assertEquals(0.0, this.areaCalculator.circle(0.0));
assertEquals(Math.PI, this.areaCalculator.circle(1.0));
assertEquals(Math.PI * 4.0, this.areaCalculator.circle(2.0));
assertThrowsExactly(IllegalArgumentException.class, () -> this.areaCalculator.circle(-1.0));
assertEquals(Double.POSITIVE_INFINITY, this.areaCalculator.circle(Double.MAX_VALUE));
assertEquals(Double.NaN, this.areaCalculator.circle(Double.NaN));
}
}

View File

@@ -1,95 +0,0 @@
import org.junit.jupiter.api.Test;
import ru.lionarius.IntegralCalculator;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiConsumer;
import java.util.function.Function;
import static org.junit.jupiter.api.Assertions.*;
class IntegralCalculatorTests {
private static void assertIntegral(final double expected, final IntegralCalculator calculator, final Function<Double, Double> function, final double lowerBound, final double upperBound) {
var value = calculator.calculate(function, lowerBound, upperBound);
assertEquals(expected, value, calculator.getAccuracy());
}
@Test
void accuracyValidRange() {
assertThrowsExactly(IllegalArgumentException.class, () -> new IntegralCalculator(0.0));
assertThrowsExactly(IllegalArgumentException.class, () -> new IntegralCalculator(-0.0));
assertThrowsExactly(IllegalArgumentException.class, () -> new IntegralCalculator(-1.0));
assertDoesNotThrow(() -> new IntegralCalculator(Double.MIN_VALUE));
}
@Test
void accuracy_SinXX() {
final var actualValue = 0.30116867893975678925156571418732239589025264018044883800265445461081000961676790443;
final Function<Double, Double> function = x -> Math.sin(x) * x;
final var lowerBound = 0.0;
final var upperBound = 1.0;
final double[] accuracies = {0.001, 0.00001, 0.0000001};
for (var accuracy : accuracies) {
var calculator = new IntegralCalculator(accuracy);
assertIntegral(actualValue, calculator, function, lowerBound, upperBound);
}
}
@Test
void bounds_X() {
final var calculator = new IntegralCalculator(0.1);
final Function<Double, Double> function = x -> x;
final var lowerBound = 0.0;
final var upperBound = 1.0;
assertIntegral(0.5, calculator, function, lowerBound, upperBound);
assertIntegral(-0.5, calculator, function, upperBound, lowerBound);
assertIntegral(0.0, calculator, function, lowerBound, lowerBound);
}
@Test
public void testProgressCallbackDifferentBounds() {
final var currentStep = new AtomicLong();
final var totalSteps = new AtomicLong();
final var callbackCount = new AtomicLong(0);
final BiConsumer<Long, Long> progressCallback = (current, total) -> {
currentStep.set(current);
totalSteps.set(total);
callbackCount.incrementAndGet();
};
final var calculator = new IntegralCalculator(0.01, progressCallback);
calculator.calculate(x -> x, 0, 1);
assertTrue(callbackCount.get() >= 2, "Callback should be called at least twice");
assertEquals(totalSteps.get(), currentStep.get(), "Final progress should be equal to total steps");
}
@Test
public void testProgressCallbackSameBounds() {
var currentStep = new AtomicLong();
var totalSteps = new AtomicLong();
var callbackCount = new AtomicLong(0);
BiConsumer<Long, Long> progressCallback = (current, total) -> {
currentStep.set(current);
totalSteps.set(total);
callbackCount.incrementAndGet();
};
var calculator = new IntegralCalculator(0.01, progressCallback);
calculator.calculate(x -> x, 0, 0);
assertTrue(callbackCount.get() >= 2, "Callback should be called at least twice");
assertEquals(totalSteps.get(), currentStep.get(), "Final progress should be equal to total steps");
}
}