Ana içeriğe geç
Kesit Python
Temel · Değerler ve metinler

Sayılar ve işlemler

Aritmetik işlemleri, tam bölme ve kalanı, üs almayı, yuvarlamayı, kayan nokta hatasını ve math modülünü Ilgaz Bank faiz hesabı üzerinden öğrenirsin.

Uygulamada aç, 19 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

Sayılar neden bu kadar önemli?

Ilgaz Bank'ta bir mevduat hesabının faizi, Anadolu Market'te bir sepetin indirimli tutarı, bir kargonun kaç kutuya sığacağı... Hepsi sayı işlemi. Python'ın aritmetiği hesap makinesine benzer ama birkaç yerde sürpriz yapar: bölme hep ondalıklı sonuç verir, ondalıklı sayılar bazen "yanlış" görünür ve yuvarlama sandığın gibi çalışmaz. Bu derste bu sürprizlerin hepsini önceden göreceksin.

Temel operatörler

bakiye = 10000
print(bakiye + 2500)     # toplama
print(bakiye - 750)      # çıkarma
print(bakiye * 1.05)     # çarpma
print(bakiye / 3)        # bölme: her zaman float
print(bakiye // 3)       # tam bölme: ondalık atılır
print(bakiye % 3)        # kalan (mod)
print(2 ** 10)           # üs alma

En çok dikkat isteyen üçlü: / her zaman float döndürür, 10 / 2 bile 5.0'dır. // tam bölme (floor division) aşağı yuvarlanmış tam sonucu verir. % ise kalanı (modulo). Bu ikili birlikte çok iş görür: 10000 TL'yi 3 taksite bölersen taksit başına 3333 TL düşer, 1 TL artar.

OperatörAnlamıÖrnekSonuç
+ - *Toplama, çıkarma, çarpma7 * 321
/Bölme (hep float)7 / 23.5
//Tam bölme7 // 23
%Kalan7 % 21
**Üs2 ** 38
-xİşaret değiştirme-(5 - 8)3

İşlem önceliği matematikteki gibidir: önce parantez, sonra üs, sonra çarpma-bölme-kalan, en son toplama-çıkarma. Emin değilsen parantez kullan; parantez ücretsizdir ve okuyana yardım eder. Bir de kısayol atamalar var: bakiye += 500, bakiye = bakiye + 500 demektir. Aynı şekilde -=, *=, /=, //=, %= kullanılır.

Tam bölme ve kalanla gerçek problemler

Anadolu Market deposunda 250 ürün var, her kutuya 12 ürün sığıyor. Kaç tam kutu dolar, kaç ürün açıkta kalır, toplam kaç kutu gerekir?

urun = 250
kutu_kapasitesi = 12
tam_kutu = urun // kutu_kapasitesi
artan = urun % kutu_kapasitesi
print("Tam kutu:", tam_kutu)
print("Açıkta kalan:", artan)
gereken_kutu = tam_kutu + (1 if artan else 0)
print("Gereken kutu:", gereken_kutu)
print("Çift mi?", 250 % 2 == 0)

Son satır, kalan operatörünün klasik kullanımı: bir sayının 2'ye bölümünden kalan 0 ise sayı çifttir. Aynı mantıkla "her 100. sipariş hediye" kuralı siparis_no % 100 == 0 ile yazılır. divmod(250, 12) fonksiyonu ise tam bölüm ve kalanı tek seferde verir: (20, 10).

Kayan nokta hatası

Şimdi sürpriz. Şu kodu çalıştır:

print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
print(1499.90 * 3)
print(round(0.1 + 0.2, 2))
print(round(2.675, 2), round(2.5), round(3.5))

0.1 + 0.2, 0.30000000000000004 çıkar. Bu Python'ın hatası değil; bilgisayarlar sayıları ikilik tabanda saklar ve 0.1, ikilik tabanda sonsuz basamaklı bir sayıdır (ondalıkta 1/3'ün 0.333... olması gibi). Her dil aynı sonucu verir. Sonuçları yuvarlamak için round(x, basamak) kullanırsın. Ancak round'un kendisi de sürprizli: Python "bankacı yuvarlaması" yapar, tam .5 durumunda en yakın çift sayıya gider; bu yüzden round(2.5) 2, round(3.5) 4 verir. round(2.675, 2) ise 2.67 çıkar çünkü 2.675 bellekte aslında 2.67499... olarak durur.

