Bradley Cutshall
Bradley Cutshall

Reputation: 23

Get average direction of degrees of the set between 360 and 1

I am trying to take a set of angles from 0 to 359 and get the average direction of the angles. I have searched everywhere and some of the examples work but for some reason my code isn't working.

For example the average of the set of {355,355,15,15} should be 5 degrees but they I get a bunch of varying answers that don't make much sense.

I'm using this equation courtesy of wiki: https://en.wikipedia.org/wiki/Mean_of_circular_quantities

public static void main(String[] args) {

    //ATAN2(sum_of_sin(theta), sum_of_cos(theta))

    double[] numbers = {355,355,15,15};
    double sin=0.0, cos=0.0, theta=0.0;

    for(double d : numbers) {
        sin += Math.sin(d);
        cos += Math.cos(d);
    }

    sin = sin / ((double)numbers.length);
    cos = cos / ((double)numbers.length);

    // Using only atan2
    System.out.println("Atan2 Only: " + Math.toDegrees(Math.atan2(sin, cos)));
    // Atan2 Only: 159.71920992022936

    // Using the wiki solution
    if (sin > 0 && cos > 0) {
        theta = Math.atan(sin/cos);
    } else if(cos < 0) {
        theta = Math.atan(sin/cos) + 180;
    } else if(sin < 0 && cos > 0) {
        theta = Math.atan(sin/cos) + 360;
    }
    System.out.println("Wiki Answer: " + theta);
    // Wiki Answer: 179.6460334382022
}

Upvotes: 2

Views: 1061

Answers (3)

Nadesri
Nadesri

Reputation: 41

NOTE: There are considerable flaws to this approach; leaving this answer here so that others understand these flaws. Please see comments between @LutzL and me (@Nadesri) for details.

Perhaps I am missing something... I think you should be able to add all the numbers, take the sum modulo 360 (assuming degrees), and then divide by n

private double avgOfAngles(List<int> numbers) {
    int n = numbers.size();
    int sum = 0;
    for (int i=0; i<numbers; i++) {
        sum += numbers.get(i);
    }
    return (double) (sum % 360) / n;
}

Of course, the above assumes that acceptable answers range between 0 to 359, inclusive; if you prefer a different range (such as -180 to 179), then the above solution would need to be offset by the appropriate amount.

The wiki notes [0, 360] as a possibly counterintuitive example (since the arithmetic mean is 180 despite that 360 degrees is for most purposes the same thing as 0 degrees); I think the above solution still handles at least this example.

Upvotes: 0

rainkinz
rainkinz

Reputation: 10394

You need to convert from degrees to radians for the input to sin and cos then back again for the result:

    double[] numbers = {355, 5, 15 };
    double sin=0.0, cos=0.0, theta=0.0;

    for(double d : numbers) {
        double s = Math.sin(Math.toRadians(d));
        sin += s;

        double c = Math.cos(Math.toRadians(d));
        cos += c;
    }

    sin = sin / ((double)numbers.length);
    cos = cos / ((double)numbers.length);

    // Using only atan2
    System.out.println("Atan2 Only: " + Math.toDegrees(Math.atan2(sin, cos)));
    // Atan2 Only: 159.71920992022936

    // Using the wiki solution
    if (sin > 0 && cos > 0) {
        theta = Math.atan(sin/cos);
    } else if(cos < 0) {
        theta = Math.atan(sin/cos) + 180;
    } else if(sin < 0 && cos > 0) {
        theta = Math.atan(sin/cos) + 360;
    }
    System.out.println("Wiki Answer: " + theta);
    System.out.println("Wiki Answer in degrees: " + Math.toDegrees(theta));

output:

Atan2 Only: 4.9999999999999964
Wiki Answer: 0.08726646259971642
Wiki Answer in degrees: 4.9999999999999964

Upvotes: 1

templatetypedef
templatetypedef

Reputation: 372814

The math methods in Java assume that you're working in radians, not degrees. Try converting all your values to radians by multiplying them by π / 180 and see if that fixes things.

Upvotes: 1

Related Questions