#!/bin/env python3

# Rechnen mit Python

# die Namen des aktuellen Sichtbarkeitsbereichs ausgeben
print(dir(), end='\n\n')

# die Module math, decimal und cmath für mathematische Funktionen, Dezimal- und
# komplexe Zahlen importieren
import math
import decimal
import cmath

# aus dem Modul fractions importieren wir die Klasse Fraction
from fractions import Fraction

print(dir(), end='\n\n')

# die Namen des Moduls math ausgeben
print(dir(math), end='\n\n')

print(math.__doc__, end='\n\n')
# This module is always available.  It provides access to the
# mathematical functions defined by the C standard.

print(math.pi, math.e) # 3.141592653589793 2.718281828459045
math.pi = 3.2 # circa :-)
print(math.pi)

print(math.log(math.e))

# 2 Float-Zahlen aus Strings erstellen
netto = float('17.2345')
mwst = float('10')
brutto = netto * (1 + mwst / 100)

print('\nBrutto:', brutto)                                 # 18.957950000000004
print('Brutto mit 2 Stellen: %.2f' % brutto)               # 18.96
print('Brutto gerundet auf 3 Stellen: ', round(brutto, 3)) # 18.958
print()

# 0o11   --> Oktalzahl
# 0x0a   --> Hexadezimalzahl (auch 0xa möglich); wahlweise Groß-/Kleinschreibung
#            bei Präfix und Hexadezimalziffern
# 1.8E5  --> float-Zahl in Exponentenschreibweise; e kann auch klein geschrieben werden
print((1 + 0o11) * 0x0a, 1.35, 1.8E5, (3 + 1j) * 3, 3 ** 4)

# Ganzzahlen vom Typ "int" unterstützen Langzahlarithmetik
print(2 ** 1024)

print(0b11, 0B11)  # Binärzahl 11 ==> 3
print(0o72, 0O72)  # Oktalzahl 72 ==> 58
print(bin(10))     # ==> '0b1010'

print('\nkomplexe Zahlen')
c = 3 + 4j # oder: 3 + 4J
# kartesische Koordinaten (Real- und Imaginärteil)
print(c.real, c.imag)

# Polarkoordinaten
print(cmath.polar(c))
# (5.0, 0.9272952180016122)

# alternative Bestimmung der Polarkoordinaten
print(abs(c), cmath.phase(c))

# Umwandlung der Polarform in die algebraische (kartesische) Form
print(cmath.rect(*cmath.polar(c)))
print(cmath.rect(cmath.polar(c)[0], cmath.polar(c)[1]))

print('\nDivision')
# // ==> ganzzahlige Division
# %  ==> Rest der Division (Modulo-Operator)
print(1/3, 1 // 3, 7 % 3)
print()

a = 12.1
b = 2
c = a / b
print(c)       # 6.05
print(str(c))  # 6.05
print(repr(c)) # 6.0499999999999998 bis Python 2.6 und 6.05 ab Python 2.7
               # repr() wird im interaktiven Modus benutzt

print('\nDecimal')
a = decimal.Decimal(str(a))
b = decimal.Decimal(str(b))
c = a / b
print(repr(c))         # Decimal("6.05")
print(c, end='\n\n') # 6.05

# Rundungsungenauigkeit bei float
z = '0.33333333333333333333'
print(decimal.Decimal(z) * 3) # Decimal('0.99999999999999999999')
print(float(z) * 3)           # 1.0

print(0.1 + 0.2 == 0.3) # False
print(decimal.Decimal('0.1') + decimal.Decimal('0.2') == decimal.Decimal('0.3')) # True

# die Operationen mit Decimals kann man ziemlich fein über den Context steuern;
# hier ein Beispiel:

# den Default-Kontext auslesen
default_context = decimal.getcontext()
# einen neuen Kontext einstellen, der eine abweichende Präzision aufweist
decimal.setcontext(decimal.Context(prec=5))

# in einer Schleife jeweils ein Zahlenpaar addieren
for z1, z2 in ('1.11111111', '2.22222222'), ('3.33333333', '4.44444444'):
    a = decimal.Decimal(z1)
    b = decimal.Decimal(z2)
    print(a)
    print(b)
    print(a + b)
    print('gerundet' if decimal.getcontext().flags[decimal.Rounded] else 'exakt')
    # den Default-Kontext wieder aktivieren
    decimal.setcontext(default_context)

# Ausgabe:
#   1.11111111
#   2.22222222
#   3.3333
#   gerundet
#   3.33333333
#   4.44444444
#   7.77777777
#   exakt

# mit with kann man die Präzision bequem auf einen Anweisungsblock begrenzen
print('\nwith')
with decimal.localcontext(decimal.Context(prec=5)):
    print(decimal.Decimal('1') / decimal.Decimal('3')) # 0.33333

print(decimal.Decimal('1') / decimal.Decimal('3'))   # 0.3333333333333333333333333333

# rationale Zahlen (Brüche)
print('\nFraction')
f1 = Fraction(6, 8)                       # Fraction(3, 4)
f2 = 2 * f1                               # Fraction(3, 2)
print('%s + %s = %s' % (f1, f2, f1 + f2)) # Fraction(9, 4)
# 3/4 + 3/2 = 9/4
