简体   繁体   中英

Floating-point precision when dealing with trigonometric functions

I have a Java class that deals with a lot of trigonometric functions using java.lang.Math . The following code determines the average direction of 0 degrees and 180 degrees. The result should be NaN, since 0 degrees and 180 degrees are in opposite directions, canceling each other out. However, when I do:

double[] angles = {0, 180};
double sines = 0;
double cosines = 0;
double avg;
for (int i = 0; i < angles.length; i++) {
    double rad = Math.toRadians(angles[i]);
    sines += Math.sin(rad);
    cosines += Math.cos(rad);
}
double sin = sines / angles.length;
double cos = cosines / angles.length;
System.out.println("Avg sin: " + sin + "\nAvg cos: " + cos); // sin != 0 but it should
double avgRad = Math.atan2(sin, cos);
avg = Math.toDegrees(avgRad);
System.out.println("Average: " + avg);

avg equals 90.0 instead of NaN . This is because the average sine of 180 degrees and 0 degrees results in a very small but positive number (due to the way floating-point precision works). If you run the above code you will see what I mean. How can I avoid this lack of precision? I know that I could round the average sines and cosines as well as the final result, but that seems a little inelegant to me.

I take it granted that you must have considered averaging angles directly (by using mod 360) before you went onto use sin/cos/tan. That being said, I think, you are in right direction in getting what you intended in your code (except possibly the negative sign flip in the last example).

~> java Main 0 180
Avg sin: 6.123233995736766E-17
Avg cos: 0.0
Average: 90.0

~> java Main 0 179
Avg sin: 0.00872620321864172
Avg cos: 7.615242180436521E-5
Average: 89.50000000000011

~> java Main 1 179
Avg sin: 0.017452406437283477
Avg cos: 0.0
Average: 90.0

~> java Main 1 180
Avg sin: 0.008726203218641817
Avg cos: -7.615242180436521E-5
Average: 90.49999999999991

~> java Main 1 181
Avg sin: 1.5959455978986625E-16
Avg cos: 0.0
Average: 90.0

~> java Main 1 182
Avg sin: -0.008723545132608694
Avg cos: 2.2843406864775373E-4
Average: -88.50000000000001

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM