[Absoluter Beginner] ganze Zahl in Zweierkomplement

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
SSV1948
User
Beiträge: 1
Registriert: Donnerstag 1. November 2012, 20:32

Guten Abend werte Forum-Gemeinde,

ich bin gerade dabei die Grundzüge von Python zu erlernen.
Und zwar beschäftige ich mich gerade mit der Aufgabe eine ganze Zahl (z.B. 41) in 16 Bits (4 Halbbits; also getrennt durch Punkt) darzustellen.

Ich hab die docs durchsucht (http://docs.python.org/release/2.7.3/), jedoch keine Funktion gefunden, die mir da behilflich bei sein könnte.
Hat jemand einen Ratschlag wie ich dieses Problem angehen könnte?

Zu Beginn muss ich natürlich die Zahl einlesen. So viel ist mir schon mal klar.

Code: Alles auswählen

zahl = int(raw_input("Zahl: "))
Im Anschluss stelle ich mir eine for-Schleife vor. Doch dann hört es schon auf mit meinen Ideen :/

Hätte jemand einen Vorschlag wie ich an dieses Problem herantreten kann?

Danke,
Sven
BlackJack

@SSV1948: Deine Frage ist komplett wirr und inverständlich. Wenn ich mal nur ganze Zahl und 16 Bits nehme, dann geht es noch. Da könnte ich mir vorstellen, dass Du die Zahl mit Binärziffern darstellen möchtest. Aber 4 Halbbits, getrennt durch Punkt‽ Was ist denn bitte ein halbes Bit? Und was willst Du durch Punkte trennen? In der Betreffzeile kommt noch das Wort Zweierkomplement vor, also willst Du auch negative Zahlen darstellen?

Habt ihr zu der Hausaufgabe keine Hinweise bekommen? Bitoperationen wie Verknüpfungen und Schiebeoperationen sind hier wichtig. Dafür gibt es Operatoren in Python. Einfach mal in der Dokumentation schauen. Für's grössere Bild gibt es ganz sicher Wikipedia-Artikel zu Zahlendarstellungen, Zweierkomplement & Co.

Und pass auf, dass der Quelltext nicht auch zu so einem gruseligen Deutsch/Englisch-Gemisch wird wie das in den eckigen Klammern in der Betreffzeile. ;-)
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Er wird sehr wahrscheinlich Halbbytes gemeint haben, nicht Halbbits...
BlackJack

Also nur zum Verständnis, die Ausgabe soll so aussehen wie folgendes DOS Programm in Assembler, das die Zahl, welche am Anfang in das `bx`-Register geladen wird, als Binärzeichenkette ausgibt‽

Code: Alles auswählen

;  nasm -f bin -o test.com test.asm
    cpu 8086
    org 100h

;--------------------------------------
segment .text

    mov bx, 42
    mov cx, 15
    mov di, binary
convert_loop:
    mov al, 0
    shl bx, 1
    adc al, '0'
    stosb
    
    or cl, cl
    jz no_point
    mov al, cl
    and al, 00000011b
    jnz no_point
    mov al, '.'
    stosb
no_point:

    dec cx
    jns convert_loop
    
    mov al, 0
    stosb
    
    mov si, binary
print_loop:
    lodsb
    cmp al, 0
    jz exit_print_loop
    mov ah, 0eh
    int 10h
    jmp short print_loop
exit_print_loop:
    
    ret

;--------------------------------------
segment .bss
binary:
    resb 16 + 4 + 1     ; digits, dots, and terminating zero.
Ausgabe:

Code: Alles auswählen

C:\>d:test
0000.0000.0010.1010
C:\>
Edit: Hinweis von Sirius3 gefolgt und ``bt`` durch ``shl`` ersetzt. Jetzt läuft's auch auf 'nem 8086. :-)
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo BlackJack,

Code: Alles auswählen

bt bx,cx
schließt unnötigerweise 8086er und 80286er Prozessoren aus. Ich würde ihn durch

Code: Alles auswählen

shl bx,1
ersetzen.

Grüße
Sirius
Benutzeravatar
pyFan
User
Beiträge: 22
Registriert: Sonntag 4. Januar 2009, 15:44

Hallo SSV1948,

die Lösung in Assembler ist wohl nicht das, was du gesucht hast.
Ich poste mal eine Lösung, obwohl das hier im Forum ja nicht gerne gesehen wird.
Die Funktion testet aber nicht den Wertebereich und macht darum Fehler.
die wichtigsten Funktionen, die man braucht sind wohl bin() und zfill().

