我發現我的應用程序在市場上發佈了一些在某些手機上產生奇怪的結果。經過調查發現,一個計算兩個GeoPoint之間距離的函數存在問題 - 有時它返回完全錯誤的值。此問題僅在具有MediaTek MT6589 SoC(又名MTK6589)的設備上重現。 AFAIK所有這些設備都安裝了Android 4.2。聯發科處理器上的雙精度值計算錯誤
更新我也能夠重現聯想S6000平板電腦的錯誤與MediaTek MT8125/8389芯片和Fly IQ444 Quattro與MT6589,並採用Android 4.1 安裝。
我創建了一個測試項目,幫助重現bug。它重複運行計算1'000或100'000次迭代。爲了排除線程問題的可能性,計算在UI線程上執行(只需很少的停頓以保持UI響應)。在測試項目中,我只是從原來的距離公式的一部分:
private double calcX() {
double t = 1.0;
double X = 0.5 + t/16384;
return X;
}
你可以通過自己在web2.0calc.com檢查X
的值約爲:0.50006103515625
。
但是,在使用MT6589芯片的設備上,經常會計算出錯誤的值:2.0
。
項目是available at Google Code(APK也是可用)。測試類的源介紹如下:
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
到float
在calcX()
方法的問題。
進一步調查
關閉JIT(通過添加android:vmSafeMode="true"
到應用清單)修復錯誤,以及。
有沒有人見過這個bug?也許這是一個已知的問題?
P.S。:如果任何人將能夠重現此錯誤在設備上與其他芯片,或者可以與任何芯片發科和Android> = 4.3,我將高度讚賞它進行測試。
https://code.google.com/p/android/issues/detail?id=63790詳細信息在運行Android 4.1.1的HTC One S設備上以及許多其他設備上看到的確切問題。在這個bug中,它最初看起來像與ProGuard的一些不良交互,但是進一步的分析已經將它降低到一些較小的Dalvik字節碼集。根本原因尚未確定,唯一的解決方法是您發現關閉JIT的解決方案。 –
是的,它與我發佈的內容非常相似。谷歌代碼鏈接包含一個測試apk你可以嘗試,並[這裏](http:// stackoverflow。com/questions/20573598/proguard-can-cause-incorrect-computation)是與ProGuard的創建者更詳細的描述和討論。 – Dmitry
我能夠在Android 4.2.1的MT6589手機(Canvas HD)中重現此錯誤。 – HackToHell