C positive Ausgabe erzwingen

Benni22

Commander
Registriert
Juni 2008
Beiträge
3.021
Guten Tag!

Ich habe ein Problem bei meinem Dezimal->Binär Rechner. Die Ausgabewerte sind richtig jedoch werden bei negativen Zahlen jede Binär 1 als -1 geschrieben. Kann ich irgendwie erzwingen, dass das -1 als 1 ausgegeben wird?

Code:
#include <stdio.h>

int main()
{
    int a, b[16];
    printf ("\nEingabe einer Dezimalzahl: ");   
    scanf ("%d", &a);                      
    
    for (int i = 0, c = a;i<=15;i++)      
    {                                   
        b[i] = c % 2;                      
        c >>= 1;                                
    }
    printf ("\nDer Wert von %d ist ", a);         
    for(int i = 15; i >= 0; --i)                 
        printf ("%d", b[i]);
    printf (" in binär.\n");
}
 
Code:
if(wert < 0) wert *= -1
 
Wenn ich das eingebe, dann wirft der Compiler mir einen Fehler raus. Hab ich gerade eine Tomate vor den Augen und bin einfach an der falschen Stelle oder hab ich was falsches eingegeben?

Code:
    printf ("\nDer Wert von %d ist ", a);     
    for(int i = 15; i >= 0; --i)                  
        if(b[i]<0 b[i]*=-1);
        printf ("%d", b[i]);
    printf (" in binär.\n");
}
 
Code:
if(b[i]<0 b[i]*=-1);

Funktioniert nicht. Entweder:

Code:
if(b[i]<0) b[i]*=-1;

Oder etwas verständlicher:

Code:
if(b[i]<0) {
   b[i] = b[i] * -1;
}
 
Zuletzt bearbeitet:
Die abschließende Klammer der if Abfrage ist zu weit hinter gerutscht...
 
Vielen Dank, jetzt funktioniert es wie es soll. (Auch wenn es eigentlich etwas gepfuscht ist. ;))
 
Code:
for(int i = 15; i >= 0; --i)                  
        if(b[i]<0 b[i]*=-1);
        printf ("%d", b[i]);

Hier haste dir selbst eine Falle gestellt. Passiert relativ häufig, wenn man nicht aufpasst. Tipp: geschweifte Klammern.
 
:evillol: oder so:
Code:
    ...
    printf ("\nDer Wert von %d ist ", a);         
    for(int i = 15; i >= 0; --i)                 
         printf ("%d", ((b[i]==0)?(0):(1)));
    printf (" in binär.\n");
}
 
Zuletzt bearbeitet: (update)
nen tip für die zukunft:
statt
Code:
b[i] = c % 2;

ist hier
Code:
b[i] = c & 1;

DEUTLICH billiger. du willst ja wissen was das erste bit ist.

% (module) führt eine division durch und die ist wesentlich teurer als eine und-operation &.
das spielt hier ja zwar keine rolle, aber das zu wissen schadet auch nicht.
 
Code:
asdf@chelloveck:/home/asdf/src$ cat modulo.c && echo --- && gcc -c -S -o modulo.s modulo.c && cat modulo.s
int i = 200 % 2;
---
        .file   "modulo.c"
.globl i
        .bss
        .align 4
        .type   i, @object
        .size   i, 4
i:
        .zero   4
        .ident  "GCC: (Debian 4.4.5-8) 4.4.5"
        .section        .note.GNU-stack,"",@progbits
Code:
asdf@chelloveck:/home/asdf/src$ cat binary.c && echo --- && gcc -c -S -o binary.s binary.c && cat binary.s
int i = 200 & 1;
---
        .file   "binary.c"
.globl i
        .bss
        .align 4
        .type   i, @object
        .size   i, 4
i:
        .zero   4
        .ident  "GCC: (Debian 4.4.5-8) 4.4.5"
        .section        .note.GNU-stack,"",@progbits

€: Ja sorry ich weiß. cat-Missbrauch. Aber ich wollte es schön zum C/P haben, da ging less nicht so gut.
 
Zuletzt bearbeitet:
Was ich auf jedenfall noch erwähnen wollte: In der Standardbibliothek gibt eine Funktion, die den Absolutbetrag einer Funktion zurückgibt: std::abs
Also statt selber irgendwas zu basteln mit if(wert <0) wert*= -1 lieber std::abs verwenden. Nicht weil es irgendwie schneller wäre, sondern weil so im Programmcode drin steht, was du haben willst, nämlich den Absolutbetrag. Quasi Dokumentation und Funktion in einem!
Code:
int pos_abs(int wert)
{
  if(wert < 0)
     return wert *-1;
   return wert;
}
oder dem Aufruf von std::abs ensteht in beiden Fällen:
Code:
movl %eax
sarl %$31, %edx
xorl %edx, %eax
subl %edx
(mit -O2 kompiliert). Für die nicht Assemblerleser unter uns: Der Programmcode hat mit der Funktion quasi gar nichts zu tun ;-) Branches sind böse, aber der gcc ist so gut, das er das in Quellcode umsetzen kann ganz ohne if's.

Der Vollständigkeit halber: Der von asdfman gepostete Assemblercode enthält keinerlei Programmcode, da das Ergebnis in beiden Fällen bereits zur Kompilationszeit feststeht - und der gcc das dann auch einfach ausrechnet und nur das Ergebnis in die Objectdatei schreibt. Also eine denkbar schlechte Methode beide Varianten zu vergleichen... Methodiktipp: Pack immer alles in eine Funktion, wenn du sowas machen willst. Bspw:
Code:
int modulo(int wert)
{
  return wert % 2;
}
Der Kompiler weiß nämlich nicht, ob die Funktion von einer anderne Objectdatei aufgerufen wird, weswegen er das ganze nicht wegoptimiert! (Deswegen auf keinenfall linken und kompilieren zusammen erledigen, dann riecht er den Braten!)

Ich hab das auch mal gemacht und hier auf's wesentliche zusammengekürzt:
Mit Modulo
Code:
movl %eax, %edx
shrl $31, %edx
addl %edx, %eax
andl $1, %eax
subl %edxm %eax
bzw. mit UND
Code:
andl $1, %eax
(beide mit -O2 kompiliert). Ich muss aber dazu erwähnen, das ich nur die Zeile mit der Berechnung selbst kompiliert habe. Evtl. kann der Compiler mehr optimieren, wenn er mehr weiß. Könnte also sein, dass das eigentliche in diesem Thread geschilderte Problem weiter optimiert wird.

Und ganz zum Schluß: Bei den iostreams kann man sich Zahlen auch direkt binär ausgeben lassen, aber da ich denke das es irgendeine Form von Hausaufgabe ist, ist die Möglichkeit nicht so geeignet ;-)
 
Zuletzt bearbeitet:
geisterfahrer schrieb:
Was ich auf jedenfall noch erwähnen wollte: In der Standardbibliothek gibt eine Funktion, die den Absolutbetrag einer Funktion zurückgibt: std::abs

Allerdings heißt sie in C einfach nur abs.
 
Du könntest auch einfach eine gerade Potenz bilden und dann die Wurzel ziehen... (Die Wurzel fällt aber bei der 1 weg)
In Scheme:
Code:
(sqrt (lambda (x) (* x x) [HIER DEINE ZAHL]))

Ist also relativ einfach immer eine positive Zahl zu bekommen.
 
Zurück
Oben