所在位置: > 9号赌城彩票游戏 >

9号赌城彩票游戏
联系方式
电话:0319 7588019
传真:0319 7588019
邮编:055151
地址:河北省任县 邢家湾镇西黄庄工业区
编程计算高低手之分
发布时间:2017-06-02 点击: 次 编辑:admin

编程计算高低手之分,很多时候要么比试在架构思维,要么就是算法实现,例如之前在J2me上频繁实现角色旋转角度计算,圆周率这类函数计算是在太耗机能了,所以当时候我实现想了用对表法,360度分别算好存放到内存上,是一种很好实现。但我看了以下代码,我震惊了!!

 

有人在Quake III的源代码里面发现这么一段用来求平方根的代码:


/*================SquareRootFloat================*/
float SquareRootFloat(float number) {    
    long i;    
    float x, y;    
    const float f = 1.5F;    
    x = number * 0.5F;    
    y  = number;    
    i  = * ( long * ) &y;    
    i  = 0x5f3759df - ( i >> 1 ); //注意这一行    
    y  = * ( float * ) &i;    
    y  = y * ( f - ( x * y * y ) );    
    y  = y * ( f - ( x * y * y ) );    
    return number * y;
}

0x5f3759df? 这是个什么东西? 学过数值分析就知道,算法里面求平方根一般采用的是无限逼近的方法,比如牛顿迭代法,抱歉当年我数值分析学的太烂,也讲不清楚。简单来说比如求5的平方根,选一个猜测值比如2,那么我们可以这么算:
5/2 = 2.5; 2.5+2/2 = 2.25; 5/2.25 = xxx; 2.25+xxx/2 = xxxx ...

这样反复迭代下去,结果必定收敛于sqrt(5),没错,一般的求平方根都是这么算的。而卡马克的不同之处在于,他选择了一个神秘的猜测值0x5f3759df作为起始,使得整个逼近过程收敛速度暴涨,对于Quake III所要求的精度10的负三次方,只需要一次迭代就能够得到结果。

普渡大学的数学家Chris Lomont看了以后觉得有趣,决定要研究一下卡马克弄出来的这个猜测值有什么奥秘。Lomont也是个牛人,在精心研究之后从理论上也推导出一个最佳猜测值,和卡马克的数字非常接近, 0x5f37642f。卡马克真牛,他是外星人吗?

传奇并没有在这里结束。Lomont计算出结果以后非常满意,于是拿自己计算出的起始值和卡马克的神秘数字做比赛,看看谁的数字能够更快更精确的求得平方根。结果是卡马克赢了... 谁也不知道卡马克是怎么找到这个数字的。

最后Lomont怒了,采用暴力方法一个数字一个数字试过来,终于找到一个比卡马克数字要好上那么一丁点的数字,虽然实际上这两个数字所产生的结果非常近似,这个暴力得出的数字是0x5f375a86。

 

 

 

 

最后自己贴一下当时候给J2me用的快速计算360度角度的函数(与上面无关):

----------------------------------------------------------------------------------------------------

package UTS.J2me.Tools;

/**
 * 数学类
 *
 * @author zqq
 */
public class Maths {
 /*
  * sin table
  */
 private static final int SIN_TABLE[] = { 0, 71, 142, 214, 285, 357, 428, 499, 570, 641, 711, 781, 851, 921, 990,
                                          1060, 1128, 1197, 1265, 1333, 1400, 1468, 1534, 1600, 1665, 1730, 1795,
                                          1859, 1922, 1985, 2048, 2109, 2170, 2230, 2290,九号赌城首页, 2349, 2407, 2464, 2521,
                                          2577, 2632, 2686, 2740, 2793, 2845, 2896, 2946, 2995, 3043, 3091, 3137,
                                          3183, 3227, 3271, 3313, 3355, 3395, 3434, 3473, 3510, 3547, 3582, 3616,
                                          3649, 3681, 3712, 3741, 3770, 3797, 3823, 3849, 3872, 3895, 3917, 3937,
                                          3956, 3974, 3991, 4006, 4020, 4033, 4045, 4056, 4065, 4073, 4080, 4086,
                                          4090, 4093, 4095, 4096 };

