Python'da üç yerleşik sayı tipi vardır: sınırsız büyüklükte tamsayılar için int, ondalıklı sayılar için ikili kayan noktalı float ve karmaşık sayılar için complex. Bölme operatörü / her zaman float döndürür, // tam bölme yapar, % kalanı verir, ** üs alır. 0.1 + 0.2 işleminin 0.30000000000000004 çıkması bir hata değil, ikili kayan noktanın doğasıdır; para gibi kesin ondalık hesap gereken yerlerde standart kütüphanedeki decimal, kesirli hesaplarda ise fractions modülü kullanılır.

Bu yazı Built-in Types sayfasının sayısal tipler bölümüne, Tutorial'ın kayan nokta ekine ve decimal ile fractions belgelerine dayanıyor. Negatif sayılarda tam bölmenin neden aşağı yuvarladığını, round() fonksiyonunun "yarımı çifte yuvarlama" kuralını, metinden sayıya dönüşümdeki tuzakları ve KDV hesabı gibi gerçek bir örneği adım adım gösteriyor. Serinin tamamı Python öğrenme rehberi sayfasında.

Temel aritmetik ve bölme çeşitleri

Temel aritmetik ve bölme çeşitleri: int(x), math.trunc(x), math.floor(x), math.ceil(x)

Toplama, çıkarma ve çarpma beklediğiniz gibi çalışır. Bölmede ise iki ayrı operatör vardır. / klasik bölmedir ve iki tamsayıyı bölseniz bile sonuç float olur. // tam bölmedir (floor division): sonucu eksi sonsuza doğru yuvarlar. % kalanı, divmod() ise ikisini birden bir çift olarak döndürür:

