我发现我在市场上发布的一款应用程序在某些手机上产生了奇怪的结果。经过调查发现,一个计算两个地理点之间距离的函数存在问题 - 有时它会返回完全错误的值。此问题仅在具有以下功能的设备上重现联发科MT6589 http://www.mediatek.com/_en/promotion/MT6589_overview.phpSoC(又名 MTK6589)。据我所知,所有此类设备都安装了 Android 4.2。
Update我还能够在 Lenovo S6000 平板电脑上重现该错误联发科 MT8125/8389 http://www.mediatek.com/_en/01_products/04_pro.php?sn=1085芯片及以上飞 IQ444 四轮驱动 http://www.fly-phone.com/devices/smartphones/iq444quattrodiamond2/搭配 MT6589 和 Android4.1安装。
我创建了一个测试项目来帮助重现该错误。它重复运行计算 1'000 或 100'000 次迭代。为了排除线程问题的可能性,计算在 UI 线程上执行(短暂暂停以保持 UI 响应)。在测试项目中,我仅使用了原始距离公式的一部分:
private double calcX() {
double t = 1.0;
double X = 0.5 + t / 16384;
return X;
}
你可以自己检查一下web2.0calc.com http://web2.0calc.com/?q=t%20%3D%201%3B%20A%20%3D%200.5%20%2B%20t%20%2F%2016384的价值X
应该大约是:0.50006103515625
.
然而,在带有 MT6589 芯片的设备上,经常会计算出错误的值:2.0
.
项目是可通过 Google 代码获取 http://code.google.com/p/test-mtk-double-bug/ (也可用)。测试类的源码如下:
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;
}
要解决这个问题,只需更改所有内容就足够了double
to float
in calcX()
方法。
进一步的调查
关闭 JIT(通过添加android:vmSafeMode="true"
到应用程序清单)也修复了错误。
以前有人见过这个错误吗?也许这是一个已知问题?
p.s.:如果有人能够在使用其他芯片的设备上重现此错误,或者可以使用任何 MediaTek 芯片和 Android >= 4.3 对其进行测试,我将非常感激。