需要帮助将代码从 C 翻译为 Java

发布于 2024-08-31 18:18:03 字数 586 浏览 8 评论 0原文

来自这篇文章。代码如下:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

围归者 2024-09-07 18:18:03

您想要使用这些方法:

并且可能存在 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;
}

You want to use these methods:

And there may be issues with strictfp, etc.

It's roughly something like this: (CAUTION: this is untested!)

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;
}
迷迭香的记忆 2024-09-07 18:18:03

这些行用于在 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;
}

Those lines are used to convert between float and int as bit patterns. Java has static methods in java.lang.Float for that - everything else is identical.

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;
}
生活了然无味 2024-09-07 18:18:03

你引用的代码是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 when i is initialized, because the address of x 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 of i, 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.

孤独陪着我 2024-09-07 18:18:03

好吧,我在这里有点冒险,因为我懂 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.

抚笙 2024-09-07 18:18:03

您关心的线路非常简单。第 2 行获取 float x 中的字节(这些字节采用某种浮点表示形式,例如 IEEE754),并将它们按原样存储在整数中。这将导致完全不同的数字,因为整数和浮点数以字节形式表示不同。第 4 行执行相反的操作,再次将该 int 中的字节传输到 float

The 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文