请选择 进入手机版 | 继续访问电脑版

开源计算机图形学社区(Open Source Computer Graphics Community) |OpenGPU Forum (2007-2013)| OpenGPU Project

 找回密码
 注册
搜索
查看: 5384|回复: 8

卡马克平方根倒数的精确度为什么没有sqrt精确? [复制链接]

Rank: 8Rank: 8

注册时间
2013-5-13
积分
198
发表于 2013-7-18 21:09:59 |显示全部楼层
本帖最后由 Razor87 于 2013-7-18 21:13 编辑

代码如下:
  1. #include <iostream> #include <math.h>
  2. using namespace std;

  3. float InvSqrt (float x)
  4. {
  5.         float xhalf = 0.5f*x;
  6.         int i = *(int*)&x;
  7.         i = 0x5f3759df - (i >> 1); // 计算第一个近似根
  8.         x = *(float*)&i;
  9.         x = x*(1.5f - xhalf*x*x); // 牛顿迭代法
  10.         return x;
  11. }

  12. float CarmSqrt(float x){
  13.         union{
  14.                 int intPart;
  15.                 float floatPart;
  16.         } convertor;
  17.         union{
  18.                 int intPart;
  19.                 float floatPart;
  20.         } convertor2;
  21.         convertor.floatPart = x;
  22.         convertor2.floatPart = x;
  23.         convertor.intPart = 0x1FBCF800 + (convertor.intPart >> 1);
  24.         convertor2.intPart = 0x5f3759df - (convertor2.intPart >> 1);
  25.         return 0.5f*(convertor.floatPart + (x * convertor2.floatPart));
  26. }

  27. int main()
  28. {
  29.         float a = 0.25;

  30.         cout << InvSqrt(a) << endl;
  31.         cout << CarmSqrt(a) << endl;
  32.         cout << sqrt(a) << endl;

  33.         return 0;
  34. }

结果如下:
  1. 1.99661     
  2. 0.488594
  3. 0.5
  4. 请按任意键继续. . .

为什么卡马克算法误差这么大?




Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14455
发表于 2013-7-19 04:15:00 |显示全部楼层
因为迭代一次是不够的,多几次会精确很多。另外,那个常数有个更好的值0x5f375a86,看这里http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf。不过话说你举的这个例子来看,精度也还好咯,比你给的另一个CarmSqrt高了几个数量级。

使用道具 举报

Rank: 9Rank: 9Rank: 9

注册时间
2012-10-11
积分
412
发表于 2013-7-19 14:59:37 |显示全部楼层
InvSqrt 函数内容是不是写错了
怎么错这么多

使用道具 举报

Rank: 13Rank: 13Rank: 13Rank: 13

注册时间
2010-5-19
积分
1316
发表于 2013-7-19 17:52:03 来自手机 |显示全部楼层
速度和精度不可能两全其美。

使用道具 举报

Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14455
发表于 2013-7-20 01:06:22 |显示全部楼层
代码没错,只是cout << InvSqrt(a) << endl;应该改成cout << 1.0f / InvSqrt(a) << endl;。所以我提到了就这个例子来说,精度已经很不错了。

使用道具 举报

Rank: 9Rank: 9Rank: 9

注册时间
2012-10-11
积分
412
发表于 2013-7-21 12:27:06 |显示全部楼层
gongminmin 发表于 2013-7-20 01:06
代码没错,只是cout

多了一步求倒数,效率上是否会有大影响?请问一下,在实际运用中,InvSqrt和CarmSqrt用哪一个更好啊

使用道具 举报

Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14455
发表于 2013-7-21 13:07:34 |显示全部楼层
animaseed 发表于 2013-7-21 12:27
多了一步求倒数,效率上是否会有大影响?请问一下,在实际运用中,InvSqrt和CarmSqrt用哪一个更好啊 ...

倒数也有近似的方式,只是那样精度会进一步下降。目前我还没用过carm,要么就是sqrt,要么就是1 / inv的版本。

使用道具 举报

Rank: 9Rank: 9Rank: 9

注册时间
2012-10-11
积分
412
发表于 2013-7-21 15:21:39 |显示全部楼层
gongminmin 发表于 2013-7-21 13:07
倒数也有近似的方式,只是那样精度会进一步下降。目前我还没用过carm,要么就是sqrt,要么就是1 / inv的 ...

了解了,谢谢龚大回复

使用道具 举报

Rank: 1

注册时间
2017-7-8
积分
13
发表于 2017-7-8 01:54:56 |显示全部楼层
x = x*(1.5f - xhalf*x*x) 这个牛顿迭代可以做两次提高精度,另外我自研究发现 使用 1.f / 结果 的方式把数据倒回来偏大,x * 结果 的方式又偏小,于是我就试着把这两个平方根结果求了一下平均值,便发现精度果然大大提高,和两次牛顿迭代一组合几乎就跟C库结果完全一样。

使用道具 举报

最近看过此主题的会员

您需要登录后才可以回帖 登录 | 注册

‹‹
我的工具栏

关于我们|手机版|Archiver|开源计算机图形学社区(Open Source Computer Graphics Community) | OpenGPU Project | OpenGPU Forum (2007-2013)

GMT+8, 2017-11-25 04:26 , Processed in 0.127247 second(s), 11 queries .

Powered by Discuz! X2

© 2001-2011 Comsenz Inc.

回顶部