2017-01-27 13 views
1

我正在編寫性能密集型Fortran代碼,它的核心是一個無矩陣乘法子程序mfmult(x,y),它接受一個輸入向量x並返回一個輸出向量y,使得如果i = i_ {n-1} i_ {n-2} ... i_2i_1i_0是n位二進制數(可能具有前導零),則Fortran中的高效單比特否定

y(i)= sum {x (J):j是我的任何1位否定}

y(000) = x(001)+x(010)+x(100) 
y(1101) = x(0101)+x(1001)+x(1111) + x(1100) etc. 

什麼是實現這個的有效途徑?一個相關的問題是:在Fortran中是否存在一個快速內在的單比特否定?我已經看過內在函數和https://rosettacode.org/wiki/Bitwise_operations#Fortran,但沒有單比特否定操作,我擔心任何手動編碼/分支語句會讓事情變得太慢。

+0

好,CPU總是反正訪問整個字節。你可以使用IBSET(),但我不認爲這會特別有效。你也可以用一些特定的常量使用IEOR()。 –

+0

IBSET和IBCLR的問題是,我首先需要一個BTEST if語句來檢查該位是否爲0和1,以便我可以選擇相反的結果,我期望在一個巨大的循環中運行相當緩慢。我不知道如何使用IEOR()。翻轉一個位似乎是這樣一個基本的操作,這些方法似乎是矯枉過正。這僅僅是Fortran作爲一種語言的限制,它沒有這種內在性? – user2520385

+0

如果您想將其稱爲限制...您認爲在Fortran中缺少的C或x86彙編中的等效內容是什麼? –

回答

4

我建議你使用內在的IEOR()。你必須先準備好正確的面具。這看起來可能是間接的,但我不認爲可以有什麼更直接事實上,看到C/Assembly: how to change a single bit in a CPU register?

所以,如果你有整數i,並且要翻轉第三位,我會真正做到:

i = ieor(i, int(b'00000100')) 

什麼,這將在x86_64的組件做的是

xorl $4, the_register_holding_i 

如果你想在整翻轉多個位最好是做好相應的準備面具,並調用IEOR()只有一次。

請注意,CPU始終與整個字節(至少)或更高效地使用整個單詞一起工作,沒有任何指令只需要一個位的地址並僅操作那一個。你不必擔心你正在訪問整個32位整數,因爲你有一個32位或64位處理器。該指令集可以有效地處理32位和64位整數。

2

這應該是有效的:

program test 
    implicit none 
    integer :: filter(0:31) 
    data filter/& 
    b'00000000000000000000000000000001', & 
    b'00000000000000000000000000000010', & 
    b'00000000000000000000000000000100', & 
    b'00000000000000000000000000001000', & 
    b'00000000000000000000000000010000', & 
    b'00000000000000000000000000100000', & 
    b'00000000000000000000000001000000', & 
    b'00000000000000000000000010000000', & 
    b'00000000000000000000000100000000', & 
    b'00000000000000000000001000000000', & 
    b'00000000000000000000010000000000', & 
    b'00000000000000000000100000000000', & 
    b'00000000000000000001000000000000', & 
    b'00000000000000000010000000000000', & 
    b'00000000000000000100000000000000', & 
    b'00000000000000001000000000000000', & 
    b'00000000000000010000000000000000', & 
    b'00000000000000100000000000000000', & 
    b'00000000000001000000000000000000', & 
    b'00000000000010000000000000000000', & 
    b'00000000000100000000000000000000', & 
    b'00000000001000000000000000000000', & 
    b'00000000010000000000000000000000', & 
    b'00000000100000000000000000000000', & 
    b'00000001000000000000000000000000', & 
    b'00000010000000000000000000000000', & 
    b'00000100000000000000000000000000', & 
    b'00001000000000000000000000000000', & 
    b'00010000000000000000000000000000', & 
    b'00100000000000000000000000000000', & 
    b'01000000000000000000000000000000', & 
    b'10000000000000000000000000000000'/ 
    integer :: a 
    integer :: k 

    ! Number whose single-bit negations should be found 
    a = b'1101' 

    do k=0,31 
    print *, ieor(a,filter(k)) 
    enddo 

end 
+0

只是一個樣式註釋 - 數據有點老式,我會在聲明中初始化過濾器,並將其作爲參數 –