Ondalıklı sayıları == ile karşılaştırmaa == b yerine abs(a - b) < 0.001 gibi bir tolerans kullan ya da sonucu önce yuvarla. Bu uygulamadaki testler de aynı yöntemi kullanır.
Para hesabında güvenli yolTutarları kuruş cinsinden tam sayı tut (1499.90 TL = 149990 kuruş) ve sadece gösterirken 100'e böl. Ya da decimal modülünü kullan. Analiz ve raporlamada float ile round yeterlidir.

Yuvarlama seçenekleri bir arada

Aynı sayıyı farklı amaçlarla yuvarlayabilirsin: rapor için iki ondalık, fatura için kuruşa, kutu sayısı için yukarı. Hangi fonksiyonun ne verdiğini yan yana gör:

import math
x = 7.456
print(round(x, 1), round(x, 2))   # en yakına
print(math.floor(x), math.ceil(x))  # aşağı, yukarı
print(int(x))                        # ondalığı at
print(round(-7.456), math.floor(-7.456), int(-7.456))

Son satır negatif sayılarda farkı gösterir: int sıfıra doğru keser (-7), floor aşağı iner (-8), round en yakını seçer (-7). Bakiye ve borç hesaplarında bu üçünü karıştırmak kuruş farklarına yol açar.

math modülü

Daha fazlası için math modülünü içe aktarırsın. En sık kullanacakların: yukarı yuvarlama ceil, aşağı yuvarlama floor, karekök sqrt, sabit pi.

import math
print(math.ceil(250 / 12))     # 21: gereken kutu, tek satırda
print(math.floor(7.9))         # 7
print(math.sqrt(144))          # 12.0
print(round(math.pi, 4))
print(abs(-350), max(3, 9, 4), min(3, 9, 4))
print(pow(2, 10), 10 ** 3)

abs, max, min, pow ve round hazır (built-in) fonksiyonlardır, içe aktarmaya gerek yoktur. Kutu problemine geri dönersen: math.ceil(250 / 12) tek satırda "gereken kutu" sayısını verir.

Ilgaz Bank faiz hesabı

Bir müşteri 50.000 TL'yi yıllık %30 faizle 3 yıl vadeli hesaba yatırıyor. Basit faizde her yıl ana para üzerinden faiz işler; bileşik faizde (compound interest) faiz de faiz kazanır. Formül: bileşik tutar = anapara × (1 + oran) üzeri yıl.

anapara = 50_000
oran = 0.30
yil = 3
basit = anapara * (1 + oran * yil)
bilesik = anapara * (1 + oran) ** yil
print("Basit faizle:", round(basit, 2))
print("Bileşik faizle:", round(bilesik, 2))
print("Fark:", round(bilesik - basit, 2))

50_000 yazımına dikkat: alt çizgi, büyük sayıları okunur yapar ve Python onu yok sayar. Üs operatörünün çarpmadan önce hesaplandığını da gör; parantez yalnızca 1 + oran için gerekti.

Oran yüzde değil kesirdir%30'u koda 30 değil 0.30 olarak yazarsın. Kullanıcıdan 30 alıyorsan 100'e bölmeyi unutma; en sık yapılan finans hatalarından biridir.
Derinleş

Operatörlerin tamamını (karşılaştırma, mantıksal, bit, öncelik) Operatörler dersinde ayrıca göreceksin. Bu bölüm sayıların kendisine odaklanıyor: yazım biçimleri, özel değerler, güvenilir yuvarlama ve finans hesaplarında gerçekten kullanılan araçlar.

Sayı yazım biçimleri (literal)

Python bir sayıyı birçok biçimde yazmana izin verir; hepsi aynı int ya da float türüne dönüşür:

YazımDeğerNerede görürsün?
1_250_0001250000Büyük tutarlar; alt çizgi yalnız okunurluk için
1.5e6, 2e-31500000.0, 0.002Bilimsel gösterim; sonuç hep float
0b101111İkilik taban: izin bayrakları
0o755493Sekizlik: Linux dosya izinleri
0xFF255Onaltılık: renk kodları, bellek adresleri
3 + 4jcomplexKarmaşık sayı: mühendislik hesapları
print(1_250_000 + 1, 1.5e6, 2e-3)
print(0b1011, 0o755, 0xFF)
print(bin(11), hex(255), oct(493))      # tersine: sayıdan metne
print(int("ff", 16), int("1011", 2))    # metinden, tabanı vererek
z = 3 + 4j
print(z.real, z.imag, abs(z))           # karmaşık sayının büyüklüğü 5.0

