联发科处理器的双precision值计算错误处理器、错误、联发科、precision

2023-09-07 08:44:30 作者:有气质的优雅:提拉米苏dě旧时光

我发现我的应用程序发布在市场上的一个产生奇怪的结果在某些手机上。经调查,原来有一个问题,一个函数,其计算两个GeoPoints之间的距离 - 有时它会返回完全错误的值。这个问题只再现与联发科MT6589 的SoC(又名MTK6589)的设备。和AFAIK所有这样的装置的安装机器人4.2

I've found that one of my application posted on the market produces weird results on some phones. Upon investigation it turns out there is an issue with one function which computes distance between two GeoPoints - sometimes it returns completely wrong value. This issue reproduces only on devices with MediaTek MT6589 SoC (aka MTK6589). And AFAIK all of such devices have Android 4.2 installed.

更新我也能够重现联想S6000平板电脑上的错误与的联发科MT8125 / 8389 芯片和飞IQ444 Quattro的与MT6589和采用Android的 4.1 安装。

Update I was also able to reproduce the bug on Lenovo S6000 tablet with MediaTek MT8125/8389 chip and on Fly IQ444 Quattro with MT6589 and with Android 4.1 installed.

我创建了一个测试项目,帮助重现bug。它运行计算反复1'000或100'000迭代。要排除的线程计算问题的可能性是在UI线程上执行的(小停顿,保持UI响应)。在测试项目中,我只是一个部分从原来的距离公式:

I created a test project which helps to reproduce the bug. It runs computation repeatedly for 1'000 or 100'000 iterations. To exclude possibility of threading issues computation is performed on the UI thread (with small pauses to keep UI responding). In the test project I used just a part from the original distance formula:

private double calcX() {
    double t = 1.0;
    double X = 0.5 + t / 16384;
    return X;
}

正如你可以检查自己上的 web2.0calc.com X 应该是大约值: 0.50006103515625 。 然而与MT6589芯片往往是错误的值计算的设备: 2.0

As you can check by yourself on web2.0calc.com the value of X should be approximately: 0.50006103515625. However on the devices with MT6589 chip often the wrong value is computed: 2.0.

项目,请在谷歌code ( APK 中也可使用)。测试类的源低于psented $ P $:

Project is available at Google Code (APK is available also). The source of the test class is presented below:

public class MtkTestActivity extends Activity {

  static final double A = 0.5;
  static final double B = 1;
  static final double D = 16384;

  static final double COMPUTED_CONST = A + B / D;

  /*
   * Main calculation where bug occurs
   */
  public double calcX() {
    double t = B;
    double X = A + t / D;
    return X;
  }

  class TestRunnable implements Runnable {

    static final double EP = 0.00000000001;

    static final double EXPECTED_LOW = COMPUTED_CONST - EP;

    static final double EXPECTED_HIGH = COMPUTED_CONST + EP;

    public void run() {
      for (int i = 0; i < SMALL_ITERATION; i++) {
        double A = calcX();

        if (A < EXPECTED_LOW || A > EXPECTED_HIGH) {
          mFailedInCycle = true;
          mFails++;
          mEdit.getText().append("FAILED on " + mIteration + " iteration with: " + A + '\n');
        }
        mIteration++;
      }

      if (mIteration % 5000 == 0) {
        if (mFailedInCycle) {
          mFailedInCycle = false;
        } else {
          mEdit.getText().append("passed " + mIteration + " iterations\n");
        }
      }

      if (mIteration < mIterationsCount) {
        mHandler.postDelayed(new TestRunnable(), DELAY);
      } else {
        mEdit.getText().append("\nFinished test with " + mFails + " fails");
      }
    }

  }

  public void onTestClick(View v) {
    startTest(IT_10K);
  }

  public void onTestClick100(View v) {
    startTest(IT_100K);
  }

  private void startTest(int iterationsCount) {
    Editable text = mEdit.getText();
    text.clear();
    text.append("\nStarting " + iterationsCount + " iterations test...");
    text.append("\n\nExpected result " + COMPUTED_CONST + "\n\n");
    mIteration = 0;
    mFails = 0;
    mFailedInCycle = false;
    mIterationsCount = iterationsCount;
    mHandler.postDelayed(new TestRunnable(), 100);
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mHandler = new Handler(getMainLooper());
    mEdit = (EditText) findViewById(R.id.edtText1);
  }

  private static final int IT_10K = 1000;

  private static final int IT_100K = 100000;

  private static final int SMALL_ITERATION = 50;

  private static final int DELAY = 10;

  private int mIteration;

  private int mFails;

  private boolean mFailedInCycle;

  private Handler mHandler;

  private int mIterationsCount;

  private EditText mEdit;

}

要解决这个问题,这是不够的,只是改变所有浮动 calcX ()方法。

To fix the issue it's enough to just change all double to float in calcX() method.

进一步调查 关闭JIT(加入安卓vmSafeMode =真正的到应用程序清单)修复的bug也是如此。

Further investigation Turning off JIT (by adding android:vmSafeMode="true" to the app manifest) fixes bug as well.

在有没有人见过这个错误?也许这是一个已知的问题?

Have anyone seen this bug before? Maybe this is a known issue?

PS:如果有人能够重现此错误的设备与其它芯片上,或可以与任何联发科的芯片测试和Android> = 4.3,我会非常AP preciate它

p.s.: if anyone would be able to reproduce this bug on the device with other chip, or could test it with any MediaTek chip and Android >= 4.3, I will highly appreciate it.

推荐答案

这是活跃于软糖源从2012年年底到2013年年初在短JIT的错误,如果两个或更多双precision常数这是在高32位的不同,但在低32位相同的是在相同的基本块中使用的JIT会认为他们是一样的,不恰当地优化他们中的一个了。

This was a JIT bug that was active in the JellyBean source from late 2012 through early 2013. In short, if two or more double-precision constants that were different in the high 32 bits, but identical in the low 32 bits were used in the same basic block the JIT would think they were the same, and inappropriately optimize one of them away.

我公司推出的缺陷: https://android-review.googlesource.com /#/ C / 47280 /

和固定它: https://android-review.googlesource.com/ #/ C / 57602 /

建立缺陷不应该出现在任何近期的Andr​​oid系统。

The defect should not appear in any recent Android builds.