Tag Archives: python

Inne

Algorytmy liczące Pi w Pythonie

Dzisiaj będzie o długich licz­bach. Wiedzie­li­ście, że Python w stałej Pi zawiera tylko 48 cyfr po prze­cinku? (a przy­naj­mniej wersja 2.6) 3.141592653589793 (odtąd błęd­nie) 115997963468544185161590576171875. To stanow­czo za mało! Tyle to ja liczy­łem na liczy­dle w przed­szkolu A ja chciał­bym wiedzieć jaka jest liczba pięcio­ty­sięczna po prze­cinku ;-) Zade­mon­struję 3 metody licze­nia liczby Pi.

Od razu mówię, nie pytaj­cie mnie o nic w związku z tymi meto­dami, bo zazwy­czaj rozu­miem tylko wstęp i pierw­szy wzór z opisu.

I. Metoda Wallisa
Posłu­żymy się takim fajnym tworem jak gene­ra­tor (yield w pętli zamiast return)

def wallisFormulaGenerator(counterMax):
   counter = 0
   while(counter <= counterMax):
      counter += 1
      yield (4*(counter**2))/(4*(counter**2)-1)       
 
def gimmePiBaby(loops):
   result = 1
   for value in wallisFormulaGenerator(loops):
      result *= value
      return 2*result
 
print(gimmePiBaby(10000))

Ta metoda jest najsłab­sza, po 18 obro­tach mamy dopiero 3.1, po 492 3.14, a dopiero po 8476 3.1415.

II. Metoda Leib­nitza
W moim przy­padku mocno oszu­kana ta metoda, ale działa popraw­nie. I dużo szybciej!

minus = True
partial = 1
denominator = 3
for i in range(100000):
   if minus:
      partial -= 1/denominator
      minus = False
   else:
      partial += 1/denominator
      minus = True
   denominator += 2
   result = 4 * partial

Jest lepiej, obli­cze­nia wyko­ny­wały się 3x szyb­ciej niż poprzednio.

III. Metoda Abra­hama Sharpa
Najwy­daj­niej­sza z wyżej przed­sta­wio­nych. Na pewno są wydaj­niej­sze, ale dla okre­śle­nia liczby nr 5000 wystar­czy. Aby wypi­sać tyle liczb ile nas inte­re­suje, zwykły obiekt typu float nie wystar­czy, potrze­bu­jemy biblio­teki BigFloat. Niestety nie daje się zain­sta­lo­wać z wersją 3 Pythona mimo użycia 2to3, więc pozo­staje wbudo­wane w Ubuntu 2.6.

import bigfloat
with bigfloat.precision(17000):
   minus = True
   partial = bigfloat.BigFloat(1)
   denominator = 3
   for i in range(1, 500000):
      if minus:
         partial -= (1/((bigfloat.pow(3,i))*denominator))
         minus = False
      else:
         partial += (1/((bigfloat.pow(3,i))*denominator))
         minus = True
      denominator += 2
   result = 6 * ((1/bigfloat.sqrt(3)) * partial)

Mój procek za 45zł 500 000 obro­tów wyko­nał w 2339 sek., a dzisiej­szy wpis spon­so­ruje cyferka 1 będąca warto­ścią pięcio­ty­sięczną po przecinku.

Mam nadzieję, że chociaż gimna­zja­li­stom algo­rytmy się przydadzą…

Inne

Śpiechu liczy zawartość alkoholu w drinkach

Zasta­na­wiało Was kiedyś o ile dokład­nie wzro­śnie całko­wita zawar­tość alko­holu gdy do piwa dodamy „u-boota” (50tkę wódki)? A o ile spad­nie gdy to piwo zbesz­cze­ścimy doda­niem soku mali­no­wego? Chodzi mi o dokładne warto­ści, a nie jakieś tam „no pewnie z 2% jak nic”. Dzisiaj się dowiecie :-)

