lab6
This commit is contained in:
@@ -1,12 +1,7 @@
|
|||||||
package ru.lionarius;
|
package ru.lionarius;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.function.Consumer;
|
||||||
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;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,7 +21,7 @@ public class IntegralCalculator {
|
|||||||
* The callback is called at least twice: once at the beginning, and once at the end of computation.
|
* The callback is called at least twice: once at the beginning, and once at the end of computation.
|
||||||
* Takes the current step and the total number of steps.
|
* Takes the current step and the total number of steps.
|
||||||
*/
|
*/
|
||||||
private final BiConsumer<Long, Long> progressCallback;
|
private final Consumer<Long> progressCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an {@link IntegralCalculator} with the specified accuracy and an optional progress callback.
|
* Constructs an {@link IntegralCalculator} with the specified accuracy and an optional progress callback.
|
||||||
@@ -36,7 +31,7 @@ public class IntegralCalculator {
|
|||||||
* @param progressCallback A callback function to track progress. Can be null.
|
* @param progressCallback A callback function to track progress. Can be null.
|
||||||
* @throws IllegalArgumentException if the accuracy is less than or equal to zero.
|
* @throws IllegalArgumentException if the accuracy is less than or equal to zero.
|
||||||
*/
|
*/
|
||||||
public IntegralCalculator(double accuracy, final BiConsumer<Long, Long> progressCallback) {
|
public IntegralCalculator(double accuracy, final Consumer<Long> progressCallback) {
|
||||||
if (accuracy <= 0.0)
|
if (accuracy <= 0.0)
|
||||||
throw new IllegalArgumentException("accuracy must be a positive number");
|
throw new IllegalArgumentException("accuracy must be a positive number");
|
||||||
|
|
||||||
@@ -73,20 +68,19 @@ public class IntegralCalculator {
|
|||||||
* @return The estimated value of the definite integral.
|
* @return The estimated value of the definite integral.
|
||||||
* @throws NullPointerException if the function is null.
|
* @throws NullPointerException if the function is null.
|
||||||
*/
|
*/
|
||||||
public double calculate(final Function<Double, Double> function, double lower, double upper, ExecutorService executor, int parallelism) throws ExecutionException, InterruptedException {
|
public double calculate(
|
||||||
|
final Function<Double, Double> function,
|
||||||
|
double lower,
|
||||||
|
double upper,
|
||||||
|
int parallelism
|
||||||
|
) throws InterruptedException {
|
||||||
if (function == null)
|
if (function == null)
|
||||||
throw new NullPointerException("function cannot be null");
|
throw new NullPointerException("function cannot be null");
|
||||||
|
|
||||||
if (executor == null)
|
|
||||||
throw new NullPointerException("executor cannot be null");
|
|
||||||
|
|
||||||
if (parallelism <= 0)
|
if (parallelism <= 0)
|
||||||
throw new IllegalArgumentException("parallelism must be a positive number");
|
throw new IllegalArgumentException("parallelism must be a positive number");
|
||||||
|
|
||||||
if (lower == upper) {
|
if (lower == upper) {
|
||||||
this.callProgressCallback(0, 1);
|
|
||||||
this.callProgressCallback(1, 1);
|
|
||||||
|
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,35 +99,35 @@ public class IntegralCalculator {
|
|||||||
var n = (long) Math.ceil((upperBound - lowerBound) / this.accuracy);
|
var n = (long) Math.ceil((upperBound - lowerBound) / this.accuracy);
|
||||||
var h = (upperBound - lowerBound) / n;
|
var h = (upperBound - lowerBound) / n;
|
||||||
|
|
||||||
this.callProgressCallback(0, n);
|
var id = LazyStorage.getInstance().startCalculation(n);
|
||||||
|
LazyStorage.getInstance().setValue(id, (function.apply(lowerBound) + function.apply(upperBound)) / 2);
|
||||||
var sum = (function.apply(lowerBound) + function.apply(upperBound)) / 2;
|
final var threads = new ArrayList<Thread>();
|
||||||
final var futures = new ArrayList<Future<Double>>();
|
|
||||||
for (var i = 0; i < parallelism; i++) {
|
for (var i = 0; i < parallelism; i++) {
|
||||||
final var order = i;
|
final var order = i;
|
||||||
futures.add(executor.submit(() -> {
|
var thread = new Thread(() -> {
|
||||||
var partitionSum = 0.0;
|
|
||||||
for (var j = order; j < n; j += parallelism) {
|
for (var j = order; j < n; j += parallelism) {
|
||||||
partitionSum += function.apply(lowerBound + h * j);
|
LazyStorage.getInstance().addProgress(id, 1);
|
||||||
|
LazyStorage.getInstance().addToValue(id, function.apply(lowerBound + h * j));
|
||||||
|
|
||||||
this.callProgressCallback(j, n);
|
if (j % (n / 15) == 0)
|
||||||
|
this.callProgressCallback(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread.start();
|
||||||
|
threads.add(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
return partitionSum;
|
for (var thread : threads) {
|
||||||
}));
|
thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var future : futures) {
|
var sum = LazyStorage.getInstance().stopCalculation(id);
|
||||||
sum += future.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
sum *= h;
|
sum *= h;
|
||||||
|
|
||||||
if (invert)
|
if (invert)
|
||||||
sum = -sum;
|
sum = -sum;
|
||||||
|
|
||||||
this.callProgressCallback(n, n);
|
|
||||||
|
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,8 +137,8 @@ public class IntegralCalculator {
|
|||||||
* @param current The current step in the integration process.
|
* @param current The current step in the integration process.
|
||||||
* @param total The total number of steps in the integration process.
|
* @param total The total number of steps in the integration process.
|
||||||
*/
|
*/
|
||||||
private void callProgressCallback(long current, long total) {
|
private void callProgressCallback(long id) {
|
||||||
if (this.progressCallback != null)
|
if (this.progressCallback != null)
|
||||||
this.progressCallback.accept(current, total);
|
this.progressCallback.accept(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
83
src/main/java/ru/lionarius/LazyStorage.java
Normal file
83
src/main/java/ru/lionarius/LazyStorage.java
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package ru.lionarius;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class LazyStorage {
|
||||||
|
|
||||||
|
private static volatile LazyStorage INSTANCE;
|
||||||
|
|
||||||
|
private final HashMap<Long, Calculation> calculations = new HashMap<>();
|
||||||
|
private long currentId = 0;
|
||||||
|
|
||||||
|
private LazyStorage() {
|
||||||
|
System.out.println("LazyStorage initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LazyStorage getInstance() {
|
||||||
|
var instance = INSTANCE;
|
||||||
|
if (instance == null) {
|
||||||
|
synchronized (LazyStorage.class) {
|
||||||
|
instance = INSTANCE;
|
||||||
|
if (instance == null) {
|
||||||
|
INSTANCE = instance = new LazyStorage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized long startCalculation(long total) {
|
||||||
|
var calculation = new Calculation();
|
||||||
|
calculation.total = total;
|
||||||
|
calculation.done = 0;
|
||||||
|
calculation.value = 0;
|
||||||
|
calculations.put(currentId, calculation);
|
||||||
|
|
||||||
|
return this.currentId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void addProgress(long id, long progress) {
|
||||||
|
var calculation = calculations.get(id);
|
||||||
|
if (calculation != null) {
|
||||||
|
calculation.done += progress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void setValue(long id, double value) {
|
||||||
|
var calculation = calculations.get(id);
|
||||||
|
if (calculation != null) {
|
||||||
|
calculation.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void addToValue(long id, double value) {
|
||||||
|
var calculation = calculations.get(id);
|
||||||
|
if (calculation != null) {
|
||||||
|
calculation.value += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized double getProgress(long id) {
|
||||||
|
var calculation = calculations.get(id);
|
||||||
|
if (calculation == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (double) calculation.done / calculation.total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized double stopCalculation(long id) {
|
||||||
|
var calculation = calculations.remove(id);
|
||||||
|
if (calculation == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return calculation.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Calculation {
|
||||||
|
public double value;
|
||||||
|
public long done;
|
||||||
|
public long total;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
package ru.lionarius;
|
package ru.lionarius;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
@@ -9,25 +7,25 @@ public class Main {
|
|||||||
Function<Double, Double> function = x -> Math.sin(x) * x;
|
Function<Double, Double> function = x -> Math.sin(x) * x;
|
||||||
var lowerBound = 0.0;
|
var lowerBound = 0.0;
|
||||||
var upperBound = 1.0;
|
var upperBound = 1.0;
|
||||||
double[] accuracies = {0.0001, 0.00001, 0.0000001, 0.000000001, 0.000000001};
|
double[] accuracies = {0.0001, 0.00001, 0.0000001, 0.00000001};
|
||||||
|
|
||||||
var executor = Executors.newCachedThreadPool();
|
|
||||||
for (final var accuracy : accuracies) {
|
for (final var accuracy : accuracies) {
|
||||||
|
var n = (long) (1 / accuracy);
|
||||||
var calculator = new IntegralCalculator(
|
var calculator = new IntegralCalculator(
|
||||||
accuracy
|
accuracy,
|
||||||
|
(id) -> {
|
||||||
|
System.out.printf("[%s] Progress: %.2f%%%n", Thread.currentThread().getName(), 100 * LazyStorage.getInstance().getProgress(id));
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
var startTime = System.nanoTime();
|
var startTime = System.nanoTime();
|
||||||
|
|
||||||
double value = 0;
|
double value = 0;
|
||||||
try {
|
try {
|
||||||
value = calculator.calculate(function, lowerBound, upperBound, executor, 1);
|
value = calculator.calculate(function, lowerBound, upperBound, 4);
|
||||||
} catch (ExecutionException e) {
|
} catch (InterruptedException e) {
|
||||||
System.err.println("Error calculating integral: " + e.getMessage());
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
System.err.println("Thread interrupted: " + e.getMessage());
|
System.err.println("Thread interrupted: " + e.getMessage());
|
||||||
executor.shutdown();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var totalTime = System.nanoTime() - startTime;
|
var totalTime = System.nanoTime() - startTime;
|
||||||
@@ -39,7 +37,5 @@ public class Main {
|
|||||||
totalTime / 1_000_000.0
|
totalTime / 1_000_000.0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
executor.shutdown();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user