python
print(17 / 3)
print(17 // 3)
print(17 % 3)
print(divmod(17, 3))
print(8 / 4)
print(7.5 // 2)
# çıktı: 5.666666666666667
# çıktı: 5
# çıktı: 2
# çıktı: (5, 2)
# çıktı: 2.0
# çıktı: 3.0

8 / 4 işleminin 2 değil 2.0 vermesi yeni başlayanları şaşırtır; bu, / operatörünün tanımı gereğidir. // işleminde ise sonucun tipi işlenenlere bağlıdır: iki tamsayıda int, işlenenlerden biri float ise float olur. Bu yüzden 7.5 // 2 sonucu 3.0'dır. Tam bölme ile kalan her zaman x == (x // y) * y + (x % y) eşitliğini sağlar.

Negatif sayılarda tam bölme ve kalan

Tam bölme sıfıra doğru değil, eksi sonsuza doğru yuvarlar; kalanın işareti de her zaman bölenin işaretiyle aynıdır. C ya da Java'dan gelen programcılar için bu farklı bir davranıştır. int() ise bir ondalıklı sayıyı sıfıra doğru keser; aşağı ya da yukarı yuvarlama için math.floor() ve math.ceil() kullanılır:

python
import math

print(-17 // 3)
print(-17 % 3)
print(17 % -3)
print(int(-5.7))
print(math.floor(-5.7), math.ceil(-5.2), math.trunc(-5.7))
# çıktı: -6
# çıktı: 1
# çıktı: -1
# çıktı: -5
# çıktı: -6 -5 -5
İşlemYuvarlama yönü-5.7 için sonuç
int(x)Sıfıra doğru keser-5
math.trunc(x)Sıfıra doğru keser-5
math.floor(x)Eksi sonsuza doğru-6
math.ceil(x)Artı sonsuza doğru-5
round(x)En yakın tamsayı, eşitlikte çift olana-6
x // 1Eksi sonsuza doğru, sonuç float-6.0

Üs alma ve sınırsız tamsayılar

** operatörü üs alır. Tamsayılar sınırsız duyarlıklıdır, yani 2 ** 100 taşma olmadan tam olarak hesaplanır. Üs negatifse sonuç float olur. Dikkat edilmesi gereken bir öncelik kuralı var: ** solundaki tekli eksiden daha sıkı bağlanır, bu yüzden -2 ** 2 ifadesi -(2 ** 2) olarak hesaplanır. Üç argümanlı pow(taban, us, mod) ise modüler üs almayı verimli biçimde yapar:

python
print(2 ** 100)
print(10 ** -2)
print(-2 ** 2)
print((-2) ** 2)
print(pow(3, 4, 5))
print(0 ** 0)
# çıktı: 1267650600228229401496703205376
# çıktı: 0.01
# çıktı: -4
# çıktı: 4
# çıktı: 1
# çıktı: 1

Python, programlama dillerinde yaygın olduğu gibi 0 ** 0 değerini 1 kabul eder. Tamsayılar sınırsız olsa da float sınırlıdır: çok büyük bir sonuç ya inf olur ya da hata verir. Aşağıda çarpma sonsuza taşarken 2.0 ** 1024 işlemi OverflowError verdi:

python
print(2 ** 64)
print(len(str(2 ** 1000)))
print(1e308 * 10)
print(2.0 ** 1024)
# çıktı: 18446744073709551616
# çıktı: 302
# çıktı: inf
# OverflowError: (34, 'Result too large')

0.1 + 0.2 neden 0.3 değil?

Bilgisayar donanımı kayan noktalı sayıları ikili (taban 2) kesirler olarak saklar. 1/3 sayısını onluk sistemde sonlu basamakla yazamadığınız gibi, 0.1 de ikili sistemde sonlu basamakla yazılamaz; sonsuz tekrar eden bir kesirdir. Saklanan değer 0.1'e çok yakın ama tam eşit olmayan bir yaklaşımdır. Python ekrana bu yaklaşımın en kısa okunabilir hâlini yazdığı için 0.1 görürsünüz, ama toplama gibi işlemler küçük hataları görünür kılar:

python
import math

print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
print(math.isclose(0.1 + 0.2, 0.3))
print(0.1 + 0.1 + 0.1 - 0.3)
print(sum([0.1] * 10))
print(format(0.1 + 0.2, ".2f"))
# çıktı: 0.30000000000000004
# çıktı: False
# çıktı: True
# çıktı: 5.551115123125783e-17
# çıktı: 1.0
# çıktı: 0.30

Tutorial bunun Python'a özgü bir hata olmadığını, donanımın kayan nokta aritmetiğini kullanan bütün dillerde aynı davranışın görüldüğünü vurgular. Belgelere göre çoğu makinede her kayan nokta işleminin hatası 2**53'te bir parça mertebesindedir; günlük işlerin çoğu için bu yeterlidir. Pratik kurallar şunlardır: kayan noktalı sayıları == ile karşılaştırmayın, math.isclose() kullanın; sonucu gösterirken biçimlendirme ile yuvarlayın; birçok değeri toplarken sum() kullanın, çünkü belgelerin belirttiği gibi ara adımlarda genişletilmiş duyarlılık kullanarak hata birikimini azaltır. Yukarıdaki örnekte on tane 0.1'in toplamı bu yüzden tam 1.0 çıktı.

Bir float'un gerçekte saklanan değerini görmek isterseniz Decimal(0.1) ya da float.as_integer_ratio() kullanabilirsiniz; ikisi de yaklaşımı kayıpsız gösterir.

round() ve yarımı çifte yuvarlama

round(sayi, basamak) fonksiyonu sayıyı belirtilen ondalık basamağa yuvarlar. İki aday eşit uzaklıktaysa çift olana yuvarlar; bu yüzden hem round(0.5) hem round(2.5) sonucu çifttir. Basamak verilmezse sonuç int, verilirse sayıyla aynı tipte olur. Negatif basamak onlar, yüzler basamağına yuvarlar:

python
print(round(0.5), round(1.5), round(2.5))
print(round(2.675, 2))
print(round(1234.5678, -2))
print(round(3.7), type(round(3.7)))
print(round(3.7, 0), type(round(3.7, 0)))
# çıktı: 0 2 2
# çıktı: 2.67
# çıktı: 1200.0
# çıktı: 4 <class 'int'>
# çıktı: 4.0 <class 'float'>

round(2.675, 2) sonucunun 2.68 yerine 2.67 çıkması belgelerde özellikle not edilmiştir: 2.675 değeri ikili sistemde tam saklanamaz ve saklanan yaklaşım 2.67'ye biraz daha yakındır. Okulda öğrendiğiniz "yarım yukarı" yuvarlamayı kesin biçimde uygulamanız gerekiyorsa decimal modülünü kullanın.

decimal: kesin ondalık hesap

decimal modülü, belgelerinin ifadesiyle "insanlar düşünülerek tasarlanmış" bir ondalık kayan nokta modeli sunar. Ondalık sayılar tam olarak temsil edilir, bu yüzden 0.1 + 0.2 tam olarak 0.3 verir. Önemli basamak kavramını da korur: 1.30 + 1.20 sonucu 2.50 olur, sondaki sıfır anlamlılığı göstermek için kalır. Bu davranış muhasebe ve para hesapları için uygundur. Varsayılan duyarlılık 28 basamaktır ve değiştirilebilir:

python
from decimal import Decimal, ROUND_HALF_UP, getcontext

print(Decimal("0.1") + Decimal("0.2"))
print(Decimal(0.1))
fiyat = Decimal("19.99")
kdv = fiyat * Decimal("0.20")
print(kdv)
print(kdv.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))
print(Decimal("2.675").quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))
print(Decimal("1.30") + Decimal("1.20"))
print(getcontext().prec)
# çıktı: 0.3
# çıktı: 0.1000000000000000055511151231257827021181583404541015625
# çıktı: 3.9980
# çıktı: 4.00
# çıktı: 2.68
# çıktı: 2.50
# çıktı: 28

Bu örnekte en önemli ayrıntı ikinci satırdır: Decimal(0.1) yazdığınızda önce 0.1 bir float olarak oluşur ve Decimal o yaklaşık değeri birebir dönüştürür. Kesin değer istiyorsanız Decimal'ı her zaman metinden oluşturun: Decimal("0.1"). quantize() metodu sonucu sabit bir basamak sayısına yuvarlar; ROUND_HALF_UP yarımı yukarı yuvarlar ve 2.675 beklendiği gibi 2.68 olur. Modülün varsayılan yuvarlama kuralı ise ROUND_HALF_EVEN'dir.

fractions: kesirli sayılar

fractions: kesirli sayılar: Tam, sınırsız, float, Decimal, Fraction

fractions.Fraction rasyonel sayıları pay ve payda olarak tam saklar; 1/3 gibi değerler hiçbir kayıp olmadan hesaplanır. Kesirler her zaman sadeleştirilir ve işaret paya taşınır. Bir float'tan oluşturulan kesir, yine o float'un ikili yaklaşımını tam olarak yansıtır; limit_denominator() metodu en yakın sade kesri bulur:

python
from fractions import Fraction

print(Fraction(1, 3) + Fraction(1, 6))
print(Fraction("0.25"))
print(Fraction(16, -10))
print(Fraction(1.1))
print(Fraction(1.1).limit_denominator(100))
print(Fraction(1, 3) * 3 == 1)
# çıktı: 1/2
# çıktı: 1/4
# çıktı: -8/5
# çıktı: 2476979795053773/2251799813685248
# çıktı: 11/10
# çıktı: True
TipKesinlikHızTipik kullanım
intTam, sınırsızHızlıSayaçlar, kimlikler, büyük tamsayılar
floatYaklaşık, 53 bitlik ikili kesirDonanım hızındaBilimsel ve mühendislik hesapları, ölçümler
DecimalOndalıkta tam, ayarlanabilir duyarlılıkfloat'tan yavaşPara, vergi, muhasebe
FractionRasyonelde tamPayda büyüdükçe yavaşlarKesirli oranlar, kesin rasyonel hesap
complexİki floatHızlıMühendislik ve sinyal hesapları

Metinden sayıya ve sayı yazımları

int() ve float() metni sayıya dönüştürür. int() baştaki ve sondaki boşlukları, işareti ve basamaklar arasındaki tekli alt çizgileri kabul eder; ikinci argümanla 2 ile 36 arasındaki tabanlarda okuma yapabilir. Taban 0 verilirse önek (0b, 0o, 0x) tabanı belirler. Kod içinde de 1_000_000 gibi alt çizgiyle gruplama yapabilir, ikili, sekizli ve onaltılı sabitler yazabilirsiniz:

python
print(int("42"), int("  -12_345 \n"))
print(int("ff", 16), int("0b1011", 0))
print(float("3.5"), float("inf"), float("-inf"))
print(1_000_000)
print(0x1F, 0o17, 0b101)
print(bin(10), hex(255), oct(8))
# çıktı: 42 -12345
# çıktı: 255 11
# çıktı: 3.5 inf -inf
# çıktı: 1000000
# çıktı: 31 15 5
# çıktı: 0b1010 0xff 0o10

Türkçe ondalık virgül tuzağı

Türkçede ondalık ayırıcı virgüldür ama Python sayı yazımında yalnızca noktayı kabul eder. Kullanıcıdan ya da bir Excel çıktısından gelen "3,5" metni doğrudan dönüştürülemez. Benzer şekilde int() ondalıklı bir metni kabul etmez:

python
print(float("3,5"))
# ValueError: could not convert string to float: '3,5'
python
print(int("3.5"))
# ValueError: invalid literal for int() with base 10: '3.5'

Basit bir çözüm float(metin.replace(",", ".")) biçimidir; binlik ayırıcı olarak nokta kullanan "1.234,56" gibi metinlerde önce noktaları kaldırmanız gerekir. Ondalıklı bir metni tamsayıya çevirmek için önce float(), sonra int() uygulayın ve kesme davranışını göz önünde bulundurun. Sayıları yine Türkçe biçimde göstermek f-string yazısının konusudur.

Bir uç durum daha var: Python 3.11'den beri çok uzun metinlerin tamsayıya dönüştürülmesi, hizmet engelleme saldırılarına karşı varsayılan olarak 4300 basamakla sınırlıdır. Sınır aşıldığında şu hata alınır:

python
buyuk = int("9" * 5000)
# ValueError: Exceeds the limit (4300 digits) for integer string conversion: value has 5000 digits; use sys.set_int_max_str_digits() to increase the limit

Karışık tipler, sıfıra bölme ve NaN

Farklı sayı tipleri bir işlemde buluştuğunda "dar" olan tip "geniş" olana genişletilir: int ile float toplandığında sonuç float olur. Karşılaştırmalar ise sayıların kesin değerleri üzerinden yapılır, bu yüzden 1 == 1.0 doğrudur. Sıfıra bölme ZeroDivisionError verir. Özel değer nan (sayı değil) kendisine bile eşit değildir; kontrolü math.isnan() ile yapılır:

python
import math

print(3 + 2.0, type(3 + 2.0).__name__)
print(True + 1)
print(1 == 1.0, 0.5 == 1 / 2)
print((255).bit_length())
print((3.0).is_integer(), (3.5).is_integer())
x = float("nan")
print(x == x, math.isnan(x))
print(10 / 0)
# çıktı: 5.0 float
# çıktı: 2
# çıktı: True True
# çıktı: 8
# çıktı: True False
# çıktı: False True
# ZeroDivisionError: division by zero

Karmaşık sayılar j sonekiyle yazılır; gerçel ve sanal kısımlar .real ve .imag nitelikleriyle alınır, abs() büyüklüğü verir. Karmaşık sayılarda tam bölme, mod ve büyüklük karşılaştırması tanımlı değildir:

python
z = 3 + 4j
print(z.real, z.imag, abs(z))
print(type(z).__name__)
print(z * 1j)
# çıktı: 3.0 4.0 5.0
# çıktı: complex
# çıktı: (-4+3j)

Sürüm notları

Python 3.14 ile int() artık __trunc__() metoduna başvurmuyor ve float.from_number() sınıf metodu eklendi. Python 3.15'te zaman damgası ya da zaman aşımı alan fonksiyonlar Decimal ve Fraction gibi her gerçel sayıyı kabul ediyor; belgeler bunun duyarlılığı artırmadığını da belirtiyor. Ayrıca bir sayı sabitinin hemen ardından boşluksuz and, or, if, in gibi bir anahtar kelime yazmak (1or x gibi) artık SyntaxWarning veriyor ve ileride söz dizimi hatasına dönüşecek. Sürümün tamamı Python 3.15 yenilikleri yazısında.

Sık yapılan hatalar

Sık yapılan hatalar: Para hesabında float kullanmak, Kayan noktayı == ile karşılaştırmak, round() fonksiyonundan "yarım yukarı" beklemek, -2 ** 2 ifadesini 4 sanmak
  • Para hesabında float kullanmak: Kuruş farkları birikir. Decimal'ı metinden oluşturun ve quantize() ile yuvarlayın.
  • Kayan noktayı == ile karşılaştırmak: math.isclose() kullanın.
  • round() fonksiyonundan "yarım yukarı" beklemek: round(2.5) sonucu 2'dir; kural yarımı çifte yuvarlamaktır.
  • -2 ** 2 ifadesini 4 sanmak: Üs alma önce yapılır; (-2) ** 2 yazın.
  • input() sonucuyla doğrudan hesap yapmak: input() metin döndürür; int() ya da float() ile dönüştürün ve geçersiz girdiyi try/except ile yakalayın.

Sık Sorulan Sorular

Python'da tamsayı taşması olur mu?

int tipi sınırsız duyarlıklıdır, yalnızca kullanılabilir bellekle sınırlıdır. Taşma ancak float ile hesap yaparken görülür; sonuç ya inf olur ya da OverflowError oluşur.

Bir sayının tam sayı olup olmadığını nasıl anlarım?

Değer float ise x.is_integer() kullanabilirsiniz; Python 3.12'den beri bu metot int üzerinde de vardır. Tip sınamak istiyorsanız isinstance(x, int) yazın ve True değerinin de int sayıldığını unutmayın.

Ondalık basamak sayısını nasıl sınırlarım?

Yalnızca gösterim için f"{x:.2f}" biçimlendirmesi yeterlidir; değer değişmez. Değerin kendisini yuvarlamak için round(), kesin ondalık kurallar için Decimal.quantize() kullanın.

math modülünde başka neler var?

math modülü karekök, logaritma, trigonometri, isclose, isqrt, gcd gibi fonksiyonlar sunar; karmaşık sayılar için de cmath modülü vardır. Etkileşimli kabukta dir(math) yazarak listeye göz atabilirsiniz (bkz. REPL).

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Python öğrenme rehberi · Değişkenler ve veri tipleri · f-string biçimlendirme · Koşullar · json modülü