 /**
  * get sin value
  *
  * @param angle
  * @return
  */
 public static int sin(int angle) {
  angle %= 360;
  if (angle < 0) {
   angle += 360;
  }
  if (angle < 90) {
   return Maths.SIN_TABLE[angle];
  }
  if (angle < 180) {
   return Maths.SIN_TABLE[180 - angle];
  }
  if (angle < 270) {
   return -Maths,九号赌城首页.SIN_TABLE[angle - 180],九号赌城首页;
  }
  else {
   return -Maths.SIN_TABLE[360 - angle];
  }
 }

 /**
  * get cos value
  *
  * @param angle
  * @return
  */
 public static int cos(int angle) {
  angle %= 360;
  if (angle < 0) {
   angle += 360;
  }
  if (angle < 90) {
   return Maths.SIN_TABLE[90 - angle];
  }
  if (angle < 180) {
   return -Maths.SIN_TABLE[angle - 90];
  }
  if (angle < 270) {
   return -Maths.SIN_TABLE[270 - angle];
  }
  else {
   return Maths.SIN_TABLE[angle - 270];
  }
 }

 /**
  * get value
  * @param value
  * @return
  */
 public static int toUnit(int value) {
  return value >> 12;
 }

 /**
  * 这个函数是旋转获得一个圆周上坐标
  *
  * @param cx  int 圆心坐标
  * @param cy  int 圆心坐标
  * @param angle  int 角度
  * @param radii  int 半径
  * @return int[] x和y的坐标
  */
 public static int[] getCirclePos(int cx, int cy, int angle, int radii) {
  int[] pos = new int[2];
  pos[0] = cx + Maths.toUnit(Maths.cos(angle) * radii);
  pos[1] = cy - Maths.toUnit(Maths.sin(angle) * radii);
  return pos;
 }

 /**
  * 求开平方
  * @param x
  * @return
  */
 public static double sqrt(double x) {
  double result = 1.5;// 初始值可以随机选,也可以根据你的应用选能最快收敛的
  double precise = 0.0000001;// 精度
  while (true) {
   double d = (result + x / result) / 2;
   double a = (result - d) > 0 ? (result - d) : (d - result);
   if (a < precise) {
    break;
   }
   result = d;
  }
  System.out.println("result:" + result);
  return result;
 }

  /**
  * 将区域分成8个区域,上下左右为60°一个方向,其他为30°一个方向,例如30°?? -30°为第一个区域,返回值为0,其他的都是顺时针旋转,每60°为一个区域
  *
  * @param 两个点
  *            (x0,y0) (x1,y1)
  * @return 点(x1,y1)在点(x0,y0)的哪个区域
  */
 public static int getAngle(double x0, double y0, double x1, double y1) {
  double r = Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
  double x = (y0 - y1) / r;
  if (x1 >= x0) {
   if (x >= -0.5 && x <= 0.5) {
    return 0;
   } else if (x > 0.5 && x <= 0.866) {
    return 7;
   }
   else if (x > 0.866 && x <= 1) {
    return 6;
   }
   else if (x >= -0.866 && x < -0.5) {
    return 1;
   }
   else if (x >= -1 && x < -0.866) {
    return 2;
   }
  }
  else if (x1 < x0) {
   if (x >= -0.5 && x <= 0.5) {
    return 4;
   } else if (x > 0.5 && x <= 0.866) {
    return 5;
   }
   else if (x >= -0.866 && x < -0.5) {
    return 3;
   }
   else if (x < -0.866) {
    return 2;
   }
   else if (x > 0.866) {
    return 6;
   }
  }
  return 0;
 }

 

}

Copyright 2017 九号赌城首页 All Rights Reserved