Całość napi­sa­łem w Pytho­nie żeby się trochę wdro­żyć. Dla Windowsa jest bardzo fajna rzecz: Porta­ble Python. Insta­lu­jesz na pendraka i nieza­leż­nie od maszyny odpa­lasz inter­pre­ter. Do cało­ści dołą­czony jest całkiem zgrabny edytor PyScripter.

Dobra, do rzeczy. Potrzebna będzie wiedza przed­gim­na­zjalna — mnoże­nie, dzie­le­nie i trochę procen­tów. Wyni­kowy program obsłu­guje się tak:

#!/usr/bin/env python
 
from shaker import Shaker, ShakerDisplayer
 
shaker = Shaker()
shaker.addIngredient('piwo', 500, 5.7)
shaker.addIngredient('wodka', 50, 40)
shaker.addIngredient('sok malinowy', 25, 0)
 
ShakerDisplayer.displayShakerDetails(shaker, 89, True)

Otrzy­mamy poniż­szy tekst:

Sklad­niki drinka:
25.00ml sok mali­nowy
30.00ml wodka
48.50ml alco­hol
471.50ml piwo
Calko­wita zawar­tosc alko­holu w drinku: 8.43%
Calko­wita zawar­tosc alko­holu w drinku (wyra­zona w gramach): 38.32g
Praw­do­po­dobna liczba promili dla faceta o wadze 89kg wynosi 0.62‰

W pliku (module!) shaker.py stwo­rzymy sobie 2 klasy: ShakerShaker­Di­splayer. Jak linijki nie miesz­czą się w okienku to można prze­su­wać strzał­kami na klawiaturze ;-)

#!/usr/bin/env python
 
import unicodedata
from numbers import Number
 
class Shaker:
 
    def __init__(self, shakerCapacity = 1000000):
 
        # Zakladamy, ze pojemnosc shakera jest nieograniczona ;-)
        self._shakerCapacity = shakerCapacity
 
        # Inicjalizuje dictionary dla przechowywania klucz => wartosc
        # Klucz dla alkoholu jest w skladnikach zawsze
        self._drinkIngredients = {'alcohol' : 0}
 
    def addIngredient(self, name, amount, alcoholPercentage = 0):
 
        # Gdyby komus zachcialo sie wprowadzac inne wartosci niz numerki i wartosci dodatnie
        if not isinstance(amount, Number) or not isinstance(alcoholPercentage, Number) or alcoholPercentage < 0 or amount < 0:
 
            # Formatowanie za pomoca {} zadziala od Pythona 3.1+    
            raise ValueError('Podano {} i {} dla {}'.format(amount, alcoholPercentage, name))
 
        # Sprawdzam czy jest wystarczajaco duzo miejsca w shakerze
        spaceInShakerLeft = self._shakerCapacity - self.totalLiquidAmount()
        if spaceInShakerLeft >= amount:
            self._storeNewIngredient(name, amount, alcoholPercentage)
        else:
 
            # Jak za malo to dolewam tylko tyle ile sie zmiesci
            self._storeNewIngredient(name, spaceInShakerLeft, alcoholPercentage)
 
    def _storeNewIngredient(self, name, amount, alcoholPercentage):
 
        # Licze objetosc czystego alkoholu w plynie
        liquidAlcohol = 0
        if alcoholPercentage > 0:
            liquidAlcohol = (amount * alcoholPercentage) / 100
            self._drinkIngredients['alcohol'] += liquidAlcohol
 
        # Sprawdzam czy w drinku jest juz dany skladnik
        if self._drinkIngredients.get(name) == None:
            self._drinkIngredients[name] = amount - liquidAlcohol
        else:
            self._drinkIngredients[name] += amount - liquidAlcohol
 
    def getAllDrinkIngredients(self):
 
        # Wypluwam czysty dictionary ze skladnikami
        return self._drinkIngredients
 
    def totalLiquidAmount(self):
 
        # Zliczam objetosc wszystkich skladnikow w shakerze
        total = 0
        for value in self._drinkIngredients.values():
            total += value
        return total
 
    def getTotalLiquidAlcohol(self):
        return self._drinkIngredients['alcohol']
 
    def getTotalAlcoholPercentage(self):
 
        # Licze calkowity procent alkoholu w drinku
        return (self.getTotalLiquidAlcohol() / self.totalLiquidAmount()) * 100
 
    def getTotalAlcoholInGrams(self):
 
        # Przeliczam ml alkoholu na gramy
        return 0.79 * self.getTotalLiquidAlcohol()
 
    def computeAlcoholPromillesPerWeight(self, weight, man = True):
 
        # PRZYBLIZONA zawartosc procentowa plynow ustrojowych w zaleznosci od plci
        humanFluidsPercentage = 0.7 if man == True else 0.6
        return self.getTotalAlcoholInGrams() / (humanFluidsPercentage * weight)
 
    def pourOutDrink(self, amount):
        """
        Metoda wlasciwie niepotrzebna. Mozna wylac (wypic!) czesc zawartosci
        shakera i sobie potem dolewac kolejne skladniki.
        """
        if amount >= self.totalLiquidAmount():
            self._drinkIngredients = {'alcohol' : 0}
        else:
            percentage = amount / self.totalLiquidAmount()
            for key, value in self._drinkIngredients.items():
                self._drinkIngredients[key] -= self._drinkIngredients[key] * percentage

