Forum: PC-Programmierung arrays miteinander addieren - verbesserungsvorschläge


von Felicitas (Gast)


Lesenswert?

guten abend,
ich wollte als übung für mich rechenarten (+-*/) für arrays 
implementieren.
das einfachste (die Addition) habe ich jetzt mal gemacht und wollte 
fragen was man besser machen kann

result ist noch static vorhanden (array mit 1024 elementen)
size ist die länge des arrays, welcher zur berechnung verwendet wurde
add1 ist array 1;
size1 ist länge von array 1;
add2 ist array 2;
size2 ist länge von array 2;
1
static uint8_t calcAdd(uint8_t* result, uint8_t* size, uint8_t* add1, uint8_t size1, uint8_t* add2, uint8_t size2)
2
{
3
    uint8_t temp1, temp2;
4
    uint8_t max = size1 > size2 ? (size1+1) : (size2+1);
5
    uint16_t temp;
6
    uint8_t overflow = 0;
7
    
8
    for(int8_t x=0; x<=max-2; x++)
9
    {
10
        temp1 = x < size1 ? add1[(size1-1) - x] : 0x00;
11
        temp2 = x < size2 ? add2[(size2-1) - x] : 0x00;
12
        temp = (uint16_t)temp1 + (uint16_t)temp2;
13
        result[(max-1) - x] = (uint8_t)(temp & 0xFF) + overflow;
14
        overflow = (uint8_t)(temp >> 8);
15
        printf(" 0x%02X, 0x%02X, 0x%02X\n", temp1, temp2, result[(max-1) - x]);
16
    }
17
18
    if(result[0] == 0x00)
19
    {
20
        memcpy(&result[0], &result[1], max);
21
        max--;
22
    }
23
24
    *size = max;
25
26
    printf("\n");
27
    return 1;
28
}

gebe ich z.B.
1
static uint8_t arr1[] = {0x22, 0x33, 0x44, 0xFF};
2
static uint8_t arr2[] = {0x22, 0x33, 0xFF};
in die Funktion ein, bekomme ich
{0x22, 0x55, 0x78, 0xFE} heraus.
Das passt.

von foobar (Gast)


Lesenswert?

- Der Overflow ist verkehrt, probier mal { 255, 255 } und { 0,1 }.
- Der letzte Overflow geht verloren.
- Der Schleifenindex ist zu klein.
- Du mischt signed/unsigned bei den Indizes mit falschem Ergebnis.
- Der memcpy ist undefiniert (darf nicht überlappen).
- "<" statt "<=" in for-Schleifen spart meistens +/-1-Korrekturen.
- Big-Endian ist kacke ;-)

von PittyJ (Gast)


Lesenswert?

Diese ganze + oder -1 Sache verwirrt nur. Da blickt keiner durch.

 max = size1 > size2 ? (size1+1) : (size2+1);
 result[(max-1) - x]

besser
max = .. size2 ..

und dann
for(int8_t x=0; x < max; x++)


Ansonsten hätte ich einen std::vector<uint8_t> benutzt.

von Achim M. (minifloat)


Lesenswert?

Felicitas schrieb:
> was man besser machen kann

Wenn man ("the user knows") die Größe der Eingangs-und Ausgangs-BigInt 
kennt und alle gleich macht, geht's einfacher.

foobar schrieb:
> Big-Endian ist kacke ;-)
Nein, mixed-Endian ist richtig kacke. Dass man BigInt in selber 
endianness wie die ausführende Maschine sortiert, dürfte einleuchten.

Man könnte allerdings versuchen, die Rechnungen in 16- oder 32-bit 
chunks vorzunehmen, sofern 16- oder 32-bit-Maschin'. Dann braucht es 
weniger Rechenschritte.

mfg mf

von Felicitas (Gast)


Lesenswert?

foobar schrieb:
> - Der Overflow ist verkehrt, probier mal { 255, 255 } und { 0,1 }.
> - Der letzte Overflow geht verloren.
> - Der Schleifenindex ist zu klein.
> - Du mischt signed/unsigned bei den Indizes mit falschem Ergebnis.
> - Der memcpy ist undefiniert (darf nicht überlappen).
> - "<" statt "<=" in for-Schleifen spart meistens +/-1-Korrekturen.

Joa, da war doch noch der ein oder andere Fehler drinne.
Das result array wurde komplett falschrum beschrieben

PittyJ schrieb:
> max = size1 > size2 ? (size1+1) : (size2+1);
>  result[(max-1) - x]
>
> besser
> max = .. size2 ..
>
> und dann
> for(int8_t x=0; x < max; x++)

Joa, dass passt besser

Achim M. schrieb:
> Man könnte allerdings versuchen, die Rechnungen in 16- oder 32-bit
> chunks vorzunehmen, sofern 16- oder 32-bit-Maschin'. Dann braucht es
> weniger Rechenschritte.

Das wollte ich zum schluss noch abändern. aber mit uint8_t kann ich es 
schneller mit Hand nachrechnen

momentan darf das Ergebnis halt nicht größer 1024 elemente haben. Aber 
das wollte ich auch zum schluss mit malloc versuchen zu umgehen. daher 
auch schonmal das size als rückgabewert um zu wissen wie groß das array 
letztendlich ist
1
static uint8_t calcAdd(uint8_t* result, uint16_t* size, uint8_t* add1, uint8_t size1, uint8_t* add2, uint8_t size2)
2
{
3
    uint8_t temp1, temp2;
4
    uint8_t max = size1 > size2 ? size1 : size2;
5
    uint16_t temp;
6
    uint8_t overflow = 0;
7
    
8
    for(uint8_t x=1; x<=max; x++)
9
    {
10
        temp1 = x <= size1 ? add1[size1 - x] : 0x00;
11
        temp2 = x <= size2 ? add2[size2 - x] : 0x00;
12
        temp = (uint16_t)temp1 + (uint16_t)temp2;
13
        result[1024 - x] = (uint8_t)(temp & 0xFF) + overflow;
14
        overflow = (uint8_t)(temp >> 8);
15
        printf(" 0x%02X, 0x%02X, 0x%02X\n", temp1, temp2, result[1024 - x]);
16
    }
17
    if(overflow)
18
    {
19
        result[1024 - max -1] = overflow;
20
    }
21
22
    *size = 1024;
23
24
    printf("\n");
25
    return 1;
26
}

von Jonas B. (jibi)


Lesenswert?

>Achim M. schrieb:
>> Man könnte allerdings versuchen, die Rechnungen in 16- oder 32-bit
>> chunks vorzunehmen, sofern 16- oder 32-bit-Maschin'. Dann braucht es
>> weniger Rechenschritte.

Ja und wenn der Prozessor halbwegs modern ist hat er ganz andere 
Erweiterungen (z.B. AVX-512), die noch viel mehr parallele Operationen 
ermöglichen. Die auszuschöpfen wäre mein Ziel... zur Übung kann man das 
schon so machen, ich würde mir allerdings erstmal eine Testbench bauen.

>aber mit uint8_t kann ich es schneller mit Hand nachrechnen

Du kannst 137 mal 229 im Kopf rechnen? Respekt. Ich denke doch du musst 
auch einen Taschenrechner benutzen, von daher ist doch vollkommen egal 
wie groß die Zahlen sind. Mit einer Testbench allerdings könntest du 
einen kompletten Test für 8 bit Wortbreite schnell schreiben und 
komplett testen lassen.

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.