www.vorkurse.de
Ein Projekt von vorhilfe.de
Die Online-Kurse der Vorhilfe

E-Learning leicht gemacht.
Hallo Gast!einloggen | registrieren ]
Startseite · Mitglieder · Teams · Forum · Wissen · Kurse · Impressum
Forenbaum
^ Forenbaum
Status Mathe-Vorkurse
  Status Organisatorisches
  Status Schule
    Status Wiederholung Algebra
    Status Einführung Analysis
    Status Einführung Analytisc
    Status VK 21: Mathematik 6.
    Status VK 37: Kurvendiskussionen
    Status VK Abivorbereitungen
  Status Universität
    Status Lerngruppe LinAlg
    Status VK 13 Analysis I FH
    Status Algebra 2006
    Status VK 22: Algebra 2007
    Status GruMiHH 06
    Status VK 58: Algebra 1
    Status VK 59: Lineare Algebra
    Status VK 60: Analysis
    Status Wahrscheinlichkeitst

Gezeigt werden alle Foren bis zur Tiefe 2

Navigation
 Startseite...
 Neuerdings beta neu
 Forum...
 vorwissen...
 vorkurse...
 Werkzeuge...
 Nachhilfevermittlung beta...
 Online-Spiele beta
 Suchen
 Verein...
 Impressum
Das Projekt
Server und Internetanbindung werden durch Spenden finanziert.
Organisiert wird das Projekt von unserem Koordinatorenteam.
Hunderte Mitglieder helfen ehrenamtlich in unseren moderierten Foren.
Anbieter der Seite ist der gemeinnützige Verein "Vorhilfe.de e.V.".
Partnerseiten
Weitere Fächer:

Open Source FunktionenplotterFunkyPlot: Kostenloser und quelloffener Funktionenplotter für Linux und andere Betriebssysteme
Forum "C/C++" - Mantisse,Exponent,Vorzeichen
Mantisse,Exponent,Vorzeichen < C/C++ < Programmiersprachen < Praxis < Informatik < Vorhilfe
Ansicht: [ geschachtelt ] | ^ Forum "C/C++"  | ^^ Alle Foren  | ^ Forenbaum  | Materialien

Mantisse,Exponent,Vorzeichen: Frage (beantwortet)
Status: (Frage) beantwortet Status 
Datum: 22:32 Fr 27.10.2006
Autor: Fabian

Hallo,

ich habe hier die Musterlösung von einem Programm. Diese versuche ich gerade nachzuvollziehen. Leider ist mir nicht alles klar.

PS: Den Zeilenumbruch mußte ich umwandeln zu \ n , da ansonsten der Formeleditor Schwierigkeiten macht.


/* Erstellen Sie ein Programm, das
   eine Zahl vom Typ double einliest
   und die Werte für Vorzeichen, Exponent
   und Mantisse auf dem Bildschirm ausgibt.
   Vorzeichen als 0 oder 1,
   Exponent als Dezimalzahl und
   Mantisse als Bitmuster.
  
   Beachte: double ist 64 bit
            Wert 1 ist vom Typ int
*/

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
     double wert;
     unsigned long long *ptr, zahl, maske;
     int i, exp;
    
     printf("Zahl eingeben: ");
     scanf("%lf", &wert);
    
// Bis hier hin ist mir alles klar

     ptr = (unsigned long long *) &wert;

Hier wird die Adresse der Variablen wert , der Pointer-Variablen ptr zugewiesen. Wofür steht nun das (unsigned long long *) ???

     zahl = *ptr;



     maske = (unsigned long long) 1 << 63;

// Diese Zeile verstehe ich überhaupt nicht!
    



printf("Vorzeichen    : ");


     if (maske & zahl){
         printf("1");      Das ist klar!
     } else {
         printf("0");  
     }

