相同的计算如何产生不同的结果 [英] How can same calculation produce different results

查看:93
本文介绍了相同的计算如何产生不同的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

仅花两个小时进行调试,我想我知道问题的原因,但我不知道它如何产生结果.

Just spend two hours debugging this, I think I know the cause of the problem but I don't understand how can it produce the kind of results it does.

我有一个基于Swing的应用程序,其中我像这样覆盖了JPanel.paint(Graphics g)

I've got a Swing based application where I override JPanel.paint(Graphics g) like this

public void paint(Graphics g) {
    <snipped code>

    Insets is = getInsets();
    Dimension sz = getSize();
    g2.setClip(is.left + 1, is.top + 1, sz.width - is.right - is.left - 2, sz.height - is.top - is.bottom - 2);

    int w = getWidth();
    int h = getHeight();
    double s = Math.min(sz.getWidth(), sz.getHeight());

    AffineTransform mc = g2.getTransform();

    AffineTransform m1 = new AffineTransform(mc);
    m1.preConcatenate(AffineTransform.getTranslateInstance(-m_CenterX, -m_CenterY));
    m1.preConcatenate(AffineTransform.getScaleInstance(m_ScaleX * s, -m_ScaleY * s));
    m1.preConcatenate(AffineTransform.getTranslateInstance(w / 2, h / 2));

    AffineTransform m2 = new AffineTransform(mc);
    m2.preConcatenate(AffineTransform.getTranslateInstance(-m_CenterX, -m_CenterY));
    m2.preConcatenate(AffineTransform.getScaleInstance(m_ScaleX * s, -m_ScaleY * s));
    m2.preConcatenate(AffineTransform.getTranslateInstance(w / 2, h / 2));

    try {
        m_InverseViewTransform = m1.createInverse();
    } catch (NoninvertibleTransformException e) {

        AffineTransform m3 = new AffineTransform(mc);
        m3.preConcatenate(AffineTransform.getTranslateInstance(-m_CenterX, -m_CenterY));
        m3.preConcatenate(AffineTransform.getScaleInstance(m_ScaleX * s, -m_ScaleY * s));
        m3.preConcatenate(AffineTransform.getTranslateInstance(w / 2, h / 2));

        System.out.println("m1 = " + m1);
        System.out.println("m2 = " + m2);
        System.out.println("m3 = " + m3);

        AffineTransform m4 = new AffineTransform(mc);
        System.out.println("m4 = " + m4);
        m4.preConcatenate(AffineTransform.getTranslateInstance(-m_CenterX, -m_CenterY));
        System.out.println("m4 = " + m4);
        m4.preConcatenate(AffineTransform.getScaleInstance(m_ScaleX * s, -m_ScaleY * s));
        System.out.println("m4 = " + m4);
        m4.preConcatenate(AffineTransform.getTranslateInstance(w / 2, h / 2));
        System.out.println("m4 = " + m4);

        System.out.println(w); 
        System.out.println(h);
        System.out.println(s);
        System.out.println(m_CenterX);
        System.out.println(m_CenterY);
        System.out.println(m_ScaleX);
        System.out.println(m_ScaleY);

        e.printStackTrace();

这是个谜,有时候,当我启动该应用程序时,通常(四分之三)会抛出NoninvertibleTransformException.

Now the mystery, sometimes when I launch the application ,more often than not, say three times out of four, the NoninvertibleTransformException is thrown.

如您所见,我将输出调试矩阵和其他三个相同计算的矩阵以及用于形成这些矩阵的变量,以进行调试.

As you can see to debug I output the offending matrix and three other identically calculated matrixes and the variables that are used to form those matrixes.

这是有趣的地方,请参见下面的输出,所有矩阵的值都不相同!

And this is where it gets interesting, see the output below, all the matrixes don't have the same value!

m1 = AffineTransform[[0.0, 0.0, 400.0], [0.0, -0.0, 289.0]]
m2 = AffineTransform[[0.0, 0.0, 400.0], [0.0, -0.0, 289.0]]
m3 = AffineTransform[[0.0, 0.0, 400.0], [0.0, -0.0, 289.0]]
m4 = AffineTransform[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]
m4 = AffineTransform[[1.0, 0.0, -49.5], [0.0, 1.0, -0.362762953421903]]
m4 = AffineTransform[[5.254545454545455, 0.0, -260.1], [0.0, -587.9922126928986, 213.3017916655554]]
m4 = AffineTransform[[5.254545454545455, 0.0, 139.89999999999998], [0.0, -587.9922126928986, 502.3017916655554]]
800
578
578.0
49.5
0.36276295342190257
0.009090909090909092
1.0172875652126274
java.awt.geom.NoninvertibleTransformException: Determinant is 0
at java.awt.geom.AffineTransform.createInverse(AffineTransform.java:2706)

更有趣的东西,如果我适当地移动调试输出/计算来深入研究这个问题,问题就会消失.

More interesting stuff, if I suitably move the debug output/calculations around to dig deep into this the problem disappears.

只有在jdk1.8.0_25.jdk中的JRE(在Mac OS X 10.8.5上)才会发生这种情况,而Java 1.6或1.6不会发生这种情况.

This happens only with JRE from jdk1.8.0_25.jdk (on Mac OS X 10.8.5), not with Java 1.6 or 1.6.

好吧,我认为真正的罪魁祸首是JPanel不是在Event Dispatched线程中创建的,一旦我做到了永不抛出异常,就不会有任何不一致之处.

Ok, I think the real culprit is that the JPanel was not created in the Event Dispatched thread, once I did that the exception is never throw there are no inconsistencies.

很明显,线程相关的时序相关问题很明显,但是我很好奇这在Java JVM规则"中如何发生,所有涉及的变量都是方法本地的,而AffineTransform的矩阵方法不应该有问题.这种效果很难理解,线程问题如何导致这种情况……

So pretty obviously a thread related timing dependent problem but I'm curious how can this happen with in Java JVM 'rules' all the variable involved are local to the method and the the matrix methods from AffineTransform are not supposed to have side effects so kind of hard to understand how thread issues can cause something like this…

我想了解一下这里发生的事情.

For my piece of mind I would like to understand what is going on here.

作为一个副作用,这个问题可能会帮助一些可怜的灵魂为类似的问题而苦苦挣扎.

As a side effect this question may help some poor soul struggling with similar issues.

我也不介意有人设法查明代码/调试/演绎中如此明显的缺陷,因为我一直盯着这些行看了好几个小时…….

Also I don't mind if someone manages to pin point so obvious flaw in the code/debug/deductions as I've been staring at those lines now for hours….

推荐答案

如果该方法不依赖于任何共享数据,那么它将无法表现出您描述的行为.从您呈现的内容还不清楚,但是您的方法避免了共享数据.我特别怀疑变量m_CenterXm_CenterYm_ScaleXm_ScaleY.这些闻起来就像您的类的实例变量,如果是,那么它们肯定会在实例化该类的线程和EDT之间共享.如果没有适当的同步,那么在构造函数(或在另一个线程中调用的其他方法)为变量赋值之前,EDT可能会看到这些变量的默认值.

If the method did not rely on any shared data then it could not exhibit the behavior you describe. It is not clear from what you presented, however, that your method avoids shared data. I am particularly suspicious of variables m_CenterX, m_CenterY, m_ScaleX, and m_ScaleY. These smell like instance variables of your class, and if so then they are certainly shared between the thread that instantiates the class and the EDT. Absent proper synchronization, the EDT may then see the default values of those variables, before they are assigned values by the constructor (or other methods invoked in another thread).

通常,在EDT中运行的方法直接或间接访问的类的所有实例变量都在EDT和创建对象的线程之间共享(如果它们不同).

More generally, any instance variables of your class that are accessed directly or indirectly by methods running in the EDT are shared between the EDT and the thread in which your object is created (if those are different).

这篇关于相同的计算如何产生不同的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