ProGuard的可能导致不正确的计算 [英] ProGuard can cause incorrect calculations
问题描述
我遇到过一个pretty的奇怪的错误。下面的小块code使用一个相当简单的数学。
保护双C_n_k(INT N,INT K)
{
如果(K℃,|| K&将N)
返回0;
双S = 1;
的for(int i = 1; I< = K;我++)
S = S *(n + 1个-ⅰ)/ I;
返回S;
}
修改使用ProGuard的可以让它出问题的一些设备。我有它证实了的HTC One的Android 4.1.1版本3.16.401.8,而是通过电子邮件,我得到的情况来看,很多手机采用Android 4+受到影响。对于其中一些(银河S3)中,美国运营商品牌的手机都受到影响,而国际版本都没有。很多手机都没有受到影响。
下面是活动的code,其计算C(N,K)为1所述; =正α25和0℃= K&其中; =正。在第一届上面提到的设备都给出了正确的结果,但随后的启动显示不正确的结果,在不同的位置各一次。
我有3个问题:
-
怎么能有呢?即使ProGuard的做出一些错误,计算应该是设备和会话之间是一致的。
-
我们怎样才能避免呢?我知道替换
双
按长
是罚款在这种情况下,但它不是一个通用的方法。使用删除双
或释放不混淆的版本是不成问题的。 -
什么的Android版本是否受到影响?我是比较快的有固定它在游戏中,所以我只知道,很多玩家都看过,而且至少是最有Android 4.0的
溢出是不成问题的,因为有时我看到错误,在计算 C(3,3)= 3/1 * 2/2 *三分之一
。通常不正确的数字开始的地方在C(10,...),以及看起来像一个电话已经遗忘,使一些分歧。
我的SDK工具是22.3(最新的),我已经看到它在建立了一个由Eclipse和IntelliJ IDEA的创建。
活动code:
包com.karmangames.mathtest;
进口android.app.Activity;
进口android.os.Bundle;
进口android.text.method.ScrollingMovementMethod;
进口android.widget.TextView;
公共类MathTestActivity扩展活动
{
/ **
*第一次创建活动时调用。
* /
@覆盖
公共无效的onCreate(包savedInstanceState)
{
super.onCreate(savedInstanceState);
的setContentView(R.layout.main);
字符串s =;
对于(INT N = 0; N< = 25; N ++)
对于(INT K = 0; K< = N; k ++)
{
双V = C_n_k_double(N,K);
S + =C(+ N +,+ K +)=+ V +(V == C_n_k_long(N,K)?:正确的是+ C_n_k_long(N,K))+\ N ;
如果(K = = N)
S + =\ N的;
}
的System.out.println(多个);
((TextView中)findViewById(R.id.text))的setText(S)。
((TextView的)findViewById(R.id.text))setMovementMethod(新ScrollingMovementMethod());
}
保护双C_n_k_double(INT N,INT K)
{
如果(K℃,|| K&将N)
返回0;
// C_N ^ķ
双S = 1;
的for(int i = 1; I< = K;我++)
S = S *(n + 1个-ⅰ)/ I;
返回S;
}
保护双C_n_k_long(INT N,INT K)
{
如果(K℃,|| K&将N)
返回0;
// C_N ^ķ
长S = 1;
的for(int i = 1; I< = K;我++)
S = S *(n + 1个-ⅰ)/ I;
返回(双)S;
}
}
main.xml中:
< XML版本=1.0编码=UTF-8&GT?;
< LinearLayout中的xmlns:机器人=http://schemas.android.com/apk/res/android
机器人:方向=垂直
机器人:layout_width =FILL_PARENT
机器人:layout_height =FILL_PARENT
>
<的TextView
机器人:layout_width =FILL_PARENT
机器人:layout_height =WRAP_CONTENT
机器人:ID =@ + ID /文
机器人:文本=您好!世界
/>
< / LinearLayout中>
错误的计算结果示例(请记住,这是不同的,每次我试试吧)
C(0,0)= 1.0
C(1,0)= 1.0
C(1,1)= 1.0
C(2,0)= 1.0
C(2,1)= 2.0
C(2,2)= 1.0
C(3,0)= 1.0
C(3,1)= 3.0
C(3,2)= 3.0
C(3,3)= 1.0
C(4,0)= 1.0
C(4,1)= 4.0
C(4,2)= 6.0
C(4,3)= 4.0
C(4,4)= 1.0
C(5,0)= 1.0
C(5,1)= 5.0
C(5,2)= 10.0
C(5,3)= 10.0
C(5,4)= 30.0修正为5.0
C(5,5)= 1.0
C(6,0)= 1.0
C(6,1)= 6.0
C(6,2)= 15.0
C(6,3)= 40.0修正为20.0
C(6,4)= 90.0修正为15.0
C(6,5)= 144.0正确的是6.0
C(6,6)= 120.0正确的是1.0
C(7,0)= 1.0
C(7,1)= 7.0
C(7,2)= 21.0
C(7,3)= 35.0
C(7,4)= 105.0正确的是35.0
C(7,5)= 504.0正确的是21.0
C(7,6)= 840.0正确的是7.0
C(7,7)= 720.0正确的是1.0
C(8,0)= 1.0
C(8,1)= 8.0
C(8,2)= 28.0
C(8,3)= 112.0正确的是56.0
C(8,4)= 70.0
C(8,5)= 1344.0正确的是56.0
C(8,6)= 3360.0正确的是28.0
C(8,7)= 5760.0正确的是8.0
C(8,8)= 5040.0正确的是1.0
C(9,0)= 1.0
C(9,1)= 9.0
C(9,2)= 36.0
C(9,3)= 168.0正确的是84.0
C(9,4)= 756.0正确的是126.0
C(9,5)= 3024.0正确的是126.0
C(9,6)= 10080.0正确的是84.0
C(9,7)= 25920.0正确的是36.0
C(9,8)= 45360.0正确的是9.0
C(9,9)= 40320.0正确的是1.0
C(10,0)= 1.0
C(10,1)= 10.0
C(10,2)= 45.0
C(10,3)= 120.0
C(10,4)= 210.0
C(10,5)= 252.0
C(10,6)= 25200.0正确的是210.0
C(10,7)= 120.0
C(10,8)= 315.0正确的是45.0
C(10,9)= 16800.0正确的是10.0
C(10,10)= 1.0
Android团队成员已经张贴在评论我的问题。如果我添加安卓vmSafeMode =真正的
来清单文件的应用程序
元素,所有的计算都正确执行。此选项没有很好的记载和老实说,我不知道这多少会影响速度,但是至少在数学将是正确的。直到一个更好的找到我将其标记为正确答案。
I have met a pretty strange bug. The following small piece of code uses a rather simple math.
protected double C_n_k(int n, int k)
{
if(k<0 || k>n)
return 0;
double s=1;
for(int i=1;i<=k;i++)
s=s*(n+1-i)/i;
return s;
}
Edit Using ProGuard can make it go wrong on some devices. I have it confirmed on HTC One S Android 4.1.1 build 3.16.401.8, but judging by e-mails I got, a lot of phones with Android 4+ are affected. For some of them (Galaxy S3), american operator-branded phones are affected, while international versions are not. Many phones are not affected.
Below is the code of activity which calculates C(n,k) for 1<=n<25 and 0<=k<=n. On device mentioned above the first session gives correct results, but the subsequent launches show incorrect results, each time in different positions.
I have 3 questions:
How can it be? Even if ProGuard made something wrong, calculations should be consistent between devices and sessions.
How can we avoid it? I know substituting
double
bylong
is fine in this case, but it is not a universal method. Dropping usingdouble
or releasing not-obfuscated versions is out of question.What Android versions are affected? I was quite quick with fixing it in the game, so I just know that many players have seen it, and at least the most had Android 4.0
Overflow is out of question, because sometimes I see mistake in calculating C(3,3)=3/1*2/2*1/3
. Usually incorrect numbers start somewhere in C(10,...), and look like a phone has "forgotten" to make some divisions.
My SDK tools are 22.3 (the latest), and I have seen it in builds created by both Eclipse and IntelliJ IDEA.
Activity code:
package com.karmangames.mathtest;
import android.app.Activity;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.widget.TextView;
public class MathTestActivity extends Activity
{
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String s="";
for(int n=0;n<=25;n++)
for(int k=0;k<=n;k++)
{
double v=C_n_k_double(n,k);
s+="C("+n+","+k+")="+v+(v==C_n_k_long(n,k) ? "" : " Correct is "+C_n_k_long(n,k))+"\n";
if(k==n)
s+="\n";
}
System.out.println(s);
((TextView)findViewById(R.id.text)).setText(s);
((TextView)findViewById(R.id.text)).setMovementMethod(new ScrollingMovementMethod());
}
protected double C_n_k_double(int n, int k)
{
if(k<0 || k>n)
return 0;
//C_n^k
double s=1;
for(int i=1;i<=k;i++)
s=s*(n+1-i)/i;
return s;
}
protected double C_n_k_long(int n, int k)
{
if(k<0 || k>n)
return 0;
//C_n^k
long s=1;
for(int i=1;i<=k;i++)
s=s*(n+1-i)/i;
return (double)s;
}
}
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/text"
android:text="Hello World!"
/>
</LinearLayout>
Example of wrong calculation results (remember, it's different every time I try it)
C(0,0)=1.0
C(1,0)=1.0
C(1,1)=1.0
C(2,0)=1.0
C(2,1)=2.0
C(2,2)=1.0
C(3,0)=1.0
C(3,1)=3.0
C(3,2)=3.0
C(3,3)=1.0
C(4,0)=1.0
C(4,1)=4.0
C(4,2)=6.0
C(4,3)=4.0
C(4,4)=1.0
C(5,0)=1.0
C(5,1)=5.0
C(5,2)=10.0
C(5,3)=10.0
C(5,4)=30.0 Correct is 5.0
C(5,5)=1.0
C(6,0)=1.0
C(6,1)=6.0
C(6,2)=15.0
C(6,3)=40.0 Correct is 20.0
C(6,4)=90.0 Correct is 15.0
C(6,5)=144.0 Correct is 6.0
C(6,6)=120.0 Correct is 1.0
C(7,0)=1.0
C(7,1)=7.0
C(7,2)=21.0
C(7,3)=35.0
C(7,4)=105.0 Correct is 35.0
C(7,5)=504.0 Correct is 21.0
C(7,6)=840.0 Correct is 7.0
C(7,7)=720.0 Correct is 1.0
C(8,0)=1.0
C(8,1)=8.0
C(8,2)=28.0
C(8,3)=112.0 Correct is 56.0
C(8,4)=70.0
C(8,5)=1344.0 Correct is 56.0
C(8,6)=3360.0 Correct is 28.0
C(8,7)=5760.0 Correct is 8.0
C(8,8)=5040.0 Correct is 1.0
C(9,0)=1.0
C(9,1)=9.0
C(9,2)=36.0
C(9,3)=168.0 Correct is 84.0
C(9,4)=756.0 Correct is 126.0
C(9,5)=3024.0 Correct is 126.0
C(9,6)=10080.0 Correct is 84.0
C(9,7)=25920.0 Correct is 36.0
C(9,8)=45360.0 Correct is 9.0
C(9,9)=40320.0 Correct is 1.0
C(10,0)=1.0
C(10,1)=10.0
C(10,2)=45.0
C(10,3)=120.0
C(10,4)=210.0
C(10,5)=252.0
C(10,6)=25200.0 Correct is 210.0
C(10,7)=120.0
C(10,8)=315.0 Correct is 45.0
C(10,9)=16800.0 Correct is 10.0
C(10,10)=1.0
Android team member has posted a possible solution in a comment to my issue. If I add android:vmSafeMode="true"
to application
element of manifest-file, all calculations are performed correctly. This option is not well documented and honestly I do not know how much will it affect the speed, but at least the math will be correct. I will mark it as correct answer until a better one is found.
这篇关于ProGuard的可能导致不正确的计算的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!