Ab jetzt versteh ich nur noch Bruchstücke!

     printf("\ nExponent    : ");
     exp = 0;
     for (i=0; i<11; i++){
         maske >>= 1;

Hier handelt es sich um eine bitweise Verschiebung nach rechts! Aber ich versteh den Zusammenhang nicht!

         exp <<= 1;
         if (maske & zahl){
             exp++;      
         }
     }
     exp -= 1023;
     printf("%d\ nMatisse       : ", exp);
     for (i=0; i<52; i++){
         maske >>= 1;
         if (maske & zahl){
             printf("1");      
         } else {
             printf("0");  
         }
     }
     printf("\ n");
  
  system("PAUSE");
  return 0;
}

Ich wäre euch unendlich dankbar, wenn jemand das Programm ein wenig kommentieren könnte.

Hier noch mal das ganze Programm ohne Kommentare:

/* Erstellen Sie ein Programm, das
   eine Zahl vom Typ double einliest
   und die Werte für Vorzeichen, Exponent
   und Mantisse auf dem Bildschirm ausgibt.
   Vorzeichen als 0 oder 1,
   Exponent als Dezimalzahl und
   Mantisse als Bitmuster.
  
   Beachte: double ist 64 bit
            Wert 1 ist vom Typ int
*/

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
     double wert;
     unsigned long long *ptr, zahl, maske;
     int i, exp;
    
     printf("Zahl eingeben: ");
     scanf("%lf", &wert);
    
     ptr = (unsigned long long *) &wert;
     zahl = *ptr;
     maske = (unsigned long long) 1 << 63;
     printf("Vorzeichen    : ");
     if (maske & zahl){
         printf("1");      
     } else {
         printf("0");  
     }
     printf("\ nExponent    : ");
     exp = 0;
     for (i=0; i<11; i++){
         maske >>= 1;
         exp <<= 1;
         if (maske & zahl){
             exp++;      
         }
     }
     exp -= 1023;
     printf("%d\ nMatisse       : ", exp);
     for (i=0; i<52; i++){
         maske >>= 1;
         if (maske & zahl){
             printf("1");      
         } else {
             printf("0");  
         }
     }
     printf("\ n");
  
  system("PAUSE");
  return 0;
}

Vielen Dank für eure Antworten! Ich hoffe, ihr kommt mit der Darstellung des Programms klar!

Viele Grüße

Fabian



        
Bezug
Mantisse,Exponent,Vorzeichen: Antwort
Status: (Antwort) fertig Status 
Datum: 01:19 Sa 28.10.2006
Autor: Frank05


> Hallo,

Hallo,


> Beachte: double ist 64 bit
>              Wert 1 ist vom Typ int
>       double wert;
>       unsigned long long *ptr, zahl, maske;

> ptr = (unsigned long long *) &wert;
>  
> Hier wird die Adresse der Variablen wert , der
> Pointer-Variablen ptr zugewiesen. Wofür steht nun das
> (unsigned long long *) ???

Das ist nötig, da wert vom Typ double ist und &wert zeigt somit auf einen double, ist also vom Typ double*. Der Witz an dem Programm ist aber gerade, dass man den Wert, der im Speicher steht nicht mehr als double gemäß IEEE754[1] interpretiert, sondern als einen 64bit Integer (und später dann eben auf eine entsprechende Bitmaske dieses Integers, was im IEEE754 als Mantisse bzw. Exponent interpretiert wird).

> zahl = *ptr;

Hier findet nun diese Umwandlung in einen Integer statt.

> maske = (unsigned long long) 1 << 63;
>
> // Diese Zeile verstehe ich überhaupt nicht!

Ich nehme an, dass du mit dem Binärsystem vertraut bist (sonst google mal kurz oder schau auf wikipedia nach). 1 << 63 ist nun die Zahl 1 (Binär: 0000000000...00001) wobei die Binärdarstellung um 63 Stellen nach links verschoben wird. Es kommt also 100000...000 mit 63 Nullen raus. Wichtig zu wissen ist hier, dass IEEE754 das erste/höchstwertige der 64Bit eines double als Vorzeichen ansieht. Und genau dieses Bit ist in der Variable maske jetzt auf 1 gesetzt, während alle anderen auf 0 gesetzt sind.

