2016-11-30 61 views
2

使用Arduino,我必須在我的計算機科學類Atmel AVR Assembly中編寫一個函數,計算彙編中兩個8位值的8位平均值。我也不允許使用任何分支指令(但跳過也沒問題)。如何計算彙編中兩個8位值的8位平均值?

這是我到目前爲止有:

.global average 
average: 
    add r24, r22 
    asr r24 
    ret 

我的程序的一部分,我必須計算的69和60的平均,它返回-64而不是64有誰知道我會使這個功能有效嗎?任何幫助將非常感激。

+3

避免整數溢出/環繞的平均技巧:http://stackoverflow.com/a/3816471/224132。我在一分鐘之內通過搜索'沒有溢出的整數平均值'找到了,因爲我知道那裏*是一個技巧,但是不記得它。它可能適用於有符號2的補碼以及未簽名,但我沒有檢查。如果需要,可以將'signed'放入Google搜索字詞中。 –

+0

請注意,我鏈接的答案只適用於未簽名,如果你知道他們在什麼順序。最高票數的答案不需要,但需要比ADD和ROR更多的操作。無論如何,這只是表明,當尋找整數技巧時,不要將自己限制在AVR asm。你會在C中找到很多東西,你可以在AVR中自己實現,甚至可以提供給編譯器,看看它是如何實現的。例如其中一些是有用的:https://graphics.stanford.edu/~seander/bithacks.html –

回答

10

訣竅是先添加然後rotate-with-carry將9位結果除以2,並將8位結果留在寄存器中。

關於我在評論中鏈接的問題的兩個答案使用:first,second

的AVR實現的是:

add r24, r25  ; 9-bit result in C and r24 
    ror r24   ; rotate-through-carry, like x86's RCR instruction 

這適用於位的符號或無符號的解釋,因爲我們所做的是丟棄從另外的9位全結果的低位。沒有算術與邏輯換檔的選擇,也沒有環繞。

另請注意,通過向-infinity輪換(不像C的整數除法運算符那樣截斷爲零)來劃分。所以(1 + -2) >> 1-1


這是足夠小,你應該把它放在一個宏,而不是一個函數。在大多數呼叫站點,它可能至少需要2條指令,因此內聯可以節省代碼大小,即使您可以使用1個字RCALL instruction而不是2個字CALL也是如此。

+0

有趣。所以在x86中我們可以使用'RCL'來達到同樣的效果。不幸的是,編譯器無法識別這種優化 –

+0

@LưuVĩnhPhúc:是的,我不知道如何用C來表達它,而不是通過將其轉換爲更大的無符號類型然後使用>> >>。對於比寄存器更寬的類型,可能沒有編譯器會將其優化回RCL。 –

+0

即使RCL增加1,Intel(Skylake上的增長率爲3)也超過1 uop,因此對於較窄的參數,Intel CPU上的ADD + SHR在64位或32位寄存器上更便宜。如果只有一個輸入需要額外的指令來進行零擴展,MOVZX(或MOV)/ ADD/SHR通常應該擊敗ADD + RCL。特別是因爲零延伸的MOV可以讓您無損破壞。 –