Klasa powy­żej poli­czy to co trzeba. Wyli­cze­nia doty­czące promili w orga­ni­zmie należy trak­to­wać jako mocno przy­bli­żone. Całej dawki alko­holu nie przyj­mu­jemy w końcu w 1 sekun­dzie, orga­nizm na bieżąco spala truci­znę. Poza tym zależy czy i co się jadło itp. itd., nie wiem, nie znam się.
Teraz jesz­cze klasa, która zajmie się wyświe­tla­niem (a raczej metoda statyczna).

class ShakerDisplayer:
 
    def displayShakerDetails(shaker, weight, man = True):
        if not isinstance(shaker, Shaker):
            raise ValueError('Podano argument klasy {}'.format(shaker.__class__))
 
        print('Skladniki drinka:')
        for key,value in shaker.getAllDrinkIngredients().items():
            # Zaokraglamy i wymuszamy 2 miejsca po przecinku
            print('{:.2f}ml {}'.format(value,key))
 
        print('Calkowita zawartosc alkoholu w drinku: {:.2f}%'.format(shaker.getTotalAlcoholPercentage()))
        print('Calkowita zawartosc alkoholu w drinku (wyrazona w gramach): {:.2f}g'.format(shaker.getTotalAlcoholInGrams()))
 
        # Nie znam lepszej metody na wyswietlenie znaku promila niz unicodedata.lookup('PER MILLE SIGN')
        # Ma ktos lepszy pomysl?
        print('Prawdopodobna liczba promili dla {} o wadze {}kg wynosi {:.2f}{}'.format('faceta' if man == True else 'kobiety', weight, shaker.computeAlcoholPromillesPerWeight(weight,man), unicodedata.lookup('PER MILLE SIGN')))

Gdyby potrak­to­wać nasz żołą­dek jak taki shaker, to po wpisa­niu pół litra wódki + 2 piwa + litrowy sprite da nam:

Sklad­niki drinka:
300.00ml wodka
257.00ml alco­hol
1000.00ml sprite
943.00ml piwo
Calko­wita zawar­tosc alko­holu w drinku: 10.28%
Calko­wita zawar­tosc alko­holu w drinku (wyra­zona w gramach): 203.03g
Praw­do­po­dobna liczba promili dla faceta o wadze 89kg wynosi 3.26‰

No nic, na zdro­wie i pozdro dla wszyst­kich Pytho­now­ców! Leniu­chom podaję link do goto­wych plików.

Inne

Python okiem pehapowca

Mamy niedzielę. W ramach leniu­cho­wa­nia zachciało mi się poznać jakiś nowy język progra­mo­wa­nia. Padło na Pythona (nieznacz­nie wygrał z Rubym).

