Java:点旋转结果不准确

时间:2011-11-11 22:59:27

标签: java math rotation point

我有以下代码......

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);
    }

当给出一个点,比如0,200时,问题就出现了。将旋转(约为轴原点0,0)调用180度应该是(0,-200)。 x坐标不应该更改。然而,它最终是(-2.4492935982947064E-14,-200)。我尝试使用strictfp但它并没有什么区别。如果旋转的坐标为零,则仅影响结果。非零值工作正常。任何想法为什么这不准确?

代码如下:

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

提供输出:

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

3 个答案:

答案 0 :(得分:3)

无论好坏,这就是浮点数学的方式。来自http://mindprod.com/jgloss/floatingpoint.html

  

“将float和double视为代表物理测量值   如果他们的橱柜制造商制作了一张桌子,那么他们会抱怨的是6.000000000001   一英尺长。类似地,不要抱怨不可避免的微小   浮点运算结果中的错误,例如数学。 COS(   Math.toRadians(90))没有出现在零上。 ( 如果你想   完美,使用int,long,BigInteger或BigDecimal。 )“

答案 1 :(得分:1)

浮点运算不完全准确。在大多数情况下,10 ^ -14功率的误差就足够了。 如果您计算Math.sin(Math.PI),您将获得1.2246467991473532E-16。为什么你需要在你的情况下准确地得到0?

答案 2 :(得分:1)

到目前为止提供的答案都是正确的,但它们缺少一个基本点。

浮点数可以采用的可能值范围不是连续的。相反,它有漏洞。所以你可以想象从0.1到0.2,而不是有无限数量的数字,只有一个有限的数字。

这就是浮点运算不准确的大部分原因。计算机无法准确代表您想要的每个实数。相反,他们只能从实际价值中获得一些小的epsilon。

例如,你不能准确地表示分数2/10。如果你打印出这个数字的所有小数位,你会发现它像0.20000000000000001。

请参阅此处以获取更全面的说明:http://floating-point-gui.de/