int(metin, taban) özellikle veri temizlemede işe yarar: renk kodları, donanım kimlikleri ya da bazı banka sistemlerinin onaltılık işlem numaraları bu yolla sayıya çevrilir. Karmaşık sayılar (complex) PCEP sınavında sorulur ama iş hayatında nadirdir; varlığını bilmen yeterli.

Özel float değerleri ve güvenli karşılaştırma

float türünde üç özel değer vardır: artı sonsuz, eksi sonsuz ve "sayı değil" (NaN, not a number). Veri setlerinde eksik değer çoğunlukla NaN olarak gelir; pandas derslerinde onunla sürekli karşılaşacaksın. NaN'ın en garip özelliği kendine bile eşit olmamasıdır.

import math
sonsuz = float("inf")
eksik = float("nan")
print(sonsuz > 10**100, -sonsuz < -10**100)
print(eksik == eksik, math.isnan(eksik))      # NaN kendine eşit değil!
print(math.isinf(sonsuz), math.isfinite(1.5))

print(0.1 + 0.2 == 0.3)
print(math.isclose(0.1 + 0.2, 0.3))           # göreli tolerans
print(math.isclose(1000.004, 1000.0, abs_tol=0.01))
elle = 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1
print(elle, math.fsum([0.1] * 10))   # fsum hata birikimini önler

math.isclose(a, b) kendi tolerans hesabını yapan güvenli karşılaştırmadır; varsayılan göreli tolerans çok küçüktür, tutar karşılaştırmasında abs_tol=0.005 (yarım kuruş) gibi mutlak bir tolerans vermek daha anlamlıdır. math.fsum ise çok sayıda float topladığında biriken küçük hataları telafi eder. (Python 3.12 ile hazır sum da float toplarken benzer bir telafi yapmaya başladı; ama elle + ile biriktirdiğin toplamlarda hata hâlâ birikir.)

Yuvarlama: round, Decimal ve muhasebe kuralı

round fonksiyonu bankacı yuvarlaması (yarımda çifte) yapar ve ikinci parametresi negatif de olabilir: round(1234.5, -2) yüzlere yuvarlar. Ama faturada Türkiye'deki alışılmış kural "yarım ve üstü yukarı"dır (ROUND_HALF_UP). Bunu float ile güvenilir yapamazsın; decimal modülünün quantize metodu tam bu iş içindir.

from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN

print(round(1234.567, -2), round(1250, -2), round(1350, -2))

fiyat = Decimal("2.675")
kurus = Decimal("0.01")
print(fiyat.quantize(kurus, rounding=ROUND_HALF_UP))    # 2.68: muhasebe
print(fiyat.quantize(kurus, rounding=ROUND_HALF_EVEN))  # 2.68: tam yarım, 8 çift
print(Decimal("2.665").quantize(kurus, rounding=ROUND_HALF_EVEN))  # 2.66
print(round(2.675, 2))                                    # float: 2.67!

tutar = Decimal("19.99") * 3
kdv = (tutar * Decimal("0.20")).quantize(kurus, rounding=ROUND_HALF_UP)
print(tutar, kdv, tutar + kdv)
Yöntem2.665 →2.675 →Ne zaman?
round(x, 2) (float)2.67*2.67*Analiz, grafik, yaklaşık rapor
ROUND_HALF_UP2.672.68Fatura, makbuz, muhasebe
ROUND_HALF_EVEN2.662.68İstatistik; birikimli yuvarlama hatasını azaltır
ROUND_DOWN2.662.67Kuruş küsuratını kesme (faiz tahakkuku politikasına göre)

* İkisi de 2.67 çıkar: 2.665 bellekte biraz üstünde, 2.675 biraz altında saklanır. float sonuçları sayının bellekteki ikilik karşılığına bağlıdır; tam yarım gibi görünen değerler aslında biraz altında ya da üstünde olabilir. Decimal ise yazdığın ondalığı tam olarak saklar. Decimal'ı hep metinden oluştur: Decimal(2.675) bozuk float'ı kopyalar.