Na pierw­szy rzut oka to w zasa­dzie taki Java­Script ogól­nego prze­zna­cze­nia bez prze­glą­darki. Python rekla­mo­wany jest jako język typu batte­ries inclu­ded, czyli stan­dar­dowa biblio­teka powinna zawie­rać wszystko to, co w typo­wych zasto­so­wa­niach progra­mi­sta potrzebuje.

Od razu widać puryzm kodu Pythona. Żadnych klame­rek, żadnych śred­ni­ków — wszystko zała­twiamy wcię­ciami i końcami linii. „Kompre­sja kodu” widoczna jest na każdym kroku, np. funk­cje dekla­ru­jemy poprzez def, a nie przy­dłu­gawe func­tion, obiekty tworzymy bez new. Weźmy na przy­kład najprost­szą funk­cję żąda­jącą od użyt­kow­nika wpisa­nia z klawia­tury jakiejś liczby:

def getIntInput(message):
    while True:
        try:
            return int(input(message))
        except ValueError:
            print("You were supposed to enter integer!")

W 6 liniach mamy zała­twioną prośbę o wpisa­nie czegoś, prze­two­rze­nie wejścia i wyła­pa­nie ewen­tu­al­nych błędów. Funk­cja nie odczepi się od użyt­kow­nika dopóki nie wpisze popraw­nie jakichś cyferek.

wiek = getIntInput("Podaj rok urodzenia")

Poni­żej w punk­tach cieka­wostki, które w Pytho­nie są, a których nie ma w PHP (tyle co w ciągu kilku godzin udało mi się wyłapać):

  • wspo­mniane już braki klame­rek i śred­ni­ków — czy naprawdę potrze­bu­jemy tego wszyst­kiego w PHP?
  • wszyst­kie metody publiczne — tego nie popie­ram, może powo­do­wać bajzel w API; zgod­nie z konwen­cją metody prywatne należy ozna­czać przed­rost­kiem _
  • fajne konstruk­cje przy itero­wa­niu: for zmienna in array oraz for zmienna in range(5)
  • dziwne zasady doku­men­to­wa­nia kodu — komen­ta­rze idą po dekla­ra­cji klasy czy metody
  • array compre­hen­sion (nawet nie wiem jak to prze­tłu­ma­czyć) — w jednej linijce możemy stwo­rzyć nową tablicę na podsta­wie starej i prze­je­chać jakąś funk­cją po każdej warto­ści przed dodaniem:
    nowaTablica = [funkcja(wartosc) for wartosc in staraTablica]
  • proste loso­wa­nie:
    zagadka = random.choice(["wartosc1","wartosc2","wartosc3"])
  • tuple, czyli nieda­jąca się mody­fi­ko­wać tablica; co ciekawe, funk­cje bardzo często zwra­cają to ustroj­stwo, możemy od razu złapać je do dwóch różnych zmiennych
    wynik1, wynik2 = funkcja()
  • obiekt None zamiast null
  • == i != do spraw­dza­nia warto­ści zmien­nych, isis not do porów­ny­wa­nia z None lub refe­ren­cji, mało tego, możliwa jest konstruk­cja 0 <= a <= 10
  • próba poró­wa­nia if „3” < 4 wywali Type­Er­ror
  • konstruk­cja final do kompletu z try/except
  • bajer dla mnie: if szuka­na­Zmienna in tablica oraz if „wyraz” in przeszukiwanyString
  • nie ma czegoś tak paskud­nego jak RESOURCE

Tyle na począ­tek. Widzę, że Python to fajna sprawa. O wszyst­kim pomy­śleli. Nawet o wbudo­wa­niu bazy danych sqlite w biblio­tekę stan­dar­dową. Jeżeli ktoś waha się czego by tu nowego się pouczyć to polecam!

P.S.: Tak, wiem, na tych waszych poli­bu­dach Pythona uczą już na I roku, ble ble srutu­tutu. Samo­ucy typu np. ja muszą sami. Dobra, kończę, bo i piwo mi się skończyło :-(