我的疑问:1.我的代码是否有错误,2,两种方法究竟哪种快,为什么,因为什么底层逻辑还是原理之类的?
原题是这样的:给出任意一个int 类型的正整数,如何快速判断该整数的值,是否是2的整数次幂?
这是第一种方法 //scanner为要求的那个任意数
这是第二种
我突发奇想,两种方法那种快,第一种是同学写的,第二种是我的。
于是我想验证,首先把输出注释了,因为我的理解,每次反正是最终结果得到的时候输出,用时应该都一样的。
首先第一种验证是,让两种方法对同一个数重复执行,例如执行百万次,然后执行100轮。计算每一轮的用时差距,结果是,第二种的用时普遍远远少于第一种。
后来我想换一种,不让他们对同一个数反复执行,而是对同一堆数反复执行。例如,先生成百万个随机数存到一个数组里,然后每个方法分别对这百万的数进行计算,统计用时,这样也执行100轮。结果是,两种方法各有千秋,但是,第二种都是几十毫秒,但第一种竟然会出现0,差不多是反过来的情况了。
实在搞不懂为什么差距会这么大,我待会展示我的源码给各位大 佬看看,不排除第二次测试的时候,代码写错了,以我的能力,我检不出来错误。如果有错误请各位大 佬指正下,回归主题,我就想知道这两种哪种快,因为什么原理?
第一次测试
long[] A=new long[100];//程序1的
long[] B=new long[100];
for(int a=0;a<100;a++){
int scanner = (int)(Math.random()*1000000000+1);
System.out.print(scanner+"\t");
//程序1
long startTime1=System.currentTimeMillis();//保存开始时间节点
for(int i=0;i<1000000;i++)//执行一次的用时都是0毫秒,无法比较,都扩大百万倍,比较用时
{
int sum=1;
for(int j=1;j<=30;j++){
sum*=2;
if(scanner==sum){
//System.out.println(scanner+"是2的整数次幂");
break;
}
if(j==30){
//System.out.println(scanner+"不是2的整数次幂");
}
}
}
long endTime1=System.currentTimeMillis();//保存结束时间节点
//程序2
long startTime2=System.currentTimeMillis();
for (int i=0;i<1000000;i++)
{
int num=scanner;
while(num>1){
if(num%2==1){//判断是否是单数,单数没有在计算的必要了,肯定不是2的倍数
break;
}
num=num/2;//让输入的数砍半,如果目标数符合,那重复执行到最后的结果是1,2/2==1
}
if(num==1){
//System.out.println(scanner+"是2的整数次幂");
}else {
//System.out.println(scanner+"不是2的整数次幂");
}
}
long endTime2=System.currentTimeMillis();
//最终比较用时
long time1=endTime1-startTime1;
long time2=endTime2-startTime2;
A[a]=time1;B[a]=time2;
System.out.println("程序1用时"+(time1)+"毫秒,程序2用时"+(time2)+"毫秒");
}
long[] difference=new long[100];
double[] multiple=new double[100];
long maxDif=Long.MIN_VALUE,minDif=Long.MAX_VALUE;
double maxMu=Double.MIN_VALUE,minMu=Double.MAX_VALUE;
for(int i=0;i<100;i++){
long num1=A[i]-B[i];
double num2=(double) A[i]/B[i];
difference[i]=num1;
multiple[i]=num2;
if(num1>maxDif){
maxDif=num1;
}
if(num1<minDif){
minDif=num1;
}
if(num2>maxMu){
maxMu=num2;
}
if(num2<minMu){
minMu=num2;
}
}
System.out.println("两个程序都执行百万次,随机数执行一百轮,第一行为每次两者的时间差,第二行为两者的时间倍数");
System.out.println(Arrays.toString(difference));
System.out.println(Arrays.toString(multiple));
System.out.println("其中最大差值达到了"+maxDif+"\t最小差值有"+minDif);
System.out.println("其中最大倍数达到了"+maxMu+"\t最小倍数有"+minMu);
第二次测试
int userScan=10;//大循环,决定进行多少轮
int count=10000000;//小循环,决定多少个随机数数字。使用随机数字,并且让一种算法一次性计算完这些,是为了差距更明显,同时避免程序2出现0时间可能
long[] A=new long[userScan];//程序1的
double[] B=new double[userScan];
for(int big=0;big<userScan;big++)
{
int[] random=new int[count];
//生成count数量的随机数,保存到random数组中
for(int a=0;a<count;a++){
random[a]=(int)(Math.random()*1000000000+1);//范围为十亿
}
//程序1
long startTime1=System.currentTimeMillis();//保存开始时间节点
for(int first=0;first<count;first++) {
int sum = 1;
for (int j = 1; j <= 30; j++) {
sum *= 2;
if (random[first] == sum) {
//System.out.println(scanner+"是2的整数次幂");
break;
}
if (j == 30) {
//System.out.println(scanner+"不是2的整数次幂");
}
}
}
long endTime1=System.currentTimeMillis();//保存结束时间节点
//程序2
long startTime2=System.currentTimeMillis();
for (int first=0;first<count;first++) {
int num = random[first];
while (num > 1) {
if (num % 2 == 1) {//判断是否是单数,单数没有在计算的必要了,肯定不是2的倍数
break;
}
num = num / 2;//让输入的数砍半,如果目标数符合,那重复执行到最后的结果是1,2/2==1
}
if (num == 1) {
//System.out.println(scanner+"是2的整数次幂");
} else {
//System.out.println(scanner+"不是2的整数次幂");
}
}
long endTime2=System.currentTimeMillis();
//最终比较用时
long time1=endTime1-startTime1;
long time2=endTime2-startTime2;
A[big]=time2-time1;
B[big]=(double)time2/time1;
System.out.println("程序1用时"+(time1)+"毫秒,程序2用时"+(time2)+"毫秒");
}
long maxDif=Long.MIN_VALUE,minDif=Long.MAX_VALUE;
double maxMu=Double.MIN_VALUE,minMu=Double.MAX_VALUE;
for(int i=0;i<userScan;i++){
long num1=A[i];
double num2=B[i];
if(num1>maxDif){
maxDif=num1;
}
if(num1<minDif){
minDif=num1;
}
if(num2>maxMu){
maxMu=num2;
}
if(num2<minMu){
minMu=num2;
}
}//遍历AB数组,将差值倍数存入相对应的数组,同时找到最大值最小值
System.out.println("两个程序都执行"+userScan+"轮,每轮生成"+count+"个随机数,两种算法分别对这相同的随机数进行处理,第一行为每轮两者用时的时间差,第二行为两者的时间倍数");
System.out.println(Arrays.toString(A));
System.out.println(Arrays.toString(B));
System.out.println("其中最大差值达到了"+maxDif+"\t最小差值有"+minDif);
System.out.println("其中最大倍数达到了"+maxMu+"\t最小倍数有"+minMu);
这是第一种测试的结果,结果很明显第二种方法快很多
这第二种测试的结果很明显有问题,但我找不到
肯定有影响呀,算法的时间复杂度和空间复杂度会影响程序的时间,所以要择优选择算法,或者先解出题目,然后再做优化
这样子测试,实际上还没排除jit的影响。运行jvm的时候把jit关了再测试吧。