1

次のコードがあります。

unsigned short wrLine;
unsigned short prev = ((wrLine - 1) % 16);
wrLine = (wrLine + 1) % 16;

これにより、次の逆アセンブリが生成されます。

unsigned short prev = ((wrLine - 1) % LINES_IN_FIFO);

0041456A   movw      r3, #25282           
0041456E   movt      r3, #8192            
00414572   ldrh      r3, [r3]             
00414574   uxth      r3, r3        
00414576   add.w     r2, r3, #4294967295        
0041457A   mov.w     r3, #15              
0041457E   movt      r3, #32768           
00414582   ands      r3, r2        
00414584   cmp       r3, #0        
00414586   bge       #10           
00414588   add.w     r3, r3, #4294967295        
0041458C   orn       r3, r3, #15          
00414590   add.w     r3, r3, #1           
00414594   strh      r3, [r7, #4]   

wrLine = (wrLine + 1) % LINES_IN_FIFO;

0041463E   movw      r3, #25282           
00414642   movt      r3, #8192            
00414646   ldrh      r3, [r3]             
00414648   uxth      r3, r3        
0041464A   add.w     r2, r3, #1           
0041464E   mov.w     r3, #15              
00414652   movt      r3, #32768           
00414656   ands      r3, r2        
00414658   cmp       r3, #0        
0041465A   bge       #10           
0041465C   add.w     r3, r3, #4294967295        
00414660   orn       r3, r3, #15          
00414664   add.w     r3, r3, #1           
00414668   uxth      r2, r3        
0041466A   movw      r3, #25282           
0041466E   movt      r3, #8192  

興味深いことに、wrLine が 0 の場合、prev は 0xFFFF になり、wrLine が 15 の場合は 0x0000 になります。なぜこれらの1つだけが機能するのか考えていますか?

ありがとう、デヴァン

4

4 に答える 4

0

2つのお勧めがあります。この問題では、どちらでも機能します。2 のべき乗除数の最速は次のとおりです。

wrLine = (wrLine - 1)&(16-1); /* (wrLine + 1) mod 16 */

JG の発言にもかかわらず、これは (a) 常に機能し、(b) wrLine が署名されている場合、コンパイラによって生成されることはありません。もう 1 つの方法は、絶対に引き算しないことです。代わりに次を使用します。

wrLine = (wrLine + 16 - 1)%16;

wrLine が最初に負でない限り、これは負の結果を作成しません。これは、除数が2 の累乗でない場合に使用するパターンです。

私は、質問者にとっておそらく十分であると認められた回答を持つ質問に回答していますが、その回答は一般的には良くありません。符号なしの値に変換するという提案は、2 の累乗の除数に対してのみ機能します。符号付きから符号なしへの変換は、(数値的に) 2 の累乗を加算することと同等です。これは、除数が 2 の累乗以下の場合にのみ 0 を加算することと同等です。

例えば:

printf("-1 % 23U = %d", -1 % 16U);

生成:

-1 % 23U = 15

...これは明らかに 22 ではありません。私が知っている (a mod b) の最も簡潔な表現は次のいずれかです。

(a%b + b)%b /* when b>0 */
(a%b - b)%b /* when b<0 */

これらには 2 つの分割が含まれるため、if または if-else を使用した長いソリューションはより高速に実行されます。回答の上部にあるソリューションは、モジュラー減算のすべてのケースを固定量で処理します。

于 2013-09-05T20:08:22.733 に答える