Gruss

pyFan

Code: Alles auswählen

# Python 2.7

def binstring16(zahl):
    # wandle die Zahl in einen String aus Nullen und Einsen
    string1=bin(zahl)
    # die ersten beiden Zeichen brauchen wir nicht ('0x') -> abschneiden
    string2=string1[2:]
    # fülle den String linksbündig mit Nullen auf (16 Bits)
    string3=string2.zfill(16)
    # erzeuge einen String mit einem Punkt nach jedem Halbbyte
    string4=string3[:4]+'.'+string3[4:8]+'.'+string3[8:12]+'.'+string3[12:]
    return string4

# Test
print binstring16(0)
print binstring16(32768*2-2)
print binstring16(2**10)     # 1024
print binstring16(32768*2+1) # ups
BlackJack

@pyFan: Mit negativen Zahlen kann es auch nicht umgehen, und das sollte es laut Betreffzeile:

Code: Alles auswählen

In [4]: binstring16(-42)
Out[4]: '0000.0000.0b10.1010'
`bin()` ist nicht so geeignet, insbesondere weil die Aufgabe sich danach anhört, als sollte man sich mit Operationen auf einzelnen Bits beschäftigen. Bei -42 sollte das Ergebnis kommen, was dieses C-Programm liefert:

Code: Alles auswählen

#include <inttypes.h>
#include <stdio.h>

#ifndef __CC65__
    #define __fastcall__
#endif

char* __fastcall__ int16_to_bitstring(uint16_t value, char *result)
{
    uint8_t i;
    uint16_t mask;

    for (i = 0, mask = 1 << 15; mask; ++i, mask >>= 1) {
        result[i] = ((value & mask) != 0) | '0';
        if ((mask & ~0x1110) != mask) result[1 + i++] = '.';
    }
    result[i] = '\0';
    return result;
}

int main(void)
{
    char result[16 + 4 + 1];
    
    puts(int16_to_bitstring(-42, result));
    
    return 0;
}
Nämlich: 1111.1111.1101.0110
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@BlackJack:

Nur interessehalber: Was genau prüft `(mask & ~0x1110) != mask`?

Also schon klar, dass du wahrscheinlich ermitteln willst, ob wir am Ende einer Vierergruppe sind, aber wie läuft das technisch ab? Insbesondere im Hinblick auf `~0x1110`. Da verstehe ich den Zusammenhang nicht. :(

Hinweis: Bitte nicht ausholen, wie man rechnerisch von Dezimal auf Dual kommt oder wie die Operationen auf die Bitmaske in der Zeile darüber ablaufen. Ganz so unbedarft bin ich nicht... ;)
BlackJack

@snafu: `mask` enthält ja das „wandernde Testbit” und mit dem Audruck versuche ich es an der jeweils vierten Stelle eines Nibbles zu löschen — ausser beim letzten Nibble. Wenn man es löschen konnte, dann war es an einer Stelle wo ein Punkt ausgegeben werden soll.

Vielleicht doch mal die Binärdarstellung mit Leerzeichen zwischen den Nibbles:

Code: Alles auswählen

0x1110  = 0001 0001 0001 0000
~0x1110 = 1110 1110 1110 1111
Und jetzt kann man sich überlegen was passiert wenn das Bit in `mask` an einer der Stellen ist an der eine 1 steht und was wenn es an einer ist wo 0 steht.
BlackJack

Ich konnt's mir nicht verkneifen es auch noch mal für meinen Lieblingsrechner in BASIC zu schreiben:

Code: Alles auswählen

   10 INPUT"ZAHL";V:FOR I=15 TO 0 STEP -1:M=2↑I:IF I=15 THEN M=-M
   20 PRINT CHR$(49+((V AND M)=0));:IF I>0 AND (I AND 3)=0 THEN PRINT".";
   30 NEXT:PRINT:GOTO 10
Testlauf:

Code: Alles auswählen

RUN
ZAHL? 42
0000.0000.0010.1010
ZAHL? -42
1111.1111.1101.0110
ZAHL? 1337
0000.0101.0011.1001
ZAHL? -4711
1110.1101.1001.1001
ZAHL? -1
1111.1111.1111.1111
ZAHL? 0
0000.0000.0000.0000
ZAHL? 1
0000.0000.0000.0001
ZAHL? -21846
1010.1010.1010.1010
ZAHL? 21845
0101.0101.0101.0101
Antworten