Forum: Mikrocontroller und Digitale Elektronik PIC24H: 16x16-Multiplikation in C?!


von DJ T. (Gast)


Lesenswert?

Hallo Freunde,

ich steh gerade total auf dem Schlauch.
Und zwar möchte ich zwei 16-Bit-Signed-Zahlen zu einer 
32-Bit-Signed-Zahl multiplizieren.

In C sieht das so aus:
sint16_t a_s16;
sint16_t b_s16;
sint32_t c_s32;
c_s32 = a_s16 * b_s16;


Der C30-Compiler macht nun folgendes daraus:
mul.ss 0x0000, 0x0004, 0x0000
asr    0x0000, #15,    0x0002

Das heißt:
Der "mul.ss" berechnet das Ergebnis genau so, wie ich es haben will, mit 
dem Low-Wort in Register 0x0000 und dem High-Wort in Register 0x0002 
(das kann ich im Debugger so verifzieren).
Dann kommt aber der "asr"-Befehl und überschreibt mein High-Wort (in 
0x0002) mit dem Vorzeichenbit aus dem Low-Wort (in 0x0000).
Damit ist dann mein Ergebnis falsch, wenn es größer als ein sint16_t 
ist.

Okay, jetzt kann ich nachvollziehen, daß der Compiler das so macht, weil 
er zuerst die rechte Seite 16-Bit-breit berechnet und erst bei der 
Zuweisung auf 32-Bit erweitert.
Aber kann ich ihm denn nicht irgendwie sagen, daß er die Erweiterung 
lassen soll?

Die Variante
c_s32 = (sint32)a_s16 * (sint32)b_s16;
rechnet zwar korrekt, aber auch komplett 32-Bit-breit, d.h. ich hab im 
Assemblercode 4 mul-Befehle, was ich vermeiden will.

Grüße,

Dosmo

von Anja (Gast)


Lesenswert?

Sebastian F. schrieb:
> In C sieht das so aus:

Das entspricht aber nicht der C Sprachkonvention. Auch wenn Du dir das 
wünscht.

In C hat das Ergebnis denselben Datentyp wie der größere der beiden 
Operanden.

Gruß Anja

von Ralf (Gast)


Lesenswert?

Wie steht's mit:
1
c_s32 = (sint32)(a_s16 * b_s16);
bzw.
1
c_s32 = (sint32)a_s16 * b_s16;

Kommt da auch das gleiche raus?

Ralf

von (prx) A. K. (prx)


Lesenswert?

Probier ggf. mal sowas wie:
1
static inline long mulss(int a, int b)
2
{
3
    long result;
4
    asm ("mul.ss %1, %2, %0" : "=r"(result) : "r"(a), "r"(b) : "cc");
5
    return result:
6
}
Ungetestet.

von DJ T. (Gast)


Lesenswert?

Hallo,

ich hab inzwischen noch was heraus gefunden:

1. Manche C-Compiler verstehen das Konstrukt
c_s32 = (sint32)(sint16)a_s16 * (sint32)(sint16)b_s16;

2. Mein C30-Comiler hat eine spezielle Intrinsic-Funktion dafür:
__builtin_mulss

Anscheinend kann man das Problem in Standard-C nicht lösen.

Grüße,

Dosmo


@Ralf:
c_s32 = (sint32)(a_s16 * b_s16);
c_s32 = (sint32)a_s16 * b_s16;
-> ergeben beide volle 32Bit-Multiplikation mit 4 mul-Befehlen

von (prx) A. K. (prx)


Lesenswert?

Sebastian F. schrieb:

> Anscheinend kann man das Problem in Standard-C nicht lösen.

Korrekt.

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.