Decimal ile float karıştırmaDecimal("1.5") + 0.1 TypeError verir; Python iki farklı kesinlikteki sayıyı sessizce birleştirmez. Hesaba giren her sabiti Decimal("0.20") gibi metinden oluştur; tam sayılarla (Decimal("19.99") * 3) karıştırmak serbesttir.

math ve statistics: sık kullanılan araçlar

FonksiyonNe yapar?İş örneği
math.prod(liste)ÇarpımArdışık büyüme oranlarını birleştirmek
math.gcd(a, b), math.lcm(a, b)EBOB, EKOKPaket boyutu, ortak sevkiyat günü
math.log10(x), math.log(x)LogaritmaBüyüklük mertebesi, sürekli faiz
math.exp(x)e üzeri xSürekli bileşik faiz
math.comb(n, k)KombinasyonKaç farklı kampanya paketi kurulabilir?
statistics.mean / medianOrtalama, ortancaSepet tutarı özeti (aykırı değere dayanıklı ortanca)
import math, statistics
print(math.lcm(6, 8), math.gcd(48, 36))     # 24. günde iki tır aynı gün; 12'li paket
print(round(math.prod([1.10, 1.05, 0.97]), 4))   # üç dönemin toplam büyüme çarpanı
print(math.comb(10, 3))                     # 10 üründen 3'lü paket sayısı
sepetler = [120, 135, 98, 110, 4200]        # bir kurumsal sipariş aykırı
print(statistics.mean(sepetler), statistics.median(sepetler))
eski, yeni = 84_000, 96_600
print(f"Değişim: %{(yeni - eski) / eski * 100:.1f}")

Son iki satır, iş hayatının en sık formülünü gösteriyor: yüzde değişim = (yeni − eski) / eski × 100. Eski değer sıfırsa formül tanımsızdır; raporda "yeni" ya da "—" yazmak gerekir. Ortalama ile ortanca arasındaki büyük fark ise verinde aykırı değer olduğunun işaretidir: tek bir kurumsal sipariş "ortalama sepeti" bir anda on katına çıkarabilir.

Gerçek işteFinans ekiplerinde kabul görmüş düzen şudur: tutarlar veritabanında ya kuruş cinsinden tam sayı ya da sabit ondalıklı (DECIMAL(18,2)) sütunlarda tutulur; Python tarafında Decimal ile hesaplanır; yuvarlama yalnızca belirlenmiş noktalarda (satır toplamı, KDV, genel toplam) ve yazılı bir kurala göre (ROUND_HALF_UP) yapılır. Taksitlendirmede bölünemeyen kuruş farkı genelde ilk ya da son taksite eklenir. Bu kuralları kodun en üstüne sabit olarak yazmak, denetimde "bu kuruş nereden geldi" sorusuna cevap verir.
Uzmanlaş

Decimal ve Fraction

from decimal import Decimal ile ondalık sayıları tam olarak temsil edersin: Decimal("0.1") + Decimal("0.2") tam 0.3 verir. Dikkat, Decimal'ı metinden oluşturmalısın; Decimal(0.1) zaten bozuk float'ı alır. Muhasebe, faturalama ve faiz hesapları Decimal ister. fractions.Fraction ise kesirleri tam tutar: 1/3 + 1/3, 2/3 çıkar. Analizde nadir, bilimsel hesapta değerlidir.

Tam sayı bölmede negatif sayılar

-7 // 2 sonucu -4'tür, -3 değil. Python tam bölmeyi her zaman aşağı (eksi sonsuza) yuvarlar ve % işareti bölenin işaretini alır: -7 % 2 1 verir. Bu tutarlılık takvim hesaplarında (haftanın günü, ay döngüsü) işe yarar, ama C ya da JavaScript'ten gelenleri şaşırtır.

Büyük sayılar ve performans

Python tam sayıları sınırsızdır: 2 ** 1000 sorunsuz hesaplanır. Bu rahatlığın bedeli hızdır; milyonlarca sayıyla işlem yapacaksan numpy'nin sabit boyutlu sayı tipleri çok daha hızlıdır. İleri seviyede bu geçişi yapacaksın.

Alıştırmalara geç (19)