18

特に Cortex-A8 と Cortex-A9 に取り組んでいます。一部のアーキテクチャには整数除算が付属していないことは知っていますが、浮動小数点数への変換、除算、整数への変換以外にそれを行う最良の方法は何ですか? それとも、それが本当に最善の解決策ですか?

乾杯!= )

4

5 に答える 5

11

定数値による除算は、たとえば次のように、64 ビットの乗算と右シフトを実行することですばやく実行できます。

LDR     R3, =0xA151C331
UMULL   R3, R2, R1, R3
MOV     R0, R2,LSR#10

ここで、R1 は 1625 で除算されます。計算は次のように行われます。

R1*0xA151C331/2^(32+10) = R1*0.00061538461545751488 = R1/1624.99999980

この式から独自の定数を計算できます。

x / N ==  (x*A)/2^(32+n)   -->       A = 2^(32+n)/N

A < 2^32 である最大の n を選択します

于 2012-10-16T07:50:51.020 に答える
7

整数除算のための他の場所からのコピーパスタ: 基本的に、ビットごとに 3 つの命令。このウェブサイトからですが、他の多くの場所でも見ました。 このサイトには、全体的に高速なナイス バージョンもあります。


@ Entry  r0: numerator (lo) must be signed positive
@        r2: deniminator (den) must be non-zero and signed negative
idiv:
        lo .req r0; hi .req r1; den .req r2
        mov hi, #0 @ hi = 0
        adds lo, lo, lo
        .rept 32 @ repeat 32 times
          adcs hi, den, hi, lsl #1
          subcc hi, hi, den
          adcs lo, lo, lo
        .endr
        mov pc, lr @ return
@ Exit   r0: quotient (lo)
@        r1: remainder (hi)
于 2011-12-01T22:45:56.083 に答える
4

コンパイラーは通常、そのライブラリー gcclib に除算を含めます。たとえば、gcc からそれらを抽出して直接使用します。

https://github.com/dwelch67/stm32vld/その後、stm32f4d/adventure/gcclib

浮かんで戻ってくるのは、おそらく最善の解決策ではありません。あなたはそれを試してみて、それがどれほど速いかを見ることができます...これは乗算ですが、除算も簡単に行うことができます:

https://github.com/dwelch67/stm32vld/その後 stm32f4d/float01/vectors.s

私はそれがどれほど速い/遅いかを確認するために時間を計りませんでした. 上記のcortex-mを使用していることを理解しました。あなたはcortex-a、スペクトルのさまざまな端、同様のフロート命令、およびgcc libのものについて話していることを理解しています。腕も同様に簡単に構築できます。実際、gcc を使用すると、すべて自動的に機能するはずです。私が行った方法で行う必要はありません。他のコンパイラーも、上記のアドベンチャー ゲームで行った方法で行う必要はありません。

于 2011-12-01T21:16:59.477 に答える
2

Webで署名されていないバージョンが見つからなかったため、署名されていない除算を実行するための独自のルーチンを作成しました。32ビットの結果を得るには、64ビットの値を32ビットの値で除算する必要がありました。

内部ループは、上記の符号付きソリューションほど効率的ではありませんが、これは符号なし演算をサポートします。このルーチンは、分子の上位部分(hi)が分母(den)よりも小さい場合は、32ビットの除算を実行します。それ以外の場合は、完全な64ビットの除算(hi:lo / den)を実行します。結果はloにあります。

  cmp     hi, den                   // if hi < den do 32 bits, else 64 bits
  bpl     do64bits
  REPT    32
    adds    lo, lo, lo              // shift numerator through carry
    adcs    hi, hi, hi
    subscc  work, hi, den           // if carry not set, compare        
    subcs   hi, hi, den             // if carry set, subtract
    addcs   lo, lo, #1              // if carry set, and 1 to quotient
  ENDR

  mov     r0, lo                    // move result into R0
  mov     pc, lr                    // return

do64bits:
  mov     top, #0
  REPT    64
    adds    lo, lo, lo              // shift numerator through carry
    adcs    hi, hi, hi
    adcs    top, top, top
    subscc  work, top, den          // if carry not set, compare        
    subcs   top, top, den           // if carry set, subtract
    addcs   lo, lo, #1              // if carry set, and 1 to quotient
  ENDR
  mov     r0, lo                    // move result into R0
  mov     pc, lr                    // return

境界条件と2の累乗の追加チェックを追加できます。詳細については、http://www.idwiz.co.za/Tips%20and%20Tricks/Divide.htmをご覧ください。

于 2012-08-24T09:48:04.127 に答える
1

ARM GNUアセンブラ用に以下の関数を書きました。マシンをサポートする CPU がない場合はudiv/sdiv、関数の最初の数行を "0:" ラベルまで切り取ってください。

.arm
.cpu    cortex-a7
.syntax unified

.type   udiv,%function
.globl  udiv
udiv:   tst     r1,r1
        bne     0f
        udiv    r3,r0,r2
        mls     r1,r2,r3,r0
        mov     r0,r3
        bx      lr
0:      cmp     r1,r2
        movhs   r1,r2
        bxhs    lr
        mvn     r3,0
1:      adds    r0,r0
        adcs    r1,r1
        cmpcc   r1,r2
        subcs   r1,r2
        orrcs   r0,1
        lsls    r3,1
        bne     1b
        bx      lr
.size   udiv,.-udiv

.type   sdiv,%function
.globl  sdiv
sdiv:   teq     r1,r0,ASR 31
        bne     0f
        sdiv    r3,r0,r2
        mls     r1,r2,r3,r0
        mov     r0,r3
        bx      lr
0:      mov     r3,2
        adds    r0,r0
        and     r3,r3,r1,LSR 30
        adcs    r1,r1
        orr     r3,r3,r2,LSR 31
        movvs   r1,r2
        ldrvc   pc,[pc,r3,LSL 2]
        bx      lr
        .int    1f
        .int    3f
        .int    5f
        .int    11f
1:      cmp     r1,r2
        movge   r1,r2
        bxge    lr
        mvn     r3,1
2:      adds    r0,r0
        adcs    r1,r1
        cmpvc   r1,r2
        subge   r1,r2
        orrge   r0,1
        lsls    r3,1
        bne     2b
        bx      lr
3:      cmn     r1,r2
        movge   r1,r2
        bxge    lr
        mvn     r3,1
4:      adds    r0,r0
        adcs    r1,r1
        cmnvc   r1,r2
        addge   r1,r2
        orrge   r0,1
        lsls    r3,1
        bne     4b
        rsb     r0,0
        bx      lr
5:      cmn     r1,r2
        blt     6f
        tsteq   r0,r0
        bne     7f
6:      mov     r1,r2
        bx      lr
7:      mvn     r3,1
8:      adds    r0,r0
        adcs    r1,r1
        cmnvc   r1,r2
        blt     9f
        tsteq   r0,r3
        bne     10f
9:      add     r1,r2
        orr     r0,1
10:     lsls    r3,1
        bne     8b
        rsb     r0,0
        bx      lr
11:     cmp     r1,r2
        blt     12f
        tsteq   r0,r0
        bne     13f
12:     mov     r1,r2
        bx      lr
13:     mvn     r3,1
14:     adds    r0,r0
        adcs    r1,r1
        cmpvc   r1,r2
        blt     15f
        tsteq   r0,r3
        bne     16f
15:     sub     r1,r2
        orr     r0,1
16:     lsls    r3,1
        bne     14b
        bx      lr

udiv符号なし整数除算用と符号付き整数除算用の2 つの関数がありますsdivr1どちらも(上位ワード) と(下位ワード) で64 ビットの被除数 (符号付きまたは符号なし) を想定し、r0で 32 ビットの除数を想定していr2ます。これらは で商を返し、r0で余りを返します。したがって、 でそれらを64 ビット整数を返すように定義し、後で商と余りをマスクすることr1ができます。エラー (0 による除算またはオーバーフロー) は、除数の絶対値以上の絶対値を持つ剰余によって示されます。符号付き除算アルゴリズムは、被除数と除数の両方の符号による大文字と小文字の区別を使用します。すべてのオーバーフロー条件を適切に検出できないため、最初に正の整数に変換しません。C headerextern

于 2015-06-14T17:38:26.050 に答える