需要帮助将代码从 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 行让我感到困惑。
From this article. Here's the code:
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;
}
...I can't even tell if that's C or C++. [okay apparently it's C, thanks] Could someone translate it to Java for me, please? It's (only, I hope) lines 2 and 4 that are confusing me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您想要使用这些方法:
Float.floatToIntBits
Float.intBitsToFloat
并且可能存在
strictfp
等问题。大致是这样的:(注意:这是未经测试的!)
You want to use these methods:
Float.floatToIntBits
Float.intBitsToFloat
And there may be issues with
strictfp
, etc.It's roughly something like this: (CAUTION: this is untested!)
这些行用于在
float
和int
之间转换为位模式。 Java 在java.lang.Float
中有静态方法 - 其他一切都是相同的。Those lines are used to convert between
float
andint
as bit patterns. Java has static methods injava.lang.Float
for that - everything else is identical.你引用的代码是C语言,尽管注释是C++风格的。
代码所做的涉及浮点值在位级别的存储方式的知识。 “幻数”
0x5f3759d5
与特定值有关。初始化
i
时会访问浮点x
值的位,因为x
的地址已取消引用。因此,i
加载了浮点值的前 32 位。在下一行中,用i
的内容写入x
,更新工作近似值。我读到,当 John Carmack 与 Id 的开源 Quake 引擎一起发布该代码时,该代码变得流行起来。代码的目的是快速计算1/Sqrt(x),用于图形引擎的光照计算。
我无法将此代码直接翻译为 Java,因为它使用如上所述的“类型双关语”——当它像访问 int 一样访问内存中的 float 时。 Java 阻止了这种活动,但正如其他人指出的那样,Float 对象提供了围绕它的方法。
在 C 中使用这个奇怪的实现的目的是为了让它非常快。在撰写本文时,我想这种方法会带来很大的改进。我想知道今天的差异是否值得,因为浮点运算已经变得更快了。
使用 Java 方法将浮点型与整数位相互转换可能比直接使用 Java 数学函数计算平方根的倒数要慢。
The code you quote is C, although the comments are C++-style.
What the code is doing involves knowledge of the way floating-point values are stored, at the bit level. The "magic number"
0x5f3759d5
has something do with a particular value.The floating point
x
value's bits are accessed wheni
is initialized, because the address ofx
is dereferenced. So,i
is loaded with the first 32 bits of the floating point value. On the next line,x
is written with the contents ofi
, updating the working approximation value.I have read that this code became popular when John Carmack released it with Id's open source Quake engine. The purpose of the code is to quickly calculate 1/Sqrt(x), which is used in lighting calculations of graphic engines.
I would not have been able to translate this code directly to Java because it uses "type punning" as described above -- when it accesses the float in memory as if it were an int. Java prevents that sort of activity, but as others have pointed out, the Float object provides methods around it.
The purpose of using this strange implementation in C was for it to be very fast. At the time it was written, I imagine a large improvement came from this method. I wonder if the difference is worth it today, when floating point operations have gotten faster.
Using the Java methods to convert float to integer bits and back may be slower than simply calculating the inverse square root directly using Java math function for square root.
好吧,我在这里有点冒险,因为我懂 C,但不懂 Java。
从字面上看,用 Java 重写这段 C 代码是自找麻烦。
即使在 C 语言中,代码也是不可移植的。
除其他外,它还依赖于:
浮点数的大小。
整数的大小。
浮点数的内部表示。
浮点数和整数的字节对齐。
使用逻辑右移实现右移(即 i>>1)
与算术右移相反(这将在 1 上移动)
具有高位 1 位的整数,因此不再等于除法
2)。
我理解Java编译为字节码而不是直接编译为
机器代码。字节码解释器的实现者调整使用
基于字节码规范和理解的假设
编译器从合理输入源输出的内容
代码。
像这样的黑客行为不属于“合理输入源”的范畴。
没有理由期望口译员会执行
用你的 C hack 更快,事实上有一个很好的机会
它会更慢。
我的建议是:忽略 C 代码。
寻求以 Java 为中心的效率提升。
C hack 的概念是:
通过利用内部知识来近似 1/square(x)
浮点数的表示已经有
指数分解为数字,exponent(x)/2 更快
如果你已经有指数(x),则计算根(x)。
然后黑客执行牛顿法的一次迭代
以减少近似误差。我猜想
一次迭代将误差减少到可以容忍的程度。
也许这个概念值得在 Java 中进行研究,
但细节将取决于对以下方面的深入了解
JAVA是如何实现的,而不是C是如何实现的。
Ok I'm going out on a limb here, because I know C but I don't know Java.
Literally rewriting this C code in Java is begging for trouble.
Even in C, the code is unportable.
Among other things it relies on:
The size of floating point numbers.
The size of integers.
The internal representation of floating point numbers.
The byte alignment of both floating point numbers and integers.
Right shift ( i.e. i>>1) being implemented using logical right shift
as opposed to arithmetic right shift (which would shift in a 1 on
integers with a high order 1 bit and thus no longer equate to divide
by 2).
I understand Java compiles to a bytecode rather than directly to
machine code. Implementers of byte code interpreters tune using
assumptions based on the spec for the byte code and an understanding
of what is output by the compiler from sensible input source
code.
Hacks like this don't fall under the umbrella "sensible input source".
There is no reason to expect the interpreter will perform
faster with your C hack, in fact there is a good chance
it will be slower.
My advice is: IGNORE The C code.
Look for a gain in efficiency that is Java centric.
The concept of the C hack is:
Approximate 1/square(x) by leveraging knowledge that the internal
representation of floating point numbers already has the
exponent broken out of the number, exponent(x)/2 is faster to
compute than root(x) if you already have exponent(x).
The hack then performs one iteration of newton's method
to reduce the error in the approximation. I Presume
one iteration reduced the error to something tolerable.
Perhaps the concept warrants investigation in Java,
but the details will depend on intimate knowledge of
how JAVA is implemented, not how C is implemented.
您关心的线路非常简单。第 2 行获取 float
x
中的字节(这些字节采用某种浮点表示形式,例如 IEEE754),并将它们按原样存储在整数中。这将导致完全不同的数字,因为整数和浮点数以字节形式表示不同。第 4 行执行相反的操作,再次将该 int 中的字节传输到 floatThe lines you care about are pretty simple. Line 2 takes the bytes in float
x
, which are in some floating-point representation like IEEE754, and stores them in an integer, exactly the way they are. This will result in a totally different number, since integers and floats are represented differently in byte form. Line 4 does the opposite, and transfers the bytes in that int to the float again