2010-05-11 174 views
1

this文章。这里的代码:需要帮助将代码从C转换为Java

float InvSqrt(float x){ // line 0 
    float xhalf = 0.5f * x; 
    int i = *(int*)&x; // store floating-point bits in integer 
    i = 0x5f3759d5 - (i >> 1); // initial guess for Newton's method 
    x = *(float*)&i; // convert new bits into float 
    x = x*(1.5f - xhalf*x*x); // One round of Newton's method 
    return x; 
} 

......我甚至不能告诉如果这是C或C++。 [好吧显然它是C,谢谢]有人可以帮我把它翻译成Java吗?这是(只是,我希望)第2行和第4行令我困惑。

+0

这是两个;它在技术上是C(地震引擎是用C语言编写的),但是它是合法的C++,并且可以在C++编译器中编译。 – 2010-05-11 14:46:52

+2

您的目标是获得反平方根,或者看看Java在上面看起来如何? – extraneon 2010-05-11 14:48:38

+0

@Michael它似乎不是地震代码,神奇的常量似乎有点关闭:) – extraneon 2010-05-11 14:52:25

回答

10

你想使用这些方法:

而且有可能是strictfp问题等

这大致是这样的:(注意:这是未经测试的!)

float InvSqrt(float x){ // line 0 
    float xhalf = 0.5f * x; 
    int i = Float.floatToIntBits(x); // store floating-point bits in integer 
    i = 0x5f3759d5 - (i >> 1); // initial guess for Newton's method 
    x = Float.intBitsToFloat(i); // convert new bits into float 
    x = x*(1.5f - xhalf*x*x); // One round of Newton's method 
    return x; 
} 
+0

@Vuntic:在stackoverflow中'strictfp'上有很多Q/A。我不太了解这个问题的细节,我只是预感到它可能是重要的。或者,也许它是不相关的=) – polygenelubricants 2010-05-11 14:59:53

2

您引用的代码是C,尽管注释是C++风格。

代码在做什么涉及在位级别存储浮点值的方式的知识。 “神奇数字”0x5f3759d5有一些特殊的价值。

i被初始化时,浮点数x的值被访问,因为x的地址被取消引用。因此,i加载了浮点值的前32位。在下一行,x写入i的内容,更新工作近似值。

我已经读过,当John Carmack用Id的开源Quake引擎发布它时,这段代码变得流行起来。代码的目的是快速计算1/Sqrt(x),用于图形引擎的照明计算。

我不会将这段代码直接转换为Java,因为它使用上面描述的“类型双引号” - 当它访问内存中的float时,就好像它是一个int。 Java阻止了这种活动,但正如其他人指出的那样,Float对象提供了一些方法。

在C中使用这个奇怪的实现的目的是为了它非常快。在写作的时候,我想这种方法有了很大的改进。我想知道这个差异是否值得今天浮点运算变得更快。

使用Java方法将float转换为整数位并返回可能比直接使用平方根的Java数学函数计算反平方根要慢。

+0

你可以把float看作Java中的整数 - 参见下面我即将发表的评论。编辑 - 迈克尔也打败了我 - 看到他! :) – corsiKa 2010-05-11 14:52:36

+0

将float作为int来处理并不是OP想要的。这将截断。他们需要像其他人所描述的floattointbits方法。 – 2010-05-11 14:55:09

+0

@布莱恩,从某种意义上说 - 这就是我要做的事 - 迈克尔也打败了我。 – corsiKa 2010-05-11 14:55:59

7

这些行用于在位图模式之间转换floatint。 Java在java.lang.Float中有静态方法 - 其他所有内容都是相同的。

static float InvSqrt(float x) { // line 0 
    float xhalf = 0.5f * x; 
    int i = Float.floatToIntBits(x); // store floating-point bits in integer 
    i = 0x5f3759d5 - (i >> 1); // initial guess for Newton's method 
    x = Float.intBitsToFloat(i); // convert new bits into float 
    x = x * (1.5f - xhalf * x * x); // One round of Newton's method 
    return x; 
} 
+0

你会评论'strictfp'吗?这是否是一个问题,因为我们玩的比特等? – polygenelubricants 2010-05-11 15:03:27

+1

理论上'strictfp'会以保证的方式使结果一致。是否需要取决于原始代码是否依赖于特定的浮点实现。 – 2010-05-11 15:10:31

+1

@polygenelubricants:我不认为strictfp在这里比其他地方更重要。 “玩位”部分完全发生在值经历任何浮点算术之前。 – 2010-05-11 15:38:29

0

你关心的行很简单。第2行采用float x中的字节,这些字节位于IEEE754等浮点表示中,并以整数形式存储它们,完全按照它们的方式存储。这将导致一个完全不同的数字,因为整数和浮点数在字节形式中表示不同。第4行完成相反的操作,并将该int中的字节再次传送到浮点数

1

好吧我在这里出去走走,因为我知道C但我不知道Java。

在Java中正确地重写这个C代码是乞求麻烦。即使在C中,代码也是不可移植的。 其中,它依赖于: 浮点数的大小。 整数的大小。 浮点数的内部表示。 浮点数和整数的字节对齐。 使用逻辑右移 来实现右移(即i >> 1),而不是算术右移(其将在 中以高位1位整数移位1,因此不再等于将 除以2) 。

我知道Java编译成字节码而不是直接写入 机器码。字节码解释器的实现者根据字节码的规范使用 假设,并理解 由编译器从可感知输入源 码输出的内容。

这样的黑客不属于“合理的输入源”。

没有理由期望解释器会用你的C hack更快地执行 ,实际上它有一个很好的机会 它会更慢。

我的建议是:IGNORE C代码。

寻找以Java为中心的效率增益。

的C劈的概念是:

近似1 /平方(X)通过利用知识浮点数的内部 表示已经具有 指数细分数目,指数(x)如果你已经有指数(x),那么/ 2比 的计算速度快于根(x)。

然后hack执行牛顿方法的一个迭代 以减少近似中的误差。我假设 一次迭代将错误减少到可以容忍的程度。

也许这个概念值得在Java中进行调查, 但细节将取决于深入了解 如何实现JAVA,而不是C如何实现。

+0

该代码在C中可能不可移植,但它在Java中非常安全,因为您提到的所有内容都严格指定在那里。我看不出有什么理由说明为什么在Java中这个速度并不快,如果它产生的有限精度是你所需要的。 – 2010-05-11 21:19:06

+0

除非您发布安全和快速的* Java *代码,否则您的评论只是背景噪音。 C代码不适用于Java消费。重点是:不要看C实现细节来计算Java实现细节。他们会有所不同。 – pbernatchez 2010-05-14 05:54:10