> if (maske & zahl){
>           printf("1");      Das ist klar!
>       } else {
>           printf("0");  
> }

Statt printf("1"); kannst du dir hier auch printf("+"); vorstellen. maske&zahl filtert jetzt eben gerade das Vorzeichenbit heraus.

> Ab jetzt versteh ich nur noch Bruchstücke!

Nachdem du nun weißt wie diese maske funktioniert sollte klar sein, was maske>>1 macht: das maskierte Bit wird um eine Stelle nach rechts verschoben. Mit maske&zahl wird dann wieder bestimmt, ob in dem double wert dieses Bit auf 1 oder 0 gesetzt ist. Jetzt musst du nur noch nachsehen, wieviele Bits IEEE754 für Exponent und Mantisse vorsieht und wie die jeweiligen Werte an diesen Bits interpretiert werden (dabei wirst du zB feststellen, warum die for-Schleifen gerade solange laufen).

Ich hoffe damit kommst du jetzt beim Verständnis des Programms weiter.

[1] []IEE754

Bezug
                
Bezug
Mantisse,Exponent,Vorzeichen: Frage (beantwortet)
Status: (Frage) beantwortet Status 
Datum: 12:36 Sa 28.10.2006
Autor: Fabian

Hallo Frank,

erstmal Danke für deine Antwort! Leider versteh ich noch nicht alles :-(


> > Beachte: double ist 64 bit
>  >              Wert 1 ist vom Typ int
>  >       double wert;
>  >       unsigned long long *ptr, zahl, maske;
>  
> > ptr = (unsigned long long *) &wert;
>  >  
> > Hier wird die Adresse der Variablen wert , der
> > Pointer-Variablen ptr zugewiesen. Wofür steht nun das
> > (unsigned long long *) ???
>  
> Das ist nötig, da wert vom Typ double ist und &wert zeigt
> somit auf einen double, ist also vom Typ double*. Der Witz
> an dem Programm ist aber gerade, dass man den Wert, der im
> Speicher steht nicht mehr als double gemäß IEEE754[1]
> interpretiert, sondern als einen 64bit Integer (und später
> dann eben auf eine entsprechende Bitmaske dieses Integers,
> was im IEEE754 als Mantisse bzw. Exponent interpretiert
> wird).
>  
> > zahl = *ptr;
>  
> Hier findet nun diese Umwandlung in einen Integer statt.
>  

Aber warum wandelt man denn den double in einen Integer überhaupt um?

> > maske = (unsigned long long) 1 << 63;
> >
> > // Diese Zeile verstehe ich überhaupt nicht!
>
> Ich nehme an, dass du mit dem Binärsystem vertraut bist
> (sonst google mal kurz oder schau auf wikipedia nach). 1 <<
> 63 ist nun die Zahl 1 (Binär: 0000000000...00001) wobei die
> Binärdarstellung um 63 Stellen nach links verschoben wird.
> Es kommt also 100000...000 mit 63 Nullen raus. Wichtig zu
> wissen ist hier, dass IEEE754 das erste/höchstwertige der
> 64Bit eines double als Vorzeichen ansieht. Und genau dieses
> Bit ist in der Variable maske jetzt auf 1 gesetzt, während
> alle anderen auf 0 gesetzt sind.

[ok] Das habe ich verstanden!

>  
> > if (maske & zahl){
>  >           printf("1");      Das ist klar!
>  >       } else {
>  >           printf("0");  
> > }
>  
> Statt printf("1"); kannst du dir hier auch printf("+");
> vorstellen. maske&zahl filtert jetzt eben gerade das
> Vorzeichenbit heraus.
>  

Wenn ich das richtig verstehe dann sieht die Maske so aus:

100000000.....000000000 ( 63 Nullen )

und jetzt vergleiche ich die Maske mit der Variablen zahl in der sich der eingegebene Wert befindet.


Ich baue mir jetzt mal ein einfaches Beispiel:

1000000.......0000000000 => Das ist meine Maske

Und jetzt gebe ich eine 1 ein:

0000000.......0000000001

Wann wir (maske & zahl) denn wahr?

if (maske & zahl){
       printf("1");      
      } else {
           printf("0");  
}


  

> Nachdem du nun weißt wie diese maske funktioniert sollte
> klar sein, was maske>>1 macht: das maskierte Bit wird um
> eine Stelle nach rechts verschoben. Mit maske&zahl wird
> dann wieder bestimmt, ob in dem double wert dieses Bit auf
> 1 oder 0 gesetzt ist. Jetzt musst du nur noch nachsehen,
> wieviele Bits IEEE754 für Exponent und Mantisse vorsieht
> und wie die jeweiligen Werte an diesen Bits interpretiert
> werden (dabei wirst du zB feststellen, warum die
> for-Schleifen gerade solange laufen).
>  

printf("\ nExponent    : ");
     exp = 0;
     for (i=0; i<11; i++){
         maske >>= 1;
         exp <<= 1;
         if (maske & zahl){
             exp++;      
         }
}

Die Maske wandert also bitweise nach rechts ( s.h Bsp unten ) , aber warum wandert der exp <<= 1 denn jetzt nach links???
Kannst du mir das mal an einem Beispiel erklären?



exp -= 1023;  // Wofür steht denn das jetzt?


     printf("%d\ nMatisse       : ", exp);
     for (i=0; i<52; i++){
         maske >>= 1;
         if (maske & zahl){
             printf("1");      
         } else {
             printf("0");  
         }
     }

Meine Maske sieht ja immer noch so aus:

100000000.....0000000

>>=1 bedeutet, das ich bei jedem Schleifendurchlauf ein Bit nach rechts wandere:

Nach dem ersten Durchlauf würde die Maske dann so aussehen:

010000000.....0000000

2. Durchlauf

001000000.....0000000

usw.

Ist das richtig erklärt???

Auch hier wieder die Frage: Wann wir die Bedingung (Maske & Zahl) wahr???

Ich bin euch unendlich dankbar für eure Antworten!

Viele Grüße

Fabian


Bezug
                        
Bezug
Mantisse,Exponent,Vorzeichen: Antwort
Status: (Antwort) fertig Status 
Datum: 11:20 So 29.10.2006
Autor: Frank05


> Hallo Frank,

Hallo Fabian,
  

> erstmal Danke für deine Antwort! Leider versteh ich noch
> nicht alles :-(

Das kriegen wir schon noch hin ;)

> > Hier findet nun diese Umwandlung in einen Integer statt.
>  >  
> Aber warum wandelt man denn den double in einen Integer
> überhaupt um?

Das hängt lediglich mit der Typisierung zusammen. Die weiter unten verwendeten Operationen wie Bitshifts sind eigentlich nur auf Integer-Typen sinnvoll anwendbar. Es würde aber auch mit einem double Typ funktionieren, aber so ist es sauberer.

> Wenn ich das richtig verstehe dann sieht die Maske so aus:
>  
> 100000000.....000000000 ( 63 Nullen )
>  
> und jetzt vergleiche ich die Maske mit der Variablen zahl
> in der sich der eingegebene Wert befindet.
>  
>
> Ich baue mir jetzt mal ein einfaches Beispiel:
>  
> 1000000.......0000000000 => Das ist meine Maske
>  
> Und jetzt gebe ich eine 1 ein:
>  
> 0000000.......0000000001
>
> Wann wir (maske & zahl) denn wahr?

Das & ist ein binäres und. Wie du in technischer Informatik gelernt haben solltest wird das wahr (1), wenn beide Eingaben auch wahr (1) sind. Für unsere Maske hier heißt das, dass die Bits der Reihe nach verglichen werden und im Ergebnis eine 1 steht genau dann wenn in Maske und dem Wert eine 1 gestanden hat. Betrachtet man den Effekt auf den eingegeben Wert genauer, so stellt man folgendes fest:
- ist ein Eingabebit 0, so ist auch das Ergebnisbit an dieser Stelle 0
- ist ein Eingabebit 1, so ist das Ergebnisbit an dieser Stelle nur 1, falls auch das Bit in der Maske 1 ist
Somit erklärt sich der Sinn der Wortwahl 'Maske'. Dieser Wert maskiert nämlich bestimmte Stellen, indem dort ein 1 Bit gesetzt wird. In der Ausgabe stehen dann überall 0 Bits außer falls an den maskierten Bits in dem Vergleichswert eine 1 stand.

> Die Maske wandert also bitweise nach rechts ( s.h Bsp unten
> ) , aber warum wandert der exp <<= 1 denn jetzt nach
> links???

Das bitweise Wandern hat hier verschiedene Bedeutungen. Im Fall der Maske soll lediglich unser Maskenbit angepasst werden. Was für ein tatsächlicher Zahlenwert zu diesem Zeitpunkt in dem unsigned long long steht ist dabei Nebensache. Ein Verschieben um 1 Bit nach links resultiert aber auch automatisch in einem Verdoppeln der Zahl, was hier bei exp ausgenutzt wird.

>  Kannst du mir das mal an einem Beispiel erklären?

Ok, betrachten wir nur mal den Bereich der Bits, die für den Exponenten zuständig sind und nehmen mal 101 als kleines Beispiel.
Die Maske ist damit zu Beginn 100 und 101 & 100 = 100. Also exp++ und damit ist exp=1. Eigentlich haben wir aber gemäß dem Binärsystem mit 100 die Zahl 4 und nicht 1. Da wir nun mit der Maske aber in umgekehrter Richtung über diese Binärzahl fahren müssen wir dafür sorgen, dass unsere Bits des berechneten Exponenten auch an die richtige Stelle kommen. Deshalb jetzt maske>>=1 und exp<<=1, was uns 010 und 10 ergibt.

010 & 101 = 000 -> keine Änderung, also weiter: maske>>=1, exp<<=1 und wir haben jetzt 001 und 100 (hier sieht man jetzt schon, wie der Exponent korrekt die 4 ergibt)

001 & 101 = 001 -> exp++ also exp = 5 bzw 101

> exp -= 1023;  // Wofür steht denn das jetzt?

Das hängt mit besagtem IEEE Standard zusammen und wie dort der Exponent kodiert wird. Er wird nämlich nicht so einfach wie in obigem Beispiel als Zahl direkt in die Bits geworfen. Das ist aber hier fürs Verständnis nicht wichtig.

> Meine Maske sieht ja immer noch so aus:
>  
> 100000000.....0000000
>  
> >>=1 bedeutet, das ich bei jedem Schleifendurchlauf ein Bit
> nach rechts wandere:
>  
> Nach dem ersten Durchlauf würde die Maske dann so
> aussehen:
>  
> 010000000.....0000000
>  
> 2. Durchlauf
>  
> 001000000.....0000000
>  
> usw.
>  
> Ist das richtig erklärt???

[ok] Ja das stimmt.

> Auch hier wieder die Frage: Wann wir die Bedingung (Maske &
> Zahl) wahr???

s.o.

Bezug
                                
Bezug
Mantisse,Exponent,Vorzeichen: Mitteilung
Status: (Mitteilung) Reaktion unnötig Status 
Datum: 20:22 So 29.10.2006
Autor: Fabian

Hallo Frank [anbet]

Vielen Dank für deine super Erklärung! Wenn man es einmal kapiert hat [lichtaufgegangen] ist alles so logisch!

Viele Grüße

Fabian

Bezug
Ansicht: [ geschachtelt ] | ^ Forum "C/C++"  | ^^ Alle Foren  | ^ Forenbaum  | Materialien


^ Seitenanfang ^
www.vorkurse.de
[ Startseite | Mitglieder | Teams | Forum | Wissen | Kurse | Impressum ]