Buffon Nadelproblem

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
bloody1337
User
Beiträge: 9
Registriert: Samstag 5. Juni 2010, 14:11

Hallo :)

ich habe ein problem.
ich soll ein buffon`s nadelproblem-programm von pascal in python umschreiben.

das programm habe ich noch nicht verstanden.die sufu habe ich benutzt und einen topic schon dazu gefunden,
bin aber trotzdem noch nicht weitergekommen.

Bild
Bild

das ist das vorgegebene programm mit ein bisschen geschmiere...ich konnte es mir nicht verkneifen! :o

meine überlegungen bislang:

Code: Alles auswählen

import math
import random

def intp(x):
    if x>= 1.0:
        return 1
    if x<0.0:
        return -1
    return 0


t=int(input("Schusszahl eingeben:"))
s=0
i=1
while i <=t:
    x =  random.random()
    y = random.random()
    a=pi*random.random()
    b=math.cos(a)/2
    c=math.sin(a)/2
    if intp(y-b)!= intp(y+b):
        return s+1
    if intp(x-c)!= intp(x+c):
        return s+1
    
print('PI: '+str((t/s)*4))

das funktioniert bislang noch nicht.dieses problem kann ich ohne hilfe nicht lösen...
am besten wäre ein programm,welches den anweisungen aus dem pascal programm gleicht
und mit elementaren,grundlegenden befehlen arbeitet.


wäre lieb,wenn es sich jemand anschaut!


danke
grüße bloody
BlackJack

@bloody1337: Das ist ein ziemlich grundlegendes Problem und auch ein sehr offensichtliches wenn man die Python-Grundlagen verstanden hat, und weiss welche Anweisung was bewirkt und wo sie Sinn macht. Hier bekommst Du sogar eine *sehr* eindeutige Meldung zu einem Syntaxfehler, also schonmal einen Hinweis auf etwas was so ganz sicher nicht geht: "SyntaxError: 'return' outside function"

Dann schau mal in das Pascal-Programm an der Stelle und versuche mal zu erklären warum Du das was da steht nicht fast haargenau so in Python "übersetzt", sondern ein ``return`` da hingeschrieben hast!?
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Und wenn der offensichtliche Syntaxfehler weg ist, kann man sich ja mal überlegen, was "NameError: name 'pi' is not defined" wohl meint und dann schauen, wieso das "while" eine Endlosschleife ist.

Stefan
bloody1337
User
Beiträge: 9
Registriert: Samstag 5. Juni 2010, 14:11

huhu :)

danke für die tipps!

ich habe nun etwas verändert und mir die grundlagen noch einmal angeschaut. so sieht es bislang aus:

Code: Alles auswählen

import math
import cmath                            # mathematische Konstanten
import random

def intp(x):
    if x>= 1.0:
        return 1
    if x<0.0:
        return -1
    return 0


t=int(input("Schusszahl eingeben:"))
s=0
i=1
while i <=t:
    x = random.random()                 # zufällige Koordinaten der Nadel
    y = random.random()                 #          --""--
    a=cmath.pi*random.random()          # Winkel der Nadel von 0 bis PI
    b=math.cos(a)/2
    c=math.sin(a)/2
    if intp(y-b)!= intp(y+b):
        s=s+1
    if intp(x-c)!= intp(x+c):
        s=s+1
    i=i+1

    print('PI: '+str((t/s)*4.0))
   

die 3 genannten fehler sind behoben,aber es kommen nur unsinnige werte raus. wo liegt nun das problem?wie kann es gelöst werden? am besten die einfachste lösung!


grüße und danke
bloody
philistion
User
Beiträge: 108
Registriert: Sonntag 7. Februar 2010, 14:16

Ich hab deine Implementierung mal ein wenig angepasst, du wirst sicher selbst erkennen wo der Fehler lag.

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-
import math
import random
import sys

# import psyco
# psyco.full()
# ^ Damit ginge es noch schneller

intp = lambda x: x >= 1.0 and 1 or x < 0.0 and -1 or 0
# Warum nicht auch mit einer lambda Anweisung? 
# Du kannst aber natürlich auch deine intp Funktion weiter verwenden, das war nicht das Problem.

def buffon(t):
    s = 0
    for i in xrange(t):
        x = random.random()
        y = random.random()
        a = math.pi * random.random()
        b = math.cos(a) / 2.0
        c = math.sin(a) / 2.0
        if intp(y - b) != intp(y + b):
            s = s + 1
        if intp(x - c) != intp(x + c):
            s = s + 1
    return s


# Damit man Zeitunterschiede der Implementierung messen kann,
# soll das Programm auch ein Argument annehmen koennen.
if len(sys.argv) > 1:
    t = int(sys.argv[1])
else:
    t = int(input('Schusszahl eingeben: '))

s = buffon(t)
print 'PI: ' + str(4.0 * t / s)
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Wenn du Python < 3 verwendest, dann bist du in die Falle der Integer-Division gelaufen. Die tritt immer auf, wenn nur ganze Zahlen an einer Division beteiligt sind. Zur Behebung entweder s vor der Division in einen float umwandeln oder lieber

Code: Alles auswählen

from __future__ import division
ganz an den Anfang schreiben, damit wird dieses Verhalten abgeschaltet.

@philistion: Woran soll bloody1337 denn das selbst erkennen? Außer das deine intp Version völlig unverständlich geworden ist, ist das einzige was wirklich einen Unterschied macht, dass du am Schluss die Multiplikation vorgezogen hast. Da gehören dann schon wirklich hellseherische Gabe dazu, ohne Vorwissen auf die Division mit ganzen Zahlen als Ursache zu schließen.
philistion
User
Beiträge: 108
Registriert: Sonntag 7. Februar 2010, 14:16

Nein, ich meinte nicht das Vorziehen. Das und die Lambda Funktion war nur eine Spielerei.

Ich meinte das ".0" nach der 4 ;)
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

philistion hat geschrieben:Ich meinte das ".0" nach der 4 ;)
Die war schon in bloody1337s Code da und macht in diesem Fall tatsächlich nur einen Unterschied, wenn die Multiplikation wie bei dir vor der Division kommt.

Worauf ich hinauswollte ist, dass bloody1337 nicht damit geholfen ist, wenn du zig-Änderungen in der Datei machst, wovon nur eine relevant(die dir anscheinend selbst nicht bewusst war) ist und ihn dann suchen lässt. Wenn man wenig Ahnung hat vermutet man die Ursache nämlich bei jeder (überflüssigen) Änderung.
Zuletzt geändert von Darii am Sonntag 6. Juni 2010, 11:25, insgesamt 1-mal geändert.
bloody1337
User
Beiträge: 9
Registriert: Samstag 5. Juni 2010, 14:11

JIPPPIEEE!!!

es klappt mal was! wie auch immer... danke an philistion

und natürlich auch die anderen,die fleißig geantwortet haben :)


dann allen noch einen schönen sonnigen sonntag :>
BlackJack

@philistion: Warum nicht mit einer ``lambda``-Anweisung? Weil ``lambda`` für namenslose Funktionen vorgesehen ist. Es hat keinen Vorteil gegenüber ``def`` aber den Nachteil, dass es ungewöhnlicher ist. Warum nicht *diese* ``lambda``-Anweisung? Weil "juhuu ich kenne die Randfälle der Sprache und kann alles in eine Zeile quetschen" unpythonisch ist.

@all: Ansonsten habe ich auch noch was leicht überdimensioniertes:

Code: Alles auswählen

from itertools import islice
from math import cos, pi as PI, sin
from random import random


BELOW, WITHIN, ABOVE = 'BELOW', 'WITHIN', 'ABOVE'
HORIZONTAL, VERTICAL = ORIENTATIONS = 'HORIZONTAL', 'VERTICAL'


def check_interval(x, lower=0, upper=1):
    if x < lower:
        return BELOW
    elif x >= upper:
        return ABOVE
    else:
        return WITHIN


class UnitNeedle(object):
    def __init__(self, x, y, angle):
        self.x = x
        self.y = y
        self.angle = angle
    
    @classmethod
    def random(cls):
        return cls(random(), random(), PI * random())

    def crosses_line(self, orientation):
        if orientation not in ORIENTATIONS:
            raise ValueError('orientation not in %r' % ORIENTATIONS)
        extent = (sin if orientation is HORIZONTAL else cos)(self.angle) / 2
        value = self.x if orientation is HORIZONTAL else self.y
        return check_interval(value - extent) != check_interval(value + extent)
    
    @property
    def line_cross_count(self):
        return sum(map(self.crosses_line, ORIENTATIONS))


def main():
    times = int(raw_input('times = '))
    needles = islice(iter(UnitNeedle.random, None), times)
    cross_count = sum(needle.line_cross_count for needle in needles)
    print 'PiDach =', 4.0 * times / cross_count


if __name__ == '__main__':
    main()
:-)
philistion
User
Beiträge: 108
Registriert: Sonntag 7. Februar 2010, 14:16

BlackJack hat geschrieben:@philistion: Warum nicht mit einer ``lambda``-Anweisung? Weil ``lambda`` für namenslose Funktionen vorgesehen ist. Es hat keinen Vorteil gegenüber ``def`` aber den Nachteil, dass es ungewöhnlicher ist. Warum nicht *diese* ``lambda``-Anweisung? Weil "juhuu ich kenne die Randfälle der Sprache und kann alles in eine Zeile quetschen" unpythonisch ist.
Ok, die lambda-Anweisung hätte ich mir sparen können, war didaktisch nicht klug. Werde in Zukunft versuchen, an Ockhams Rasiermesser zu denken.
@all: Ansonsten habe ich auch noch was leicht überdimensioniertes:
Gibt es sowas eigentlich auf für Python? ;)
BlackJack

@philistion: Ich finde ja Code-Golf interessanter. Da gibt's objektive Bewertungskriterien.

Bedingungen: Berechnung von π nach dem Algorithmus in dem Pascal-Programm, also mit `x` *und* `y`. Keine Zeile > 80 Zeichen (exclusive Newline). Das Newline am Zeilenende zählt als Zeichen. Alle Zeilen sind durch ein Newline abgeschlossen.

Eingabe vom Benutzer, kein Prompttext erforderlich, keine Fehleingaben behandeln. Ausgabe die Näherung von π.

Ich habe eine Lösung mit 180 Zeichen.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

@BlackJack:
Ich komme auf 218 - die import'e reißen mich da rein :(
Aber meine intp()-Version 'gefällt' mir

Code: Alles auswählen

intp=lambda n:n>1 or-(n<0)or 0
BlackJack

@b.esser-wisser: Ist ganz nett aber so lang. :-P Meine Variante ist 4 Zeichen kürzer und zwar mit der ursprünglichen Bedingung ``>=`` statt nur ``>``. Das war letztendlich so kurz, dass das Definieren einer Funktion mit ``lambda`` und zweimal Aufrufen länger ist, als den Ausdruck einfach zweimal direkt in den Code einzusetzen.

Oh, und ein Leerzeichen kannst Du noch weglassen.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

215, Ich geb's erst mal auf :(
Mein Ansatz mit m(x+c,x-c) als Ersatz für "intp(x+c) != intp(x-c)" hat's nicht gebracht (abgesehen von "m=lambda a,b:any((a>=1>b,a<0,b>=1,b<0))" :twisted: ).

Btw.: Warum ist "1or 0" korrekt, aber "0or 1" ein Syntaxfehler? (Bug in python 2.6.5?)

hth, Jörg
BlackJack

@b.esser-wisser: Ab Python 2.6 kann man literale Binär- und Oktalzahlen eingeben, wie das bis dato nur mit Hexadezimalzahlen ging:

Code: Alles auswählen

>>> 0x7f
127
>>> 0b01111
15
>>> 0o664
436
Bei ``0or`` denkt der Parser "Oh, ein Oktalliteral" und stolpert dann über das ``r`` was ja keine gültige Oktalziffer ist. Habe ich bisher auch noch nicht drüber nachgedacht. :-)
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

An die 0oxx-Schreibweise hatte ich nicht gedacht, ich dachte die gäbe es erst ab python 3.x - vielleicht sollte ich mir die "what's new"-Seite mal genauer ansehen :oops:
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

ich bin bei 198 Zeichen, ich denke beim import gibt es noch Potenzial:

Code: Alles auswählen

import math as m,random as r
und natürlich bei der lambda Funktion.

Habt ihr euch auch schon gefragt was dieses Buffon Nadelproblem eigentlich bringt. Denn dieses PI Dach wird ja anhand des PI Wertes ermittelt...
BlackJack

@DaMutz: Man braucht pi ja nur weil es eine Simulation im Rechner ist. Wenn man wirklich Nadeln oder Stöcke auf Kästchenpapier oder gekachelten Boden werfen würde steckt diese Naturkonstante ja einfach in der Natur der Sache.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Ich bin bei 203, durch den letzten Trick ist die Schleife evtl. eins zu kurz :oops:
Disclaimer: Der link ist nicht für Anfänger und erst recht nicht dazu da,irgendwas davon in einem richtigen Programm zu verwenden.
Antworten