I need help figuring out the following problem :
Create a class Statistics.java to implement the StatisticsI.java. Statistics.java contains ArrayList data to store to data objects of Double type, and properties (attributes): count, min, max, mean, std. The implementation has the following specifications.
addData(Double d) adds data d into the array list, and then update the values of count, min, max, mean, and std, using incremental algorithms, i.e. using exiting existing value to calculate new values, rather than calculating by traversal through the data array.
getCount() returns count.
getMin() returns min.
getMax() returns max.
getMean() returns mean.
getSTD() returns std.
stats() computes the count, min, max, mean, and stddev from the data array in one loop, and then sets the values of the properties.
I have the interface
public interface StatisticsI {
void addData(double d);
int getCount();
double getMin();
double getMax();
double getMean();
double getSTD();
void stats();
}
Here is the code I have so far for the implementation part.
import java.util.ArrayList;
public class Statistics implements StatisticsI {
private ArrayList<Double> data;
private long count;
private double min;
private double max;
private double mean;
private double std;
public Statistics() {
data = new ArrayList<Double>();
count = 0;
min = 0;
max = 0;
mean = 0;
std = 0;
}
public void addData(double d) {
data.add(d);
count += 1;
data.set(data.indexOf(min), min);
data.set(data.indexOf(max), max);
data.set(data.indexOf(mean), mean);
data.set(data.indexOf(std), std);
}
public int getCount() {
count = data.size();
return (int) count;
}
public double getMin() {
return min;
}
public double getMax() {
return max;
}
public double getMean() {
int mean = 0;
for (int i = 0; i < data.size(); i++) {
double currentNum = data.get(i);
mean += currentNum;
}
return mean / data.size();
}
public double getSTD() {
{
double avg = getMean();
double t = 0;
for (int i = 0; i < data.size(); i++) {
double numbers = data.get(i);
double value = Math.pow(numbers - avg, 2);
t += value;
}
double std = (double) t / (double) (data.size());
return Math.sqrt(std);
}
}
public void stats() {
count = data.size();
}
}
I am having trouble with the addData and stats methods and I am not sure if I am doing this correctly and I am trying to figure out how to implement it.
My question is how to implement the interface with what is required in the methods.
Update: How do I call the methods from Statistics
Here is the code for the main class
public static void main(String[] args) {
ArrayList<Double> numList = new ArrayList<Double>();
StatisticsI stats = new Statistics();
Random r = new Random();
for(int i = 1; i <= 10; i++) {
numList.add((double) r.nextInt(10000));
}
double count = stats.getCount();
double min = stats.getMin();
double max = stats.getMax();
double mean = stats.getMean();
double std = stats.getSTD();
System.out.println("The count for the list is:"+ count);
System.out.println("The min for the list is:" + min);
System.out.println("The max for the list is:" + max);
System.out.println("The mean for the list is:" + mean);
System.out.println("The standard deviation for the list is:" + std);
}
}
The problem is I don't get any values for my output, I get :
The count for the list is:0.0
The min for the list is:Infinity
The max for the list is:-Infinity
The mean for the list is:0.0
The standard deviation for the list is:NaN
How do I get my output to work?
in addData(..), use "min = Math.min(min, d)". Math.max also exists, but std and mean are trickier. It's probably easiest to calculate those in the getters by iterating the list.
You can update min, max, mean values immediately in addData.
Update It is also possible to use Welford's algorithm to calculate running deviation.
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;
double variance = 0.0;
public void addData(double d) {
data.add(d);
count++;
if (d < min) {
min = d;
} else if (d > max) {
max = d;
}
// fixed calculation of running mean and variance by Welford's algorithm
double new_mean = mean + (d - mean) / count;
variance += count < 2 ? 0.0 : (d - mean) * (d - new_mean);
mean = new_mean;
std = count > 1 ? Math.sqrt(variance / (count - 1)) : 0;
}
Or, you can reset all these values in stats() method using the data list.
There is a convenient way to calculate all stats at once via DoubleSummaryStatistics and Java 8 Stream API:
public void stats() {
DoubleSummaryStatistics stats = data.stream().collect(Collectors.summarizingDouble(x -> x));
count = stats.getCount(); // long value returned instead of `int data.size()`
min = stats.getMin();
max = stats.getMax();
mean = stats.getAverage();
std = this.getSTD();
}
public double getSTD() {
double avg = getMean();
double t = 0.0;
for (double d : data) {
t += Math.pow(avg - d, 2);
}
return Math.sqrt(t / getCount());
}
Loop-based "streamless" calculation of stats including "naive" variance calculation algorithm for std could be as follows:
public void stats() {
count = data.size();
min = Double.POSITIVE_INFINITY;
max = Double.NEGATIVE_INFINITY;
mean = 0.0;
variance = 0.0;
double sum = 0.0;
double sq = 0.0;
int i = 0;
for (double d : data) {
min = Math.min(min, d);
max = Math.max(min, d);
i++;
// calculate running mean as above to use in variance
double new_mean = mean + (d - mean) / i;
variance += i < 2 ? 0 : (d - mean) * (d - new_mean);
mean = new_mean;
sum += d;
sq += d * d;
}
System.out.println("running mean=" + mean);
std = count > 1 ? Math.sqrt((sq - mean * mean / count) / (count - 1)) : 0;
mean = count == 0 ? 0 : sum / count;
}
// override STD getter to remove all calculations
public double getSTD() {
return std;
}
Test
Statistics stats = new Statistics();
stats.addData(17);
stats.addData(19);
stats.addData(24);
System.out.println("after addData()");
System.out.println("mean=" + stats.getMean());
System.out.println("std=" + stats.getSTD());
System.out.println("after addData()");
stats.stats();
System.out.println("mean=" + stats.getMean());
System.out.println("std=" + stats.getSTD());
Output
after addData()
mean=20.0
std=3.605551275463989
after stats()
running mean=20.0
mean=20.0
std=3.605551275463989
Related
Here is the code, I keep not getting the correct output from the getMax method.
I fill an array with the sum of the int values of an ArrayList, then check which one of them is the smallest and the biggest, finally outputting them and pruning away the decimal places, which might cause errors maybe?
Code might be bad, I'm a noob:
public static void miniMaxSum(ArrayList<Integer> arr) {
double[] acc = new double[arr.size()];
for (int i=0; i<arr.size(); i++){
for (int j=0; j<arr.size(); j++){
acc[i] += arr.get(j);
}
acc[i] -= arr.get(i);
}
//double min = acc[arr.size()-1];
//double max = acc[0];
System.out.printf("%.0f", getMin(acc));
System.out.print(" ");
System.out.printf("%.0f", getMax(acc));
}
public static double getMin(double[] acc){
double min = 0;
for (int j=0; j<acc.length; j++){
for (int i=0; i<acc.length; i++){
if (acc[i] > acc[j]){
min = acc[j];
} else {
min = acc[i];
}
}
}
return min;
}
public static double getMax(double[] acc){
double max = 0;
for (int j=0; j<acc.length; j++){
for (int i=0; i<acc.length; i++){
if (acc[i] > acc[j]){
max = acc[i];
System.out.println(max);
}
else {
max = acc[j];
}
}
}
return max;
}
Method to do the checks yourself
public static double findMax(double[] data) {
double max = Double.MIN_VALUE;
for (double val : data) {
if (val > max) {
max = val;
}
}
return max;
}
Using the Math utility
public static double findMax2(double[] data) {
double max = Double.MIN_VALUE;
for (double val : data) {
max = Math.max(val, max);
}
return max;
}
Using streams
public static double findMax3(double[] data) {
return Arrays.stream(data).max().getAsDouble();
}
Doing your own checks
public static double findMin(double[] data) {
double min = Double.MAX_VALUE;
for (double val : data) {
if (val < min) {
min = val;
}
}
return min;
}
Using Math utility
public static double findMin2(double[] data) {
double min = Double.MAX_VALUE;
for (double val : data) {
min = Math.min(val, min);
}
return min;
}
Using streams
public static double findMin3(double[] data) {
return Arrays.stream(data).min().getAsDouble();
}
You can do everything you want do do in a single loop. First calculate the sum for each value and then check for that sum if it is a new maximum and/ or minimum value. If any of these option is true, update the respective maximum or minimum value.
import java.util.*;
public class Application {
public static void main(String[] args) {
var test = new double[]{10d, 4.43d, 5.3d, -6.8d, 7.1d, 8.7d, 8.1d, 234d, -3.9d, -455.3d};
minMaxSum(test);
}
public static void minMaxSum(double[] arr) {
double acc = 0;
// initialize the minimal value with the maximal value
double min = Double.MAX_VALUE;
// initialize the biggest value with the smallest possible value
double max = Double.MIN_VALUE;
var sum = new double[arr.length];
// a single for loop
for (int i = 0; i < arr.length; i++) {
var cur = arr[i];
// sum up adding the current value
acc += cur;
// save the current value in new array so we can verify the result (not actually required for the algorithm)
sum[i] = acc;
// if something is smaller than what we've already encountered => set new smallest value
if(acc < min) min = acc;
// if something is bigger than what we've already encountered => set new biggest value
if(acc < max) max = acc;
}
System.out.printf("""
Original: %s
Prefix-sum: %s
Min: %s
Max: %s
""", Arrays.toString(arr), Arrays.toString(sum), min, max);
}
}
Expected output:
Original: [10.0, 4.43, 5.3, -6.8, 7.1, 8.7, 8.1, 234.0, -3.9, -455.3]
Prefix-sum: [10.0, 14.43, 19.73, 12.93, 20.03, 28.73, 36.83, 270.83, 266.93, -188.37]
Min: -188.37
Max: 270.83
As many people recommended sorting as a viable approach, here some remarks on sorting. First, yes, it would give you a correct result but there is a price to pay which is speed and well it is just an unnecessarily complex solution.
Sorting based on comparisons and without any pre-conditions cannot be done faster than in O(n log n). It is obvious that the solution above needs O(n) time thus is a complexity class faster. Also the constants (which are ignored in big-O notation) are quite small in the above solution, so even if some pre-conditions were met and you could use a special sorting algorithm like Map sort (or alike) which run in O(n) (again: under certain conditions) the above solution would still be faster and, not to mention, much simpler. So don't make your life harder than it needs to be.
You do not need to use nested loops for getMax or getMin functions.
public static double getMax(double[] acc){
double max = Double.MIN_VALUE;
for (double value : acc) {
if( value > max) max = value;
}
return max;
}
if you want to sort the list anyway:
public static void miniMaxSum(ArrayList<Integer> arr) {
if(arr.size() > 0) {
Collections.sort(arr);
System.out.println(arr.get(0));
System.out.println(arr.get(arr.size() - 1));
}
}
I am trying to use java to pass an array to get the mean, median,mode , max an min in java. I am currently having an issue passing the array to a function and return its value so i can output the results. I believe i have the loops correct to solve the mean median and mode but i cannot get them to send and receive as wanted. How can I pass the array and send back the values needed?
UPDATE: i have updated the code it will compile and i can input the number of years but i get several errors following after that. it is also not printing the outputs
Exception in thread "main" java.util.UnknownFormatConversionException: Conversion = 'i'
at java.util.Formatter$FormatSpecifier.conversion(Formatter.java:2646)
at java.util.Formatter$FormatSpecifier.(Formatter.java:2675)
at java.util.Formatter.parse(Formatter.java:2528)
at java.util.Formatter.format(Formatter.java:2469)
at java.io.PrintStream.format(PrintStream.java:970)
at java.io.PrintStream.printf(PrintStream.java:871)
at la5cs1110_woodspl_03.pkg17.pkg2016.La5cs1110_WoodsPl_03172016.main(La5cs1110_WoodsPl_03172016.java:56)
Java Result: 1
public static void main(String[] args) {
int i;
List<Double> hArray = new ArrayList<>();
int nYears = 0, y = 0;
double rMax = 0.00,rMin = 100.00;
//get input check if between 1-80
while(y == 0){
String userData = JOptionPane.showInputDialog
("Enter number of years");
nYears = Integer.parseInt(userData);
if (nYears > 1 && nYears <= 80 )
y = 1;
}
y = 0;
while(y <= nYears){
for(i = 0; i < 12; i++){
Random rand = new Random();
double rNum = rand.nextFloat() * (rMax - rMin) + rMin;
hArray.add(rNum);
}
double mean = getMean (hArray);
double median = getMedian (hArray);
double mode = getMode (hArray);
double max = getMaxValue(hArray);
double min = getMinValue (hArray);
System.out.printf("In year %i the Mean = %d , mode = %d, median = %d," +
" max = %d, min = %d", y , mean, median, mode, max, min);
y++;
}
}
private static double getMean(List<Double> hArray) {
double sum = 0;
for (int i = 0; i < hArray.size(); i++) {
sum += hArray.get(i);
}
return sum / hArray.size();
}
//Median
private static double getMedian(List<Double> hArray) {
int middle = hArray.size()/2;
if (hArray.size() %2 == 1) {
return hArray.get(middle);
} else {
return (hArray.get(middle-1) + hArray.get(middle)) / 2.0;
}
}
//Mode
public static double getMode(List<Double> hArray) {
double maxValue = 0, maxCount = 0;
for (int i = 0; i < hArray.size(); ++i) {
int count = 0;
for (int j = 0; j < hArray.size(); ++j) {
if (hArray.get(j) == hArray.get(i)) ++count;
}
if (count > maxCount) {
maxCount = count;
maxValue = hArray.get(i);
}
}
return maxValue;
}
public static double getMaxValue(List<Double> hArray){
double maxValue = hArray.get(0);
for(int i=1;i < hArray.size();i++){
if(hArray.get(i) > maxValue){
maxValue = hArray.get(i);
}
}
return maxValue;
}
public static double getMinValue(List<Double> hArray){
double minValue = hArray.get(0);
for(int i=1;i<hArray.size();i++){
if(hArray.get(i) < minValue){
minValue = hArray.get(i);
}
}
return minValue;
}
}
Your hArray is a List. You should convert it to an array first.
getMean(hArray.toArray)
Check out this.
This does not compile, you try to pass a Double to a method, which expects a double[]. So you have to change the parameter of your methods and use a List and just pass in the hArray (see Tibrogargan answer - i.e., you would have to modify each of your implementations) or do the following:
create a Double[]
Double[] hArray2 = hArray.toArray(new Double[hArray.size()]);
change your methods' signature, so that they expect an Double[]
private static double getMean(Double[] hArray) { ...}
pass hArray2 instead of hArray
double mean = getMean(hArray2);
// ...
That should be it.
Replace the section where you're trying to pass a single element from the array to your statistics functions with calls using the whole array and change the signature of the calls so they take a List<Double> param, not a double[]. Something like this:
double mean = getMean (hArray);
double median = getMedian (hArray);
double mode = getMode (hArray);
double max = getMaxValue(hArray);
double min = getMinValue (hArray);
//Mean
private static double getMean(List<Double> hArray) {
double sum = 0;
for (int i = 0; i < hArray.size(); i++) {
sum += hArray.get(i);
}
return sum / hArray.size();
}
See also: How do you calculate the variance, median, and standard deviation in C++ or Java?
Fix for median:
Copied directly from this above link with some minor modifications to use a List as a param
public Double median(List<Double> list)
{
Double[] array = list.toArray(new Double[list.size()]);
Arrays.sort(data);
if (data.length % 2 == 0)
{
return (data[(data.length / 2) - 1] + data[data.length / 2]) / 2.0;
}
else
{
return data[data.length / 2];
}
}
Fix for mode:
public Double mode(List<Double> list)
{
java.util.TreeMap<Double,Integer> map = new java.util.TreeMap<>();
Double maxVal = null;
int maxCount = 0;
for (Double d : list) {
int count = 0;
if (map.containsKey(d)) {
count = map.get(d) + 1;
} else {
count = 1;
}
map.put(d, count);
if (count > maxCount) {
maxVal = d;
maxCount = count;
}
}
return maxVal;
}
I've created two different methods that calculate random monthly savings, and the monthly interest on those savings and saves each to its own array. I would like to have a new method that returns the last element in the calculateInterest array (as its the cumulative total of savings and interest in a year), so i can use that specific number in a different part of my program later.
So her is what i have so far. My methods for calculating savings and interest work just fine but i don't know how to actually get the value and not just the array number (which is all I've been able to call) in my last method.
Any help or direction would be greatly appreciated!
public class EmployeeSavings extends AddressBook {
private double accountValue;
private double[] monthlyInterests = new double [12];
private double[] monthlySavings = new double[12];
private static final double MONTHLY_RATE= 0.00417;
public double[] generateMonthlySavings() {
double min = 100;
double max = 800;
double range = (max - min);
for (int i = 0; i < monthlySavings.length; i++) {
monthlySavings[i] = (Math.random() * range) + min;
System.out.println(monthlySavings[i]);
}
return monthlySavings;
}
public double[] calculateInterest() {
double count = 0;
for (int i = 0; i < monthlyInterests.length; i++) {
if (i <= monthlyInterests.length)
count = (monthlySavings[i] + count) * (1 + MONTHLY_RATE);
System.out.println(count);
}
return monthlyInterests;
}
public double[] getMonthlyInterest(){
return monthlyInterests;
}
public double[] getMonthlySavings() {
return monthlySavings;
}
// Would like to return total value here
public double getAccountValue() {
for (int i = 12; i <= getMonthlyInterest().length; i++) {
accountValue = i;
}
return accountValue;
}
If your java version is 8 I would do it like so
public double getAccountValue() {
return DoubleStream.of( getMonthlyInterest() ).sum();
}
It's much shorter and I think it's also more readable. But if your java version isn't 8 do something like this
double[] d = getMonthlyInterest();
double value = 0d;
for (int i = 0; i < d.length; i++) {
value += d[i]; // d[i] returns value which has i index in array d.
}
I am expecting 3.5 as result from average method, but I get 3.0. No idea why. I expected Double to give me the result, but no.
java.util.ArrayList;
public class Hangman {
public static void main(String[] args) {
ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(3);
intList.add(2);
intList.add(7);
intList.add(2);
System.out.println("The variance number is : ");
System.out.println(sum(intList));
System.out.println(intList.size());
System.out.println(average(intList));
}
public static int sum(ArrayList<Integer> intList) {
int sum = 0;
for (int counter = 0; counter < intList.size(); counter++) {
sum = sum + intList.get(counter);
}
return sum;
}
public static double average(ArrayList<Integer> intList) {
double avg = sum(intList) / (intList.size());
return avg;
}
public static ArrayList<Double> subtract(ArrayList<Integer> intList) {
ArrayList<Double> subtracted = new ArrayList<Double>();
for (double subtract : intList) {
subtracted.add((double) (subtract - average(intList)));
}
return subtracted;
}
public static double variance(ArrayList<Integer> intList) {
double sumDiffsSquared = 0.0;
double avg = average(intList);
for (int value : intList) {
double diff = value - avg;
diff *= diff;
sumDiffsSquared += diff;
}
return (sumDiffsSquared / (intList.size() - 1));
}
}
sum needs to return a double, otherwise when you do a
sum(intList) / (intList.size());
in your average method, it truncates the value calculated down to an integer, and then puts that value in double form.
Your function needs to return a double value.
Change your method to
public static double sum(ArrayList<Integer> intList) {
double sum = 0;
for (int counter = 0; counter < intList.size(); counter++) {
sum = sum + intList.get(counter);
}
return sum;
}
and you should be doing fine.
Though the type of avg is double , sum() method is returning a Integer value. So you have return a double from sum() method
double avg = (double)sum(intList) / (intList.size());
I'm having trouble trying to find the sum of this series non-recursively
So far I have:
public static double sum_nr(int n) {
int result = 0;
for (int i = 1; i<=n; i++)
{
result=result+1/(i+1);
}
return result;
}
public static void main(String[] args){
int n= 4;
System.out.println("Calculation for sum_nr(n) " + n + " is "+ sum_nr(n));
}
I keep getting 0.0 as the sum.
What am I doing wrong?
I think it's due to not using the right type. You're doing integer division rather than using a float type.
public static double sum_nr(int n) {
double result = 0;
for (double i = 0; i < n; i++)
{
result=result+1.0/(i+1);
}
return result;
}
Integer division will lead to 0 results. you should use float/double instead of int for variable result.
result=result+1/(i+1); will always give 0 as i is an integer. Assign i value to a float and use that
float result = 0f; // declare result as float too or double for (int
i = 1; i<=n; i++)
{ float val = i;
result=result+1/(float+1);
}
Same as everyone else says but their answers aren't complete.
public static double sum_nr(int n) {
float result = 0;
for (int i = 1; i<=n; i++){
result=result+1/((float)i+1);
}
return result;
}
result needs to be a float, or double, but you also need to cast i as a float, or double, as well. No need to create a new variable
The series you are referring to is the harmonic series. There's a closed form approximation for this.
H(n) = ln(n) + gamma + 1/(2n) - 1/(12n^2)
where gamma is the Euler-Mascheroni constant. See here.
In Java, here's some code to both compute correctly and show the difference of the approximation to the actual as n grows. It will become asymptotically smaller:
constant double EULER_MASCHERONI = 0.57721566490153286060651209008240243104215933593992;
public static double approximateHarmonicSummation(int n) {
return Math.log(n) + EULER_MASCHERONI + 0.5 * n - 1.0 / (12.0 * Math.pow(n, 2));
}
public static double sum_nr(int n) {
double result = 0;
for (double i = 0; i < n; i++) {
result += 1.0 / (i + 1);
}
return result;
}
public static void main(String[] args) {
double approx = 0.0;
double actual = 0.0;
for (int n = 0; n < 1000; n++) {
approx = approximateHarmonicSummation(n);
actual = sum_nr(n);
System.out.println("Calculation for approximation of sum_nr(n) " + n + " is "+ approx);
System.out.println("Calculation of sum_nr(n) " + n + " is "+ actual);
System.out.printlin("Difference = " + (actual - approx) + "\n");
}
}
Hopefully that helps.