En kısa kod satırı kullanımı ile asal sayıları bulma

Programlama eğitimi verdiğim için öğrencilerimi her zaman en kısa kodla programlarını yazmayı tavsiye ederim. Bu bazen benim için de oldukça şaşırtıcı sonuçlar çıkarabiliyor ve benim de yeni şeyler öğrenmemi sağlıyor.

Sorumuz basit: 1000 e kadar olan asal sayıları yazdıran bir program yazınız. (Tabiki en kısa kod satırını kullanarak)

Daha kısası olabilir gibi geliyor ama tek satırlık bir cevap yazdım:

Cevap
print(*list(filter(lambda x: False if True in [x%i==0 for i in range(2, x)] else True, range(2, 1000))))
3 Beğeni

Bu tabi üst düzey bir cevap olmuş :slight_smile: sonuçta ortaokul öğrencilerini düşünürsek bu şekilde cevap verebilecek düzeyde değiller

Merhaba @sonsuz hocam,
Ben sizin gibi bir eğitmen değilim belki. Ama şahsen kısa kod yazmak yerine kendisine verilen kaynakları iyi değerlendiren kodun daha önemli olduğunu düşünüyorum(belki ortaokul öğrencileri için geçerli olmayabilir bilemem). Bence bırakın implementation daha uzun olsun. Ama sizin bulunduğunuz şartları da bilemiyorum.
Saygılar.

5 Beğeni

Akıl yaşta değil baştadır diye düşünürsek bunu ilkokul öğrencileri de yapabilir.

1 Beğeni

Ben tabi haliyle şöyle bir kod bekliyorum öğrencilerden.

for sayi in range(2,1000):
    asal = True
    for bolen in range(2,sayi//2):
        if sayi%bolen==0:
            asal = False
    if asal:
        print(sayi, end = ", ")
1 Beğeni

Fakat bir öğrencim şöyle bir kod gönderdi.

for i in range (2,1000):
    for a in range (2,i//2):
        if (i%a)==0:
            break
    else:
        print (i,end=", ")

Programa bakınca bütün sayıları yazdırır diye düşündüm ilk başta elseyi if’e bağlı olarak değerlendirdim. Sonra else nin if’e değil de for döngüsüne bağlı olduğunu gördüm. Bu beni şaşırttı diyebilirim. C/C++ programlamadan geldiğim için alışık olmadığım bir görüntüydü.

Şaşırmaya devam etmek güzel bir şey.

1 Beğeni

Merhaba, ben de ufak bir fikir vermek isterim.

era = [0 for i in range(1001)]
for i in range(2, 1001):
    if(era[i] == 0):
        print(i)
        k = i + i
        while(k < 1001):
            era[k] = 1
            k += i

Eratosthenes kalburu. Sıklıkla kullanılır.
Öğrencinizin kodunu aşağıdaki gibi düzeltsek daha optimize olur.

from math import sqrt
for i in range (2,1000):
    for a in range (2,int(sqrt(i))):
        if (i%a)==0:
            break
    else:
        print (i,end=", ")

Neyse her üç kodu da test edelim(testin doğru sonucu vereceğini garanti edemeyiz ama aralık ne kadar büyük olursa doğruluk payı o kadar artar. O yüzden kodlarda ufak değişiklikler yaptım. Hatamız varsa affola.)

from timeit import timeit as tit

testcode1 = """
prime = []
era = [0 for i in range(1000001)]
for i in range(2, 1000001):
    if(era[i] == 0):
        prime.append(i)
        k = i + i
        while(k < 1000001):
            era[k] = 1
            k += i
"""

testcode2 = """
prime = []
from math import sqrt
for i in range (2,1000000):
    for a in range (2,int(sqrt(i))):
        if (i%a)==0:
            break
    else:
        prime.append(i)
"""

testcode3 = """
prime = []
for i in range (2,1000000):
    for a in range (2,i//2):
        if (i%a)==0:
            break
    else:
        prime.append(i)
"""



print("testcode1", tit(stmt = testcode1, number = 1))
print("testcode2", tit(stmt = testcode2, number = 1))
print("testcode3", tit(stmt = testcode3, number = 1))

outputs:

testcode1 0.3228799
testcode2 4.667852399999999
# [hesaplamasını bekliyorum, hesabı bitirebilirse editleme de yapacağım.]

Gerçekten ben de çok şaşırdım. Tesadüfe bak ki face gruplarından birinde daha böyle bir şey görmüştüm de kodu çalıştırmaya üşendiğimden(yani telde olduğumdan kodu çalıştırmadım) yanlış olduğunu düşünmüştüm. İlginç :thinking:

Edit: Sayın Seyirciler, Baylar ve bayanlar, işte karşınızdaaaa

testcode3 1398.2167295

Edit 2: Özür dilerim, tescode1 kodunu yeniden editledim. Ama yine de pek bir değişiklik olmadığını söyleyebilirim. Şöyle ki.

testcode1 0.46847779999999994
1 Beğeni

Bu fonksiyonun implementasyonu hakkında bir varsayımda bulunuyor. Kaynağınız var mı?

Üstteki yazıyı yazarken araştırmadım. Ama bir zamanlar araştırmıştım. Aklımda log2(n) diye kalmış.

Kaynağım sağlam bir kaynak değil.
Yanlış bilgi verdiğimi düşünüyorsanız beni bilgilendirerek hatalarımı düzeltebilirsiniz.

CPython’un math.sqrt'yi nasıl impleme ettiğini bilmiyorum. 5 dakikadır kaynak kodlarına bakıyorum ama sadece isqrt’yi bulabildim, o da tahmin ettiğim gibi 64bit sayılar için fast path kullanıyor (bu da implementasyondaki optimizasyonların karmaşıklığı nasıl etkilediğine bir örnek).

Ama günümüzde çoğu işlemcinin float’ların karekökünü almaya özel instruction’ları (talimat?) var. Yani kök alma işlemi yazılım değil donanım seviyesinde gerçekleşiyor. Bu da kök işlemini O(1) civarına indiriyor.

1 Beğeni

En kısa olanı değil en okunabilir olanı yazmalarını tavsiye etmelisiniz bence

2 Beğeni

Zaten onu anlatmak istemiştim. Nasıl gereksiz kod kullanıp uzattıklarını görseniz. Kısa, net anlamında kullandım.

1 Beğeni

[print(n)for n in range(2,999)if all([n%i!=0 for i in range(2,n)])]

3 Beğeni

Eratosthenes kalburu kadar zaman kazandırmasa da ilk koda göre daha hızlı bir yöntem.

asallar = [2]
for sayi in range(3,1000000):
    for bolen in asallar:
        if sayi%bolen==0:
            break
    else:
        asallar.append(sayi)
print(asallar)
2 Beğeni
import re

asal_degil = re.compile(R"^1?$|^(11+?)\1+$")
kaca_kadar = 1_000
asallar = [sayi
           for sayi in range(kaca_kadar)
           if not re.search(asal_degil, "1"*sayi)]
1 Beğeni

Cok bariz bir seyi atlamisim:

[print(n)for n in range(2,999)if all([n%i for i in range(2,n)])]

Sonuca ulasamayan bir takim denemeler:

[print(n)for n in range(2,999)if all(map(lambda i:n%i,range(2,n)))]
print(list(filter(lambda n:all([n%i for i in range(2,n)]),range(2,999))))
print(list(filter(lambda n:all(map(lambda i:n%i,range(2,n))),range(2,999))))
list(map(lambda n:print(n)if all(map(lambda i:n%i,range(2,n)))else 0,range(2,999)))
print(reduce(lambda p,n:p+[n]*all([n%i for i in p]),range(2,999),[]))
print(list(map(lambda n:all(map(lambda i:n%i,range(2,n))),range(2,999))))
1 Beğeni

Konu eski ve çözülmüş bir durum ama üzerinde konuşmaya değer.

Özellikle bu kısım zaten hoşuma gidip üzerinde konuşmaya değer bulduğum kısım.

Farklı dillerin eski versiyonlarını bilen dil sınıflandırma yaklaşımlarının bir kaçına bakan biri için aslında anlaşılabilir bir durum.

C/C++, Pascal gibi dillerde kod satır şeklinde işlenmez. Bloklar halinde işlenir yanı bloğun başlangıcını ve bitişini koda ayrıca bildirmeliyiz.

Mesela bunu c de { } küme parantezleri ile yaparız. Blok nerede başlar bildirir sonra nerede biter onu da ayrıca bildiririz. Bu parantezler olmadığında kod çalışmaz kodun nerede başlayıp bittiğini anlayamaz. Bu da yetmez bir kaç bloktan oluşan kod da oluşturabilir bir de komple kodu bitireyim diye sonuna ; noktalı virgül bildirimi ister mesela if koşullu karşılaştırmasında hem bloğu hemde else bağlantılarını ayrıca bildirmek ve else lerin bittiğini de ayrıca noktalı virgülle bildirmek gerekir.

Pascal bu işe daha da ilginç yaklaşır. Madem başlangıç ve bitiş bildireceğim ve yüksek seviye dilim o zaman begin ve end bildirimleri arasında yazalım blokları buradan anlarız gibi yaklaşım getiriyor kodun yarısı begin end lerle dolu oluyor.

Basic ve python gibi yorumlanan diller önden bir compile edilmeyeceği için (aslında belleğe yerleştirirken bir precompile durumu var ama konumuz bu değil) satır satır alıp işler. Yani beklenti satırlar içerisindedir ve bir sonraki satırda olup biteceklerin icabına sonra bakarız yaklaşımı vardır. Tabi kapsam/scope durumu biraz yanıltıcı olabilir sadece o satıra indiğinde anlamlı olarak faydalanılır ama önden o scope için pek ön almaz (optimizasyon da konumuz dışı o konuda da istisnalar var)

Bu durumda pyrhon içinde anahtar kelimeleriniz bloklanmadığından kapsamı nereye bağladığınız biraz kendi sorumluluğunuzda kalıyor bu nedenle şaşırmamak gerekir.

Ha madem başlığa girdik biraz faydası olsun kod konusunda da bir iki çift kelam edelim.

Bu asal sayı kodları neden öğrencilere öğretiliyor diye merak ediyorum açıkcası. Yani hani kriptografide asal sayı içeren fonksiyonlar aranan özelliktir, ne kadar büyük ve iyi bir asal sayınız varsa kriptografiniz o kadar geri döndürülemez şekilde olur mantığını anlarım.

Ama zaten böyle bir şeyle uğraşan çok az kişi vardır ve zaten bunlar da ilk bin asal sayı ile ilgilenmezler bile. Onlar bulabildiikleri en büyük asalsayının peşindelerdir.

Konumuz öğrenci ise hadi çocuklar asal sayı nedir biliyorlardır. Madem bildikleri bir konu Bunun üzerinde uygulama yaptırırsak programlamanın ne faydası var yada nasıl yapılır güzel bir egzersiz olabilir diye düşünülüyor herhalde.

Sonuçta, for, if döngüsü çalıştırmak için bildikleri bir konunun kuralları üzerinden yürümek faydalı olabilir. Belki (?!)

Bir bilgisayarın en iyi yaptığı işin iterasyon olduğunu düşünürsek tekrarlayan işleri yaptırmaya çalışmak ve bunu koşullara göre tekrarlatmak evet mantlıklı.

Yani eğitim amaçlı bir enstrüman olmuş asal sayılar.

Bu nedenle insanlık için küçük ama öğrenciler için büyük bir konu olmuş.

Olaya yeni bir yaklaşım getirmek adına şunu söyleyebilirim, evet bilgisayarlara tekrarlanan işlemler yaptırmak iyidir ama bu demek değildir ki olaya matematiksel olarak da bakılmasın.

Öğretim amaçlı kısımda tamam onlar dümdüz devam etsinler ama normal bir programcı olarak her zaman sınırlar olmalıdır. Ekonomi gibi, sonsuz isteklerle sınırlı kaynakların denkleştirilmesi ekonominin tanımıdır (Üretim planlama hocamın da kulakları çınlasın.)

Bu durumda malın zaman faydası, malın yer faydası gibi konulara da giresim var da neyse.

Yani her zaman gerçek dünyada size yeterli bellek, yeterli zaman verilmiyor olabilir. Bu durumda bazan düşündüğünüz gibi dümdüz gidemeyebiliyorsunuz.

Koşulları değiştirelim. Bellek sıkıntımız yok, zaman sıkıntımız var ne yaparız? Algoritmamızın en az iterasyonla yada en az koşulla bu işi yapmasını istesek neler yapabiliriz?

Gerçi python kullanan birinin bellek ve zaman kaygısı olmalımıdır o da ayrı bir konu.

Ama oldu ya kafa yorduk diyelim.

Olaya bu yöndem bakmak istedim. Şöyle ufak bir internet taraması.

Ve farklı bir yaklaşım buldum.

Tabi ki daha iyileri de araştırlabilir konu bellek olduğunda farklı yaklaşım gerekebilir ama biz iterasyon azaltabilir miyiz diye bakıyoruz varsayalım.

Şimdi bunu da lambda tek satıra da yazarız da üzerinde konuşulabilsin diye insan kodu olarak bırakmaya karar verdim:

import math
def is_prime(n):
  for i in range(2,int(math.sqrt(n))+1):
    if (n%i) == 0:
      return False
  return True

Kaynak: How to Check if a Number is Prime in Python - Geekflare

Neden böyle bir şey yapmış?

Onu da kaynakta grafiklerle açıklamış.

Tabi sizin öğrenciler bununla uğraşsın diye yazmadım bunları ama bir kod varsa kodun amacı da olmalı. Öğrenciler için koşul ve iterasyon egzersizi, programcılar ve matematikçiler için de asal sayı ve matematik egzersizi olarak bakmak gerekir diye düşünüyorum.

Kolay gelsin.

Bu arada kod üzerinde tartışabiliriz. Sizce yaklaşım mantıklı ?

1 Beğeni

Asal sayılar klasik sorulardan birisi. Bölünebilme var, karşılaştırma var, döngü var, hatta iç içe döngü var. Burada amaç aslında basit ve anlaşılabilir bir şey üzerinden kodlama mantığını anlatmak.

Bu konularda klasik sorularım var belki diğer öğretmenler yapmıyordur bilemiyorum.

Mesela karşılaştırmalar (karar verme, if) konusundan sonra illa ki, üç sayı istetip bu sayıların üçgen olup olmadığını, üçgense ne tür bir üçgen olduğunu (eşkenar, ikizkenar, dik üçgen ve çeşit kenar gibi) yaptırırım.

Bir de fonksiyonlar konusundan sonra mutlaka mükemmel sayılar, zengin sayılar, arkadaş sayılar soruları da klasiklerimin arasındadır.

def is_prime(n):
  for i in range(2,int(n**0.5)+1):
    if (n%i) == 0:
      return False
  return True

Şu kod için de math kütüphanesini eklemeden daha iyi değil mi sanki bilemedim.

Tercih meselesi, burada önemli olan karekök alma yaklaşımının performansı. Bu karakökü çok farklı şekillerde alabilirsiniz, C gibi bir dilde bitshift yaparak bile alabilirsiniz o kısmı tercih.

Burada önemli olan matematiksel yaklaşım. Belki daha iyi yaklaşımlar da vardır. Literatürü taramak lazım.

Eğitimci değilim, yani en azından yetiişkin eğitimi dışında bir eğitim bilgim yok beni aşar yaklaşımınız. Sadece bakınca bir de bu işe reküsif/özyinelemeli fonksiyon soruları da geldi aklıma onu da çok sever eğitimciler.

1 Beğeni