#!/usr/bin/python
# coding=latin1
from sys import argv

###############################################################################
# Berechnung der jeweils nziff ersten und letzten Ziffern von 9**9**9
#
# Aufruf des Programms:
#
#  neun [<nziff> [<breite>]]
#
#  nziff ist die Anzahl der berechneten Ziffern, breite die Ausgabebreite.
#
# Prinzipielles Verfahren:
#
# p = 9**9**9 =
#   = 9**(3**2)**9 =
#   = 9**3**(2*9) =
#   = 9**3**18 =
#   = 9**(3*3*...*3) =
#   = ((...((9**3)**3)**...)**3)
#
# Grüße an AVRFan :)
#
# Die Berechnung der letzten nziff Ziffern erfolgt in Modulo-10**nziff-
# Arithmetik unter Zuhilfenahme des long-Datentyps (Integer beliebiger Größe).
#
# Für die Berechnung der ersten nziff Ziffern wird ein neuer Datentyp (im
# Folgenden FP10 genannt) eingeführt. Jede Zahl z wird in der Form (m, e)
# dargestellt, wobei z = m * 10**e ist. Für diesen Datentyp wird eine
# Multiplikations- und eine Normierungsoperation definiert. Für die Mantisse m
# wird ebenfalls der long-Datentyp verwendet. Die Potenzierung mit dieser
# Methode bringt einen Rundungsfehler mit sich, der im Bereich von 7 Stellen
# liegt (emprisch bestimmt). Deswegen wird die Berechnung mit nziff1 = nziff +
# 10 Stellen durchgeführt, die 10 zusätzlichen Stellen werden am Schluss wieder
# entfernt.
###############################################################################

def norm(x):
  # Normierung von FP10-Zahlen
  # Die Mantisse wird am Ende abgeschnitten oder mit Nullen erweitert,
  # so dass sie genau nziff1 Stellen hat. Der Exponent wird entsprechend
  # korrigiert.

  m = x[0]     # Mantisse
  e = x[1]     # Exponent
  s = str(m)   # Mantisse als String
  n = len(s)
  if n < nziff1:                    # Mantisse zu kurz?
    m = long(s + (nziff1 - n) * "0")  # mit Nullen erweitern
    e -= nziff1 - n                   # Exponent korrigieren
  elif n > nziff1:                  # Mantisse zu lang?
    m = long(s[:nziff1])              # abschneiden
    d = int(s[nziff1])                # Ist die nächsten Ziffer
    if d >= 5:                        # mindestens 5,
      m += 1                          # Mantisse aufrunden
    e += n - nziff1                   # Exponent korrigieren
  return (m, e)                       # Ergebnis zurückgeben
  
def mul(x, y):
  # Multiplikationsroutine für FP10-Zahlen

  m = x[0] * y[0]      # Mantisse multiplizieren
  e = x[1] + y[1]      # Exponenten addieren
  return norm((m, e))  # Rückgabe des normierten Ergebnisses

def first():
  # Berechnung der ersten nziff Ziffern
  # Die Potenzierung erfolgt im FP10-Format

  p = (9L, 0)            # die Zahl 9 in FP10-Darstellung
  for i in range(18):    # 18mal
    p = mul(p, mul(p, p))  #mit 3 potenzieren
  sz = p[1] + nziff1     # Gesamtstellenzahl = Exponent + Mantissenlänge
  # Rückgabe des nach nziff Ziffern abgeschnittenen Ergebnisses und der
  # Gesamtstellenzahl
  return str(p[0])[:nziff], sz
  
  
def last():
  # Berechnung der letzten nziff Ziffern
  # Die Potenzierung mit 3 erfolgt jeweils modulo 10**nziff, da die anderen
  # Stellen nicht interessieren und auf das Ergebnis keinen Einfluss haben.

  z = 10 ** nziff
  p = 9L
  for i in range(18):  # 18mal 
    p = p * p * p % z    # mit 3 potenzieren (modulo 10**nziff)
  return str(p)

def mprint(s, n):
  # Ausgabe mit Zeilenumbruch nach n Zeichen

  le = len(s)
  for i in range(0, le, n):
    print s[i:min(i+n, le)]

###############################################################################
# Hauptprogramm

# Defaultparameter
nziff = 100
breite = 50

# Kommadozeilenargumente
if len(argv) >= 2:
  nziff = int(argv[1])    # gewünschte Stellenzahl
if len(argv) >= 3:
  breite = int(argv[2])   # Ausgabebreite

nziff1 = nziff + 10     # erweiterte Stellenzahl für führende Ziffern,
                        # um Rundungsfehler zu kompensieren
fi, sz = first()        # Berechnung der nziff ersten Ziffern und der
                        # Gesamtstellenzahl
la = last()             # Berechnung der nziff letzten Ziffern

# Ausgabe
mprint(fi, breite)
print "...".center(breite)
print ("%d Ziffern weggelassen" % (sz-2*nziff)).center(breite)
print "...".center(breite)
mprint(la, breite)
