2011-11-11 21 views
0

我有以下代码...的Java:点旋转的结果是不准确的

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。调用180度旋转(绕轴原点0,0)应该是(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} 

回答

1

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

+0

这似乎是准确的所有值工作,除了为零,在这种情况下,它可以超过2.0了。 –

+0

啊,它不是-2,它是-2.4E-14(-2 x 10^-14)off – kylewm

+0

@WilliamtheCoderer,我希望你不要用p1.x == p2.x和p1.y = = p2.y?在其他情况下,为什么它很重要? 0.00000000000002对于大多数情况来说确实很小。 –

3

是好还是坏,这只是它与浮点运算的方式。从http://mindprod.com/jgloss/floatingpoint.html

“想想浮动和双为代表的物理测量,如果他们的橱柜制造商提出6.000000000001 英尺长的桌子没有 人会抱怨类似的,不要抱怨在所难免微小 错误。浮点运算结果,如数学,COS( Math.toRadians(90))不出来一声就为零。(如果你想 完美,使用的int,long的BigInteger或BigDecimal的。)”

1

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

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

这就是浮点运算不准确的原因。电脑不能准确地代表你想要的每一个真实数字。相反,他们只能从实际价值中得到一小部分。

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

在这里看到一个更彻底的新手必看:http://floating-point-gui.de/