Java: Point rotation results are not accurate

我们两清 提交于 2019-12-25 03:58:29

问题


I have the following code...

public class Point {
    private double x;
    private double y;
    static private final double RADTODEG = 180.0d / Math.PI ;
    static private final double DEGTORAD = Math.PI / 180.0d;

    /**
     * Rotates the point by a specific number of radians about a specific origin point.
     * @param origin The origin point about which to rotate the point
     * @param degrees The number of radians to rotate the point
     */
    public void rotateByRadians(Point origin, double radians) {
        double cosVal = Math.cos(radians);
        double sinVal = Math.sin(radians);

        double ox = x - origin.x;
        double oy = y - origin.y;

        x = origin.x + ox * cosVal - oy * sinVal;
        y = origin.y + ox * sinVal + oy * cosVal;
    }

    /**
     * Rotates the point by a specific number of degrees about a specific origin point.
     * @param origin The origin point about which to rotate the point
     * @param degrees The number of degrees to rotate the point
     */
    public void rotateByDegrees(Point origin, double degrees) {
        rotateByRadians(origin, degrees * DEGTORAD);
    }

    /**
     * Rotates the point by the specified number of radians about the axis' origin (0,0). To rotate about a specific origin point, see rotateByRadians(Point, double)
     * @param radians Measure of radians to rotate the point
     */
    public void rotateByRadians(double radians) {
        if(isEmpty()) // Since we're rotating about 0,0, if the point is 0,0, don't do anything
            return;

        double cosVal = Math.cos(radians);
        double sinVal = Math.sin(radians);

        double newx = x * cosVal - y * sinVal;
        double newy = x * sinVal + y * cosVal;

        x = newx;
        y = newy;
    }

    /**
     * Rotates the point by the specified number of degrees about to the axis' origin (0,0). To rotate about a specific origin point, see rotateByDegrees(Point, double)
     * @param degrees Measure of degrees to rotate the point
     */
    public void rotateByDegrees(double degrees) {
        rotateByRadians(degrees * DEGTORAD);
    }

The problem arises when given a point, say 0,200. Calling the rotation (about axis origin 0,0) for 180 degrees it should be (0, -200). The x coordinate shouldn't have changed. However, it ends up being (-2.4492935982947064E-14, -200). I tried using strictfp but it doesn't make a difference. This only affects the result if the coordinate being rotated is zero. Nonzero values work fine. Any ideas why this is not accurate?

The code is below:

   Point p = new Point(0.0d, 200.0d);
   p.rotateByDegrees(180.0d);
   System.out.println(p);

Gives output:

shapelib.Point Object {x: -2.4492935982947064E-14 y: -200.0}

回答1:


Float arithmetic is not fully accurate. Error of 10^-14 power is enough in most cases. If you calculate Math.sin(Math.PI) you'll get 1.2246467991473532E-16. Why do you need to get precisely 0 in your case?




回答2:


For better or for worse, that's just the way it is with floating point math. From http://mindprod.com/jgloss/floatingpoint.html:

"Think of float and double as representing physical measurements. No one would complain if their cabinet maker made a desk 6.000000000001 feet long. Analogously, don’t complain about the inevitable tiny errors in floating point arithmetic results e.g. Math. cos( Math.toRadians( 90 ) ) not coming out bang on zero. ( If you want perfection, use int, long, BigInteger or BigDecimal. )"




回答3:


Both the provided answers so far are correct, but they're missing a fundamental point.

The range of possible values a floating point number can take on is not continuous. Rather, it has holes in it. So you can imagine that from 0.1 to 0.2, instead of there being an infinite amount of numbers, there are only a finite number.

That's most of the reason why floating point arithmetic is inaccurate. Computers can't exactly represent every real number you'd like. Instead, they can get to only some small epsilon away from the actual value.

As an example, you can't exactly represent the fraction 2 / 10. If you print out all the decimal places to this number, you'll find it something like 0.20000000000000001.

See here for a more thorough writeup: http://floating-point-gui.de/



来源:https://stackoverflow.com/questions/8100986/java-point-rotation-results-are-not-accurate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!