#!/usr/bin/env python

# Rechnerarchitektur, WS 2010/11, Hochschule Muenchen
# Hans-Georg Esser
#
# gleitkomma.py  v 0.1  (2010/10/27)


# Nutzt Bibliotheksfunktionen 
# - argv (Aufrufargumente)
# - exit (Programm mit Fehlercode beenden)
from sys import argv, exit



def DualToIEEE (vz, exp, bitstr, laenge):
  # Umwandeln in 32-/64-Bit-Gleitkommazahl nach IEEE 754 (wie Vorlesung)
  # vz: Vorzeichen (0,1)
  # exp: Exponent
  # bitstr: Bit-String
  # Ausgabe: IEEE-754-Darstellung (32 oder 64 Bit)
  if laenge == 64:
    explen = 11    # Laenge des Exponenten
    manlen = 52    # Laenge der Mantisse; 1 + 11 + 52 = 64
    exzess = 1023  # Exzess 1023 (2^(11-1)-1)
  elif laenge == 32:
    explen = 8     # Laenge des Exponenten
    manlen = 23    # Laenge der Mantisse; 1 + 8 + 23 = 32
    exzess = 127   # Exzess 127 (2^(8-1)-1)
  else:
    exit(1)

  bitstr = bitstr + laenge*"0"  # hinten mit Nullen auffuellen
  # Exponent
  e = exp + exzess              # Exzess zum Exponenten addieren
  e_str = bin(e)[2:]            # Dualdarstellung ("0b" abschneiden)
  e_str = (explen-len(e_str))*"0" + e_str  # fuehrende Nullen
  # Mantisse
  m_str = bitstr[1:manlen+1]      # Mantisse ohne fuehrende 1!

  return (str(vz), e_str, m_str)



def BinStrToHexStr (b):
  # wandelt Binaer-String ("101010") in Hex-String um
  # Leider funktioniert  hex(int("0b"+bitstring))  nicht
  v = 0
  bits = b
  while len(bits)>0:
    v = 2 * v + int(bits[0])     # vorderstes Bit in bits[0]
    bits = bits[1:]
  hexstring = hex(v)
  hexstring = hexstring[2:]      # "0x" abschneiden
  if hexstring[-1] == "L":
    hexstring = hexstring[:-1]   # "L" (long) abschneiden
  hexstring = hexstring.upper()  # Grossbuchstaben
  # Leerzeichen einfuegen
  h = ""
  while len(hexstring)>0:
    h = h + hexstring[:4] + " "
    hexstring = hexstring[4:] 
  return h



anleitung = """\
Aufruf: gleitkomma.py ZAHL (mit Dezimalpunkt)
        z. B. gleitkomma 18.4"""

# Aufrufargument einlesen ...
try:
  argument = argv[1]
except:
  print anleitung
  exit(1)

# ... und in Zahl umwandeln
try:
  zahl = float(argument)
except:
  print anleitung
  exit(1)

# Vorzeichen bestimmen  
a = zahl
if a<0:
  vz = 1       # negativ: 1
  vzstr = "-"
else:
  vz = 0       # positiv: 0
  vzstr = "+"

a = abs(a)     # Vorzeichen weg lassen

# aufteilen in Vor- und Nachkomma-Teil
vorkomma  = int(a)
nachkomma = a - vorkomma


# Vorkommastellen in Dualdarstellung umwandeln
vorkomma_bits = ""
v = vorkomma
while v > 0:
  bit = v % 2
  v = v / 2
  vorkomma_bits = str(bit) + vorkomma_bits

# Nachkommastellen in Dualdarstellung umwandeln
nachkomma_bits = ""
n = nachkomma
counter = 52
while (n > 0) and (counter > 0):
  counter = counter - 1
  n = n * 2
  bit = int(n)     # nur Vorkomma-0 oder Vorkomma-1 von n
  n = n - int(n)   # Vorkommastelle auf 0 setzen
  nachkomma_bits = nachkomma_bits + str(bit)
if counter == 0:
  mehr_stellen = True

# Dualzahl: Vorzeichen, Vorkomma-Bits, Nachkomma-Bits
dual = vzstr + vorkomma_bits + "." + nachkomma_bits

# Ergebnisse ausgeben
print "Zahl:           ", zahl
print "Vorzeichen:     ", vz, "("+vzstr+")"
print "Vorkomma:       ", vorkomma
print "Vorkomma(b):    ", vorkomma_bits
print "Nachkomma:      ", nachkomma
print "Nachkomma(b):   ", "(0.)" + nachkomma_bits
print "Dualdarstellung:", dual


# Fixkommadarstellung: 

potenz = len(vorkomma_bits)-1
bits = vorkomma_bits + nachkomma_bits

while bits[0] == "0":
  bits = bits[1:]      # fuehrende 0 abschneiden
  potenz = potenz - 1  # Potenz um 1 erhoehen

print "Fast normiert:  ", vzstr + bits[0]+","+bits[1:]+ " * 2^"+str(potenz)

print
print "IEEE 754: (Vorzeichen, Exponent, Mantisse)"

(vz_str, e_str, m_str) = DualToIEEE (vz, potenz, bits, 64)
print "DualToIEEE(64): ", vz_str, e_str, m_str
print "Hexadezimal:    ", BinStrToHexStr (vz_str + e_str + m_str)

(vz_str, e_str, m_str) = DualToIEEE (vz, potenz, bits, 32)
print "DualToIEEE(32): ", vz_str, e_str, m_str
print "Hexadezimal:    ", BinStrToHexStr (vz_str + e_str + m_str)

