Forum: PC-Programmierung Square-and-Multiply in C


von Dennis S. (eltio)


Lesenswert?

Hallo zusammen,

ich möchte den Square-and-Multiply-Algorithmus in C implementieren. 
Allerdings habe ich schon einen Fehler bei dem "Durchlaufen" der 
einzelnen Bits des Exponenten ab dem MSB (ab LSB ist kein Problem). Hier 
ist der Code:
1
#include <stdio.h>
2
#include <stdint.h>
3
4
uint32_t binary_exp( uint32_t x, uint32_t b)
5
{
6
    uint32_t res = 1;
7
    
8
    for( int i=31; i>=0; --i )
9
    {
10
        res = res * res;
11
        if( (b & (1<<i)) == 1)
12
        {
13
            res = res*x;
14
        }
15
        printf( "i: %2d \t (1<<i): %2d\n", i, (1<<i) );
16
    }
17
    return res;
18
}
19
20
int main( void )
21
{
22
    printf( "3 hoch 9: %d", binary_exp( 3U, 9U ) );
23
    return 0;
24
}

Und hier die Ausgabe auf der Konsole. Wieso ist das Bit 31 negativ?
1
i: 31    (1<<i): -2147483648
2
i: 30    (1<<i): 1073741824
3
i: 29    (1<<i): 536870912
4
i: 28    (1<<i): 268435456
5
i: 27    (1<<i): 134217728
6
i: 26    (1<<i): 67108864
7
i: 25    (1<<i): 33554432
8
i: 24    (1<<i): 16777216
9
i: 23    (1<<i): 8388608
10
i: 22    (1<<i): 4194304
11
i: 21    (1<<i): 2097152
12
i: 20    (1<<i): 1048576
13
i: 19    (1<<i): 524288
14
i: 18    (1<<i): 262144
15
i: 17    (1<<i): 131072
16
i: 16    (1<<i): 65536
17
i: 15    (1<<i): 32768
18
i: 14    (1<<i): 16384
19
i: 13    (1<<i): 8192
20
i: 12    (1<<i): 4096
21
i: 11    (1<<i): 2048
22
i: 10    (1<<i): 1024
23
i:  9    (1<<i): 512
24
i:  8    (1<<i): 256
25
i:  7    (1<<i): 128
26
i:  6    (1<<i): 64
27
i:  5    (1<<i): 32
28
i:  4    (1<<i): 16
29
i:  3    (1<<i):  8
30
i:  2    (1<<i):  4
31
i:  1    (1<<i):  2
32
i:  0    (1<<i):  1
33
3 hoch 9: 3

Gruß
Dennis

von TriHexagon (Gast)


Lesenswert?

Printf interpretiert deine Eingaben als signed integer (%d). Für 
unsigned integer musst du %u verwenden.

https://de.wikibooks.org/wiki/C-Programmierung:_Einfache_Ein-_und_Ausgabe#Formatelemente_von_printf

von Dennis S. (eltio)


Lesenswert?

TriHexagon schrieb:
> Printf interpretiert deine Eingaben als signed integer (%d). Für
> unsigned integer musst du %u verwenden.
>
> https://de.wikibooks.org/wiki/C-Programmierung:_Ei...

Oh wie bedauerlich! Daran habe ich nicht gedacht... Vielen Dank!

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dennis S. schrieb:

> ab LSB ist kein Problem

Warum verwendest du nicht die Version ab LSB?  Du brauchst nur Bit 0 des 
Exponenten zu testen und den Exponenten in jedem Durchlauf nach rechts 
zu schieben bis er 0 ist:
1
#include <stdint.h>
2
3
uint32_t binary_exp (uint32_t x, uint32_t b)
4
{
5
    uint32_t res = 1;
6
    
7
    while (b)
8
    {
9
        if (b & 1)
10
            res *= x;
11
12
        x *= x;
13
        b >>= 1;
14
    }
15
    return res;
16
}

>         if( (b & (1<<i)) == 1)

Für i = 31 ergibt das einen Signed Overflow ergo Undefined Behavior. 
Daher schiebt man für solche Masken niemals 1 sondern immer 1u.

>         if (1 == (b & (1u << i)))

von Dennis S. (eltio)


Lesenswert?

Johann L. schrieb:
> Warum verwendest du nicht die Version ab LSB?  Du brauchst nur Bit 0 des
> Exponenten zu testen und den Exponenten in jedem Durchlauf nach rechts
> zu schieben bis er 0 ist:

Das war der erste Schuss der Implementierung und ich habe mir noch keine 
Gedanken gemacht ob es für den Algorithmus egal ist von wo aus ich 
anfange... aber es scheint ja wirklich keine Rolle zu spielen!?

Johann L. schrieb:
> Für i = 31 ergibt das einen Signed Overflow ergo Undefined Behavior.
> Daher schiebt man für solche Masken niemals 1 sondern immer 1u.

Habe ich in meiner Version schon geändert. Übrigens mit einem großen U, 
wie in den MISRA-Regeln empfohlen. ;-)

Gruß
Dennis

von Eric B. (beric)


Lesenswert?

Dennis S. schrieb:
> if( (b & (1<<i)) == 1)

b & (1 << i) wird nur 1 wenn i == 0. Das ist nicht was du willst/meinst:
1
 if (b & (1u << i))
oder
1
 if ((b & (1u << i)) != 0)
soll funktionieren

: Bearbeitet durch User
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.