2010-05-11 124 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