Ondalıklı sayıyı, Kesirli hale dönüştür

Herkese Merhaba,
Bir süredir yazmaya çalıştığım kodu sonunda tamamlayabildim.
Yapmak istediğim şey;
Kullanıcı tarafından girilen Ondalıklı sayıyı, Kesirli hale dönüştüren program yazmaktı.
Örneğin kullanıcı 0.75 değerini girdiğinde program bu sayının karşılığı olan 3 / 4 çıktısını sunacak.

Hâlâ acemi bir kullanıcı olduğumu bilerek kodu yorumlar mısınız?
kodu geliştirme yönünde ne yapabilirim?
sağlıcakla kalın.

'''
Created on Fri Apr 16 21:10:17 2021
@author: Mustafa Halil  ( https://github.com/mhalil _ https://twitter.com/AcikKaynakci )

Belirtilen Ondalıklı sayıyı, Kesirli hale dönüştüren program.

Örnek çıktılar;
0.75 sayısının kesirli gösterimi: 3 / 4
1.25 sayısının kesirli gösterimi: 5 / 4

'''

sayi = float(input("Kesirli halini görmek istediğiniz ondalıklı sayıyı yazın:"))

bol = str(sayi).split('.')      # girilen sayıyı tamsayı ve ondalık kısma böl, liste halinde tut

ts = int(bol[0])                # sayının tamsayı kısmı
ond = int(bol[1])               # sayının ondalık kısmı
ond_uzn = len(str(ond))         # ondalık kısmın basamak sayısı

pay = int(str(ts) + str(ond))   # pay sayı değeri
pyd = 10 ** ond_uzn             # payda sayı değeri

def carpan(sayi):               # belirtilen sayı değerini çarpanlara ayırıp liste halinde geri döndüren fonksiyon.
    lst = [1]
    bolen = 2

    for i in range(1,sayi):
        if sayi % bolen == 0:
            sayi /= bolen
            lst.append(bolen)
        else:
            bolen += 1
    return lst
 

def carp(liste):                # belirtilen liste içerisindeki tüm değerleri çarpıp sunuç döndüren fonksiyon. (liste içerisi sadece sayıdan oluşmalı)
    sonuc = 1
    if liste == []:
        sonuc = 1
    else:
        for i in liste:
            sonuc *= i
    return sonuc


pay_carpan = carpan(pay)           # pay sayı değerini çarpanlarına ayır, listele
payda_carpan = carpan(pyd)           # payda sayı değerini çarpanlarına ayır, listele


def sil(a, l1, l2):             # 2 liste (l1 ve l2) içerisindeki ortak sayı değerini (a) silen fonksiyon.
    if ((a in l1) and (a in l2)):
        l1.remove(a)
        l2.remove(a)

index = 0

while index <= len(pay_carpan):    # index değeri, pay değerinin çarpanları sayısından küçük eşit olduğu sürece döngüyü çalıştır.
    try:
        a = pay_carpan[index]       # pay'ın tek çarpanlar değeri
           
        if a in payda_carpan:                   # eğer pay'ın çarpan değeri payda çarpan listesinde varsa ...
            sil(a, pay_carpan, payda_carpan)    # ortak çarpan değerini sil
        else:                                   # değilse
            index +=1                           # pay çarpan listesindeki sonraki sayıya geçmek için index değerini 1 artır.
         
    except IndexError:              # IndexError hatası alırsak ...
        break                       # döngüyü sonlandır / bitir.

print(sayi, "sayısının kesirli gösterimi:", carp(pay_carpan),"/", carp(payda_carpan)) # pay çarpanlarındaki değerlerle, payda çarpanlarındaki  değerleri (her iki listedeki ortak değerler silindikten sonra) kendi içerisinde çarp ve sonuç olarak ekrana yazdır.
2 Beğeni

Bütün çarpanları bulup işlem yapmanıza gerek yok, EBOB’u daha kolay hesaplayabilirsiniz:

def ebob(x, y):
    while y:
        r = x
        x = y
        y = r % y
    return x

def çevir(tam, kesir):
    payda = 10 ** len(kesir)
    kesir = int(kesir)
    bölen = ebob(kesir, payda)
    payda //= bölen
    kesir //= bölen
    tam = int(tam) * payda
    pay = kesir + tam
    return f"{pay}/{payda}"

tam, kesir = input().split(".")
print(çevir(tam, kesir))

Standart kütüphane ile de işlem çok daha kolay bir şekilde yapılabilir:

from decimal import Decimal

print("{}/{}".format(*Decimal(input()).as_integer_ratio()))
1 Beğeni

Bu kısmı

şununla değiştirebilirsiniz

        for deger in liste:
            sonuc *= deger

zira eğer liste boşsa for hiç dönmez ve başta yazdığınız sonuc = 1'den dolayı fonksiyon yine 1 döndürür. Bir de if liste == [] yerine if not liste'yi tercih edebilirsiniz daha “pythonik” olsun diye, elinize sağlık

1 Beğeni

çok mantıklı,
yazdığınız kodları anlamam biraz vakit aldı ama anladım.
yazdığım kodlarda ebob’u oluşturan sayılarla tek tek uğraşmışım. resmen alememlik yapıyormuşum :slight_smile:
çok teşekkür ederim, ufkum açıldı.

Çok teşekkür ederim.
bu şekilde kodlamak hiç aklıma gelmezdi.
sağ olun, var olun.

Kesirli halini görmek istediğiniz ondalıklı sayıyı yazın:0.001
0.001 sayısının kesirli gösterimi: 1 / 10

Kesirli halini görmek istediğiniz ondalıklı sayıyı yazın:.00005
Traceback (most recent call last):
File “a.py”, line 17, in
ts = int(bol[0]) # sayının tamsayı kısmı
ValueError: invalid literal for int() with base 10: ‘5e-05’

Kesirli halini görmek istediğiniz ondalıklı sayıyı yazın:.9999999999

Kesirli halini görmek istediğiniz ondalıklı sayıyı yazın:.99999999999999999999999999
1.0 sayısının kesirli gösterimi: 1 / 1

Kesirli halini görmek istediğiniz ondalıklı sayıyı yazın:1.1000000000001


Test case’leri ekleyebilirsin. Su halde kodda degisiklik yapmak cok zor, cunku her degisiklikten sonra 2-3 dakika test etmek gerekiyor (veya test etmeyip hatali kod uretiyoruz, yukaridaki orneklerdeki gibi)

Illa unittest kullanmana gerek yok, ufak programlarda alt alta assert'ler de isi goruyor:

assert kesirli(".1") == (1, 10)
assert kesirli(".01") == (1, 100)

Hmm, simdi fark ettim ki bunu yapmadan once verilen ondalikli sayiyi kesirli hale donusturen bir fonksiyon yazman lazim. Yukaridaki kesirli gibi.

1 Beğeni

Cevabınız için teşekkür ederim.
Bu kodu yazmama neden olan şey;
tweeter’da takip ettiğim bir kullanıcının sorduğu soruları çözmek için kod yazmak ve python pratiği yapmak idi.
Ancak python ile matematik sorularını çözen kod yazdığımda çıkan sonuçlar her zaman float oluyordu.
Şıklar kesirli sayılardan oluştuğu için direkt cevabı bulamıyordum, tek tek şıklardaki kesirli değerleri ondalıklı sayıya çevirmem gerekiyordu.

Yazdığım Kodlar hatalı ancak şimdilik doğru şıkkı bulabiliyorum :slight_smile:
assetr ve test konularını araştıracağım, tektat teşekkürler.