Skip to content

fractions Modülü: Tam Hassas Rasyonel Sayılar — 1/3 + 1/6 = 0.5 Kanıtla

Float 0.1'i tam saklayamaz. Decimal saklar ama 1/3'ü değil. Fraction modülü bütün rasyonel sayıları **kesirli** saklayarak tam matematik yapıyor. Bu derste: müzik teorisinde armoni oranları, mutfakta tarif ölçeklendirme, geometrik hesap, bilim simülasyonlarında precision kurtarma — niş ama bilinmesi değerli bir araç.

Şükrü Yusuf KAYA
18 min read
Intermediate
fractions Modülü: Tam Hassas Rasyonel Sayılar — 1/3 + 1/6 = 0.5 Kanıtla
🎵 Bu ders 'niş' ama hayatın bir köşesinde lazım
Fraction modülünü 1000 Python projeniz boyunca belki 1-2 kez kullanırsınız. Ama kullandığınız o anlarda — başka çözüm yok. 1/3'ü tam saklamak, müzik notalarının matematiksel oranlarını korumak, bilim simülasyonlarında accumulated precision loss'tan kaçınmak — bunlar Fraction'ın şahsi alanı.

Önce hatırlatma — niye var?#

Önceki derslerde gördük:
  • float:
    0.1
    saklanırken bozuluyor (binary'de sonsuz tekrar).
  • Decimal:
    0.1
    tam ama
    1/3
    saklayamıyor (decimal'de de sonsuz tekrar: 0.333...).
from decimal import Decimal, getcontext getcontext().prec = 30 print(Decimal(1) / Decimal(3)) # 0.333333333333333333333333333333 (28 hane, sonra kesiyor) print(Decimal(1) / Decimal(3) * 3) # 0.999999999999999999999999999999 (1.0 değil!)
Decimal'da bile precision kaybı var.
1/3 * 3
matematiksel olarak
1
ama Decimal sonsuz tekrar etmediği için
0.999...
.
from fractions import Fraction print(Fraction(1, 3)) # 1/3 print(Fraction(1, 3) * 3) # 1 — TAM! print(Fraction(1, 3) + Fraction(1, 6)) # 1/2 — TAM!
Fraction sayıları payda + pay olarak saklıyor, asla bozmuyor.
1/3
sonsuza kadar
Fraction(1, 3)
olarak duruyor. Ne zaman ihtiyaç olursa float veya Decimal'a çeviriliyor.

Fraction oluşturma yolları#

from fractions import Fraction # 1. İki integer (en yaygın) a = Fraction(3, 4) # 3/4 b = Fraction(1, 2) # 1/2 c = Fraction(-5, 8) # -5/8 # 2. String'den d = Fraction("3/4") # 3/4 e = Fraction("0.25") # 1/4 f = Fraction("3.14") # 157/50 # 3. Float'tan (DİKKAT — float precision sızıyor) g = Fraction(0.1) # 3602879701896397/36028797018963968 (!) # float 0.1 saklanırken bozulduğu için Fraction da o # bozuk değeri tam yansıtıyor # Doğrusu: h = Fraction("0.1") # 1/10 (string'den temiz) i = Fraction(1, 10) # 1/10 # 4. Decimal'dan from decimal import Decimal j = Fraction(Decimal('0.1')) # 1/10 # 5. Tek argüman = integer k = Fraction(5) # 5/1 = 5 # Kontrol attribute'ları print(a.numerator) # 3 print(a.denominator) # 4 print(a) # 3/4 print(repr(a)) # Fraction(3, 4) # Otomatik basitleştirme Fraction(6, 8) # Fraction(3, 4) — GCD 2, otomatik sadeleşti Fraction(100, 25) # Fraction(4, 1) = 4
🎯 Önemli kural:
Fraction(0.1)
yerine
Fraction("0.1")
veya
Fraction(1, 10)
kullan. Aynı şey Decimal için de geçerliydi — float'tan parse alma.

Aritmetik — tam hassas#

from fractions import Fraction a = Fraction(1, 3) b = Fraction(1, 6) # Toplama print(a + b) # 1/2 # Çıkarma print(a - b) # 1/6 # Çarpma print(a * b) # 1/18 # Bölme print(a / b) # 2 (Fraction(2, 1)) # Üs print(a ** 2) # 1/9 print(a ** -1) # 3 (tersi) print(a ** Fraction(1, 2)) # ~0.577 — float'a düşer (kare kök rasyonel değil) # Karşılaştırma — tam doğru print(Fraction(1, 3) == Fraction(2, 6)) # True (otomatik basitleştirme) print(Fraction(1, 3) < Fraction(1, 2)) # True # Float'la karışık print(Fraction(1, 2) + 0.5) # 1.0 (float dönüyor — Python promotion) print(Fraction(1, 2) + Fraction(1, 2)) # 1 (Fraction kalıyor) # Klasik 0.1 tuzağına Fraction çözümü print(Fraction("0.1") + Fraction("0.2") == Fraction("0.3")) # True!
Fraction'ın aritmetiği "matematik kitabındaki gibi". Cebirsel manipulation için ideal.

Float ve Decimal'a dönüşüm#

Fraction sonuçta gösterilirken float'a çevrilebilir:
from fractions import Fraction from decimal import Decimal f = Fraction(1, 3) # Float'a (precision kaybeder, ama gösterim için OK) print(float(f)) # 0.3333333333333333 # Int'e (truncation) print(int(Fraction(7, 2))) # 3 (sıfıra doğru) # Decimal'a doğrudan dönüşüm (3.10+) print(Decimal(Fraction(1, 4))) # 0.25 # print(Decimal(Fraction(1, 3))) # InvalidOperation — sonsuz tekrar # Decimal'a hassas dönüşüm def fraction_to_decimal(f, precision=28): """Fraction → Decimal, ihtiyacın kadar precision ile.""" from decimal import Decimal, getcontext with localcontext() as ctx: ctx.prec = precision return Decimal(f.numerator) / Decimal(f.denominator) # String formatlama f = Fraction(1, 3) print(f"{float(f):.10f}") # 0.3333333333 print(f"{f}") # 1/3 — direkt repr

limit_denominator
— yaklaşık rasyonel#

Bir float'u veya Fraction'ı, küçük paydaya sahip bir Fraction ile yaklaşık temsil etmek için:
import math # π'nin rasyonel yaklaşımları pi = Fraction(math.pi) print(pi) # 884279719003555/281474976710656 (uzun) print(pi.limit_denominator(10)) # 22/7 — klasik π yaklaşımı (3.142...) print(pi.limit_denominator(100)) # 311/99 print(pi.limit_denominator(1000)) # 355/113 — tarihsel olarak ünlü, çok hassas print(pi.limit_denominator(10000)) # 355/113 (aynı — bu paydası ile aşılamıyor) print(pi.limit_denominator(1000000)) # 3126535/995207 # 0.3333333... → 1/3 Fraction(0.3333333).limit_denominator(100) # 1/3
Bu özellik müzik teorisinde ve mühendislikte çok kullanışlı — büyük rasyonel'i basit kesirle yaklaşık göstermek.

Gerçek dünya 1: Müzik teorisi#

Müzikte armonik aralıklar (intervals) frequency ratio'larıdır. Tüm tarihsel temeli kesirler:
from fractions import Fraction # Pisagor armonik aralıkları (just intonation) INTERVALS = { "Unison": Fraction(1, 1), # Aynı nota "Minor 2nd": Fraction(16, 15), # 256/243 alternatif "Major 2nd": Fraction(9, 8), # Tam ton "Minor 3rd": Fraction(6, 5), "Major 3rd": Fraction(5, 4), # En "yumuşak" armonik "Perfect 4th": Fraction(4, 3), "Tritone": Fraction(45, 32), "Perfect 5th": Fraction(3, 2), # En önemli — Pisagor'un keşfi "Minor 6th": Fraction(8, 5), "Major 6th": Fraction(5, 3), "Minor 7th": Fraction(9, 5), "Major 7th": Fraction(15, 8), "Octave": Fraction(2, 1), # Frekans iki katı } # A4 = 440 Hz başlangıç A4 = 440 print(f"{'Aralık':<15} {'Oran':<10} {'Frekans (Hz)':<15} {'Cent':<8}") print("-" * 50) for name, ratio in INTERVALS.items(): freq = A4 * float(ratio) cents = 1200 * math.log2(float(ratio)) print(f"{name:<15} {str(ratio):<10} {freq:<15.2f} {cents:<8.1f}")
Çıktı:
Aralık Oran Frekans (Hz) Cent -------------------------------------------------- Unison 1/1 440.00 0.0 Major 2nd 9/8 495.00 203.9 Major 3rd 5/4 550.00 386.3 Perfect 5th 3/2 660.00 702.0 Octave 2/1 880.00 1200.0
Equal temperament (modern piyano akort) bu kesirlere yaklaşık ama tam değil
2^(1/12)
üzerine kurulu. Just intonation (kesirli) "matematiksel olarak saf" ama her tonalitede çalışmıyor; bu yüzden 1700'lerden beri equal temperament tercih ediliyor.
Müzik üreten kod yazıyorsan (synthesizer, müzik teorisi yazılımı, oyun ses motoru) Fraction tam armonik oranları korumak için ideal.

Gerçek dünya 2: Tarif ölçeklendirme#

Tarifte "1/3 cup un, 2/3 cup süt, 1/4 tsp tuz" yazıyor. 6 kişilik tarif var, sen 4 kişi için pişirmek istiyorsun. 2/3 oranında ölçeklendirmen lazım.
from fractions import Fraction class Recipe: def __init__(self, name, servings, ingredients): self.name = name self.servings = servings self.ingredients = ingredients # list of (amount: Fraction, unit, name) def scale(self, target_servings): ratio = Fraction(target_servings, self.servings) new_ingredients = [ (amount * ratio, unit, name) for amount, unit, name in self.ingredients ] return Recipe(self.name, target_servings, new_ingredients) def __repr__(self): lines = [f"=== {self.name} ({self.servings} kişi) ==="] for amount, unit, name in self.ingredients: # Fraction'ı güzel yazdır if amount.denominator == 1: amt_str = str(amount.numerator) else: whole = amount.numerator // amount.denominator remainder = Fraction( amount.numerator % amount.denominator, amount.denominator ) if whole == 0: amt_str = str(remainder) else: amt_str = f"{whole} {remainder}" lines.append(f" {amt_str} {unit} {name}") return "\n".join(lines) # 6 kişilik kek tarifi cake = Recipe("Çikolatalı kek", 6, [ (Fraction(1, 3), "cup", "un"), (Fraction(2, 3), "cup", "şeker"), (Fraction(1, 2), "cup", "süt"), (Fraction(1, 4), "tsp", "tuz"), (Fraction(2, 1), None, "yumurta"), (Fraction(3, 4), "cup", "kakao"), ]) print(cake) print() # 4 kişiye ölçekle print(cake.scale(4)) print() # 9 kişiye ölçekle (büyütme) print(cake.scale(9))
Çıktı:
=== Çikolatalı kek (6 kişi) === 1/3 cup un 2/3 cup şeker 1/2 cup süt 1/4 tsp tuz 2 None yumurta 3/4 cup kakao === Çikolatalı kek (4 kişi) === 2/9 cup un 4/9 cup şeker 1/3 cup süt 1/6 tsp tuz 1 1/3 None yumurta 1/2 cup kakao
Float'la yapsaydın
0.222222... cup un
olurdu — okuyamazdın. Fraction "1/3 cup" net.
Bu pattern e-ticaret B2B catalog ölçeklendirme, kimya stökiometrisi, inşaat malzeme hesabı gibi yerlerde de işe yarar.

Karar matrisi: Fraction vs Decimal vs float#

KriterfloatDecimalFraction
Saklama tabanıBinaryDecimalPay/payda
Precision~15 hane (sınırlı)AyarlanabilirSonsuz (rasyonel için)
0.1 + 0.20.300000000000000040.3 ✅3/10 ✅
1/3 + 1/3 + 1/31.0 (genelde)0.999...1 ✅
Yuvarlama kontrolüYok✅ ROUND_* modesİhtiyaç yok (exact)
PerformansEn hızlı (donanım)Yavaş (~50x)Çok yavaş (~100x)
Para hesabı❌ (UI gösterimi garip)
Bilim simülasyonuYavaş
Cebir, tam oran
Müzik teorisi
JSON serializeDoğalCustom encoderCustom
NumPy desteği✅✅⚠️ object dtype
Pratik karar:
  • Para → Decimal.
  • Bilim/AI/grafik/genel → float.
  • Saf rasyonel matematik (cebir, geometri, müzik) → Fraction.
  • Tam hassasiyet gerekiyor ama yuvarlama yok → Fraction.
Hayatın boyunca Fraction kullanma sıklığı: float >> Decimal >> Fraction. Ama gerektiği yerde başka çözüm yok.

Pratik: Olasılık hesabı tam fraction#

Bilim/istatistik dersinde olasılıkları kesin vermek istersen:
from fractions import Fraction # Bir torbada 5 kırmızı, 3 mavi, 2 yeşil top # Toplam 10 top red = Fraction(5, 10) # 1/2 blue = Fraction(3, 10) green = Fraction(2, 10) # 1/5 # Toplam olasılık 1 (kontrol) print(red + blue + green) # 1 # İki kırmızı top art arda (replacement-without) two_red = Fraction(5, 10) * Fraction(4, 9) print(two_red) # 2/9 ≈ 0.222 # Kırmızı sonra yeşil red_then_green = Fraction(5, 10) * Fraction(2, 9) print(red_then_green) # 1/9 ≈ 0.111 # En az bir kırmızı (3 atış, replacement) no_red_3_throws = (Fraction(5, 10)) ** 3 # tüm 3 atışta non-red yok # = (1/2)^3 = 1/8 at_least_one_red = 1 - no_red_3_throws print(at_least_one_red) # 7/8 # Float yaklaşık print(float(at_least_one_red)) # 0.875 # Kayıpsız hesap — bilim makalesinde "0.875 değil 7/8" demek istiyorsan, Fraction
Yapay zekâ algoritmalarında olasılık hesabı (Bayesian inference) kesinlik gerekirse Fraction tercih edilir. Pratik AI kütüphaneleri (PyTorch, scikit-learn) float kullanıyor — performans için. Ama akademik/araştırma kodunda bazen Fraction görürsün.

Yaygın tuzaklar#

1.
Fraction(0.1)
yapma#

# 🚫 Fraction(0.1) # Fraction(3602879701896397, 36028797018963968) # float 0.1 saklanmış halini Fraction'a aktarıyor # ✅ Fraction("0.1") # Fraction(1, 10) Fraction(1, 10)

2. Fraction'ı UI'da göstermek#

# 🚫 Para gösterimi amount = Fraction(1, 3) * 100 # 100/3 print(amount) # 100/3 — UI'da "100/3 ₺"? # ✅ print(f"{float(amount):.2f} ₺") # 33.33 ₺
UI gösterimleri için float veya Decimal'a çevir.

3. Performance — döngüde Fraction yaratma#

# 🚫 for _ in range(1_000_000): f = Fraction(1, 3) # her iter'de yeni nesne — yavaş # ✅ ONE_THIRD = Fraction(1, 3) for _ in range(1_000_000): f = ONE_THIRD # reuse

4. Float'la karışık aritmetik#

# Sonuç float'a düşüyor (precision kaybediyor) result = Fraction(1, 3) + 0.5 # 0.8333333333333333 (float) # Doğrusu — hep Fraction kal result = Fraction(1, 3) + Fraction(1, 2) # 5/6 (Fraction) # Veya en sonunda dönüştür result = Fraction(1, 3) + Fraction(1, 2) final_display = float(result)

5. JSON serialize#

Fraction'ı JSON'a koymak otomatik değil — string olarak ya da numerator/denominator ayrı sakla.
import json f = Fraction(3, 4) # Yöntem 1: string json.dumps({"value": str(f)}) # {"value": "3/4"} # Yöntem 2: ayrı alan json.dumps({"num": f.numerator, "den": f.denominator}) # {"num": 3, "den": 4} # Yöntem 3: float (precision kaybı) json.dumps({"value": float(f)}) # {"value": 0.75}

Bu derste neler kazandın?#

Fraction'ın gerekli olduğu durum: float ve Decimal'in dahi temsil edemediği rasyonel sayılar.
Fraction oluşturma yolları: integer pair, string, float (dikkat!), Decimal, integer.
Aritmetik tam hassas:
1/3 * 3 = 1
,
1/3 + 1/6 = 1/2
.
Float ve Decimal'a dönüşüm:
float()
,
Decimal()
.
limit_denominator()
— büyük kesri küçük paydaya yaklaşık (π → 22/7).
Müzik teorisi uygulaması — armonik intervalleri tam oranlarla.
Tarif ölçeklendirme — Recipe sınıfı, scale method.
Karar matrisi: Float vs Decimal vs Fraction — ne zaman hangisi.
Olasılık hesabı — kesin Fraction olarak (1/2 yerine 0.5).
5 yaygın tuzak — Fraction(0.1), UI gösterimi, performans, float karıştırma, JSON.
Sıradaki ders:
bool
ve
None
.
True
aslında
int
'in alt sınıfı (
True == 1
!), her tip "doğru/yanlış" değerlendirilebilir (truthiness),
None
sentinel'ı,
is None
vs
== None
kritik fark,
Optional
type hint. Küçük kavramlar ama her gün karşına çıkacak.

Frequently Asked Questions

Bağlama bağlı. Müzik yazılımı, akademik bilim simülasyonu, sembolik matematik (SymPy) — Fraction doğru. Para hesabı ya da genel iş kodunda — hayır, Decimal/float tercih edilir. 'Niş bir alan' demek 'yanlış' değil, 'spesifik kullanım' demek.

Yorumlar & Soru-Cevap

(0)
Yorum yazmak için giriş yap.
Yorumlar yükleniyor...

Related Content

fractions Modülü: Tam Hassas Rasyonel Sayılar — 1/3 + 1/6 = 0.5 Kanıtla | Python Programlama