Forum: Mikrocontroller und Digitale Elektronik 16x16 signed Multiplikation


von crazy horse (Gast)


Lesenswert?

int16 FIX_MPY(int16 a, int16 b)
{
  // shift right one less bit
  int32 c = ((int32)a * (int32)b) >> 14;
  // last bit shifted out = rounding-bit
  b = c & 0x01;
  // last shift + rounding bit
  a = (c >> 1) + b;
  return a;
}

Gibts da Optimierungspotential? Die Routine wird sehr oft (16384 mal pro 
Berechnung) aufgerufen, wenn man da noch was machen könnte, ich bin in 
Zeitnot :-)
Ist für einen M16, und auf die Rundung kann ich nicht verzichten.
Ich sehe nichts mehr.

von Ralf (Gast)


Lesenswert?

Hallo,

du könntest die Multiplikation vom HW-Multiplizierer ausführen lassen. 
Normalerweise sollte sich unter den intrinsics was finden lassen.

Dann würde ich wahrscheinlich zwei mal nach links schieben und das 
Hiword nehmen. Mir ist z.B. beim IAR Compiler mal aufgefallen, dass der 
Compiler wirklich 14 mal schiebt in solchen Fällen (hängt wahrscheinlich 
von der Optimierungsstufe ab). Zwei mal schieben und dann ein mov.w ist 
da schon etwas schneller.
Kannst Du die Funktion evtl. als inline Funktion verwenden?

Viele Grüße,
Ralf

von crazy horse (Gast)


Lesenswert?

;## #  FUNCTION FIX_MPY
;## #  FRAME  AUTO  ( __PAD11)  size  1,  offset -1
;## #  REGISTER ARG    (       a)   size   2,   REGISTER R1
;## #  REGISTER ARG    (       b)   size   2,   REGISTER R2
;## #  ARG Size(0)  Auto Size(1)  Context Size(5)

  ._type  307,'x',269,2
  ._type  307,'m','a',0,269
  ._type  307,'m','b',0,269
  ._func  'FIX_MPY','G',1,307,$FIX_MPY,0
  ._inspect  'F', 's', "FIX_MPY", "$FIX_MPY", 'G', 6
  .align
  ._line  303
;## # C_SRC :  {
  .glb  $FIX_MPY
$FIX_MPY:
  enter  #01H
  ._block
  ._var  'a','A',269,0
  ._var  'b','A',269,0
  ._var  'c','A',292,0
  ._line  305
;## # C_SRC :    int32 c = ((int32)a * (int32)b) >> 14;
  ._block
  ._var  'a','R',269,6
  ._var  'b','R',269,7
  mul.w  R2,R1  ;  b
  ._eblock
  sha.l  #-8H,R3R1
  sha.l  #-6,R3R1
  ._line  307
;## # C_SRC :    b = c & 0x01;
  mov.w  R1,R0
  and.w  #0001H,R0  ;  b
  ._block
  ._var  'b','R',269,5
  ._line  309
;## # C_SRC :    a = (c >> 1) + b;
  sha.l  #-1,R3R1
  add.w  R1,R0  ;  a
  ._eblock
  ._block
  ._var  'a','R',269,5
  ._line  312
;## # C_SRC :    return a;
  ._eblock
  exitd

das der Auszug aus dem listing. Scheint genauso gemacht, wie du 
vorgeschlagen hast, schade.
Trotzdem vielen Dank.

von Bertrik S. (bertrik)


Lesenswert?

What is the exact purpose of your code? Knowing that can help to 
optimise.

By shifting right by 14 places, you are throwing away a lot of 
information. Maybe you can find a way to figure out how to not calculate 
those bits in the first place. As far as I understand, even many 
hardware multipliers have a variable execution time that increases with 
the number of non-zero bits.

The following code is a little simpler and should be equivalent to 
yours:
int16 FIX_MPY(int16 a, int16 b)
{
  // shift right one less bit
  int32 c = ((int32)a * (int32)b) >> 14;
  // round it
  return ((c + 1) >> 1);
}

von crazy horse (Gast)


Lesenswert?

Thanks for the idea!

int16 FIX_MPY(int16 a, int16 b)
{
        int32 c = ((int32)a * (int32)b + (1<<14)) >> 15;
  return c;

}

Irgendwie geht immer noch was :-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.