This commit is contained in:
Jagath Kumar 2024-03-12 12:55:38 +05:30
parent 24c370707c
commit 364a23f10d
8 changed files with 218 additions and 0 deletions

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>core-java-calculating-moving-averages</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<artifactId>core-java-modules</artifactId>
<groupId>com.baeldung.core-java-modules</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,26 @@
package com.baeldung;
public class ExponentialMovingAverage {
private final double alpha;
private Double previousEMA;
public ExponentialMovingAverage(double alpha) {
if (alpha <= 0 || alpha > 1) {
throw new IllegalArgumentException("Alpha must be in the range (0, 1]");
}
this.alpha = alpha;
this.previousEMA = null;
}
public double calculateEMA(double newValue) {
if (previousEMA == null) {
// First data point, EMA is same as the value itself
previousEMA = newValue;
} else {
// Calculate EMA using the formula: EMA = alpha * newValue + (1 - alpha) * previousEMA
previousEMA = alpha * newValue + (1 - alpha) * previousEMA;
}
return previousEMA;
}
}

View File

@ -0,0 +1,31 @@
package com.baeldung;
public class MovingAverageByCircularBuffer {
private final double[] buffer;
private int head;
private int count;
public MovingAverageByCircularBuffer(int windowSize) {
this.buffer = new double[windowSize];
}
public void add(double value) {
buffer[head] = value;
head = (head + 1) % buffer.length;
if (count < buffer.length) {
count++;
}
}
public double getMovingAverage() {
if (count == 0) {
return Double.NaN;
}
double sum = 0;
for (int i = 0; i < count; i++) {
sum += buffer[i]; //buffer[(head + i) % buffer.length];
}
return sum / count;
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
public class MovingAverageWithApacheCommonsMath {
private final DescriptiveStatistics stats;
public MovingAverageWithApacheCommonsMath(int windowSize) {
this.stats = new DescriptiveStatistics(windowSize);
}
public void add(double value) {
stats.addValue(value);
}
public double getMovingAverage() {
return stats.getMean();
}
}

View File

@ -0,0 +1,38 @@
package com.baeldung;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class ExponentialMovingAverageTest {
@Test(expected = IllegalArgumentException.class)
public void when_alpha_is_invalid_should_throw_exception() {
new ExponentialMovingAverage(0); // Alpha outside valid range
}
@Test
public void when_first_value_is_added_EMA_should_be_same_as_value() {
ExponentialMovingAverage ema = new ExponentialMovingAverage(0.5);
assertEquals(10.0, ema.calculateEMA(10.0), 0.001);
}
@Test
public void when_values_are_added_EMA_should_update_correctly() {
ExponentialMovingAverage ema = new ExponentialMovingAverage(0.4);
assertEquals(10.0, ema.calculateEMA(10.0), 0.001);
assertEquals(14.0, ema.calculateEMA(20.0), 0.001);
assertEquals(20.4, ema.calculateEMA(30.0), 0.001);
}
@Test
public void when_alpha_is_closer_to_one_EMA_should_respond_faster_to_changes() {
ExponentialMovingAverage ema1 = new ExponentialMovingAverage(0.2);
ExponentialMovingAverage ema2 = new ExponentialMovingAverage(0.8);
assertEquals(10.0, ema1.calculateEMA(10.0), 0.001);
assertEquals(10.0, ema2.calculateEMA(10.0), 0.001);
assertEquals(12.0, ema1.calculateEMA(20.0), 0.001); // Responds slower
assertEquals(18.0, ema2.calculateEMA(20.0), 0.001); // Responds faster
}
}

View File

@ -0,0 +1,35 @@
package com.baeldung;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MovingAverageByCircularBufferTest {
@Test
public void when_initial_average_is_calculated_it_should_be_zero() {
MovingAverageByCircularBuffer ma = new MovingAverageByCircularBuffer(5);
assertEquals(Double.NaN, ma.getMovingAverage(), 0.001); // Empty buffer
}
@Test
public void when_values_are_added_average_should_update_correctly() {
MovingAverageByCircularBuffer ma = new MovingAverageByCircularBuffer(3);
ma.add(10);
assertEquals(10.0, ma.getMovingAverage(), 0.001);
ma.add(20);
assertEquals(15.0, ma.getMovingAverage(), 0.001);
ma.add(30);
assertEquals(20.0, ma.getMovingAverage(), 0.001);
}
@Test
public void when_window_size_is_full_oldest_value_should_be_overwritten() {
MovingAverageByCircularBuffer ma = new MovingAverageByCircularBuffer(2);
ma.add(10);
ma.add(20);
assertEquals(15.0, ma.getMovingAverage(), 0.001);
ma.add(30); // Overwrites 10
assertEquals(25.0, ma.getMovingAverage(), 0.001);
}
}

View File

@ -0,0 +1,36 @@
package com.baeldung;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MovingAverageWithApacheCommonsMathTest {
@Test
public void when_initial_average_is_calculated_it_should_be_NAN() {
MovingAverageWithApacheCommonsMath movingAverageCalculator = new MovingAverageWithApacheCommonsMath(5);
assertEquals(Double.NaN, movingAverageCalculator.getMovingAverage(), 0.001);
}
@Test
public void when_values_are_added_average_should_update_correctly() {
MovingAverageWithApacheCommonsMath movingAverageCalculator = new MovingAverageWithApacheCommonsMath(3);
movingAverageCalculator.add(10);
assertEquals(10.0, movingAverageCalculator.getMovingAverage(), 0.001);
movingAverageCalculator.add(20);
assertEquals(15.0, movingAverageCalculator.getMovingAverage(), 0.001);
movingAverageCalculator.add(30);
assertEquals(20.0, movingAverageCalculator.getMovingAverage(), 0.001);
}
@Test
public void when_window_size_is_full_oldest_value_should_be_dropped() {
MovingAverageWithApacheCommonsMath ma = new MovingAverageWithApacheCommonsMath(2);
ma.add(10);
ma.add(20);
assertEquals(15.0, ma.getMovingAverage(), 0.001);
ma.add(30);
assertEquals(25.0, ma.getMovingAverage(), 0.001); // 10 dropped, 20 and 30 remain
}
}

View File

@ -224,6 +224,7 @@
<module>java-rmi</module>
<module>java-spi</module>
<module>java-websocket</module>
<module>core-java-calculating-moving-averages</module>
</modules>
<dependencies>