Menu

C'de Matematik Fonksiyonları: math.h, sqrt, pow ve -lm ile Bağlama

math.h turu - sqrt, pow, fabs, floor ve ceil, round, fmod, trigonometri ve logaritma aileleri, INFINITY ve NAN - ayrıca klasik undefined reference hatasına yol açan -lm bağlayıcı bayrağı.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

C'nin çekirdek dili size + - * / ve % verir, başka bir şey vermez - kuvvet operatörü yok, karekök yok, yuvarlama yok. Aritmetiğin ötesindeki her şey <math.h> içinde bildirilen standart matematik kütüphanesinde yaşar.

Bu fonksiyonların hepsi double hassasiyetinde çalışır: double argüman alır ve double döndürürler. İçselleştirilecek ilk şey budur, çünkü bir int geçirmek sessizce çalışır (dönüştürülür), oysa sonucu bir int'e atamak kesri sessizce atar.

Başlarken ve -lm Bayrağı

Kendi makinenizde bunu derlemek başarısız olabilir:

/usr/bin/ld: /tmp/ccXYZ.o: in function `main':
program.c:(.text+0x1a): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status

Bu, math.h ile ilgili tek en yaygın tökezlemedir ve kodunuzdaki bir hata değildir. Başlık bildirimleri sağladı, dolayısıyla derleyici memnundu; gerçekleştirimler, bağlayıcının Linux'ta varsayılan olarak dahil etmediği ayrı bir kütüphanede (libm) yaşar. -lm ekleyin:

gcc program.c -o program -lm

Bayrak kaynak dosyalardan sonra gelmelidir - bağlayıcılar girdilerini sırayla işler ve kendisine ihtiyaç duyan koddan önce listelenen bir kütüphane hiçbir şeyi çözmez. macOS'ta ve Windows'ta MinGW ile matematik yordamları zaten standart C kütüphanesinin parçasıdır, dolayısıyla -lm gereksizdir (macOS'ta zararsız olsa da).

Kuvvetler ve Kökler

Negatif bir sayının sqrt(x)'i çökmek yerine NaN döndürür; argüman negatif olabiliyorsa onu koruyun. hypot bilmeye değer, çünkü sqrt(x*x + y*y) ile aynı değeri hesaplar ama x ya da y çok büyük olduğunda taşmaz.

Küçük tam sayı kuvvetleri için düz çarpma hem daha hızlı hem kesindir - x * x, logaritmalardan geçen ve 9 beklediğiniz yerde 8.999999999999998 döndürebilen pow(x, 2.0)'ı yener.

Yuvarlama: floor, ceil, round, trunc

Dört fonksiyon, negatif sayılar için dört farklı cevap. Ezberlenmeye değen kısım o tablodur:

  • floor(x) - x'ten büyük olmayan en büyük tam sayı. Her zaman negatif sonsuzluğa doğru hareket eder: floor(-2.3) sonucu -3'tür.
  • ceil(x) - x'ten küçük olmayan en küçük tam sayı. Her zaman pozitif sonsuzluğa doğru hareket eder: ceil(-2.3) sonucu -2'dir.
  • round(x) - en yakın tam sayı, yarımlar sıfırdan uzağa: round(2.5) sonucu 3, round(-2.5) sonucu -3'tür.
  • trunc(x) - kesirli kısmı kes, sıfıra doğru hareket ederek: trunc(-2.7) sonucu -2'dir.

Dördü de bir double döndürür. Tam sayı istediğinizde int'e dönüştürmek sorunsuzdur, ama tek başına (int)x'in kırpma yaptığını not edin - dolayısıyla (int)(x + 0.5) eski "yuvarlama" deyimidir ve negatif sayılar için yanlıştır. round() kullanın.

fabs ve fmod

fabs, kayan nokta için mutlak değerdir. Onun yerine abs'e uzanmak klasik bir hatadır, çünkü abs bir int alır ve dönüşüm sessizce olur:

%, double üzerinde hiç çalışmaz - bir tam sayı operatörüdür ve derleyici onu reddeder. fmod(a, b) onun kayan nokta karşılığıdır ve a'nın işaretini korur.

fabs ayrıca iki double'ı karşılaştırmanın doğru yoludur, çünkü kayan noktada == bir tuzaktır:

0.1 ve 0.2 ikili olarak tam gösterilemez, dolayısıyla toplamları 0.3'ten kıl payı uzaktır. Bir toleransla karşılaştırın, asla == ile değil.

Trigonometri

Trigonometri fonksiyonları derece değil radyan ile çalışır - yanlış cevapların diğer güvenilir kaynağı.

Tam küme: sin, cos, tan, tersleri asin, acos, atan, iki argümanlı atan2(y, x) ve hiperbolik aile sinh, cosh, tanh. Açılar için atan(y / x) yerine atan2(y, x)'i tercih edin - x == 0 durumunu halleder ve bölgeyi doğru bulur.

math.h, çoğu sistemde M_PI'yi tanımlar, ama bu standart C değil bir POSIX uzantısıdır, dolayısıyla -std=c17 altında eksik olabilir. Yukarıdaki gibi kendi sabitinizi tanımlamak taşınabilirdir.

Logaritmalar ve Üsteller

Matematikten taşınan adlandırma tuzağına dikkat edin: log(), 10 tabanında değil doğal logaritmadır (e tabanı). 10 tabanı log10()'dur.

log(0.0) negatif sonsuzluk, log(-1.0) NaN döndürür - hiçbiri çökmez, bu da kötü bir argümanın bir şey nan yazdırana dek hesabınızın içinde sessizce yolculuk etmesi demektir.

INFINITY, NAN ve Onları Denetlemek

Kayan noktanın sayı olmayan değerleri vardır ve math.h onları adlandırır:

O son satır kritik olanıdır. if (x == NAN) yazamazsınız - her zaman yanlıştır. isnan(x) kullanın. (x != x özdeşliği yalnızca NaN için doğrudur; isnan çoğu zaman böyle gerçeklenir ve onsuz bir araç zinciriyle karşılaşırsanız kullanışlı bir yedektir.)

Sonsuzluklar taşmadan (exp(1000.0)) ve sıfırdan farklı bir double'ın sıfıra bölünmesinden gelir; bu, tam sayı bölmesinin aksine tanımlıdır ve çökmez.

float ve long double Türevleri

Her fonksiyonun üç biçimi vardır: double sürümü, f sonekli float sürümü ve l sonekli long double sürümü.

float       sqrtf(float x);
double      sqrt(double x);
long double sqrtl(long double x);

Ölçülmüş bir sebebiniz yoksa düz double sürümlerini kullanın - double, C'nin varsayılan olarak yükselttiği tiptir ve float türevlerini karıştırmak genellikle dönüşümlerde kazandırdığından fazlasına mal olur. Sonekin önemli olduğu tek yer, yalnızca float kullanan bir hesabın çift duyarlık desteği olmayan donanımda başarım açısından kritik olmasıdır.

Pratik Bir Örnek

Bunlardan birkaçını bir araya getirelim - iki nokta arasındaki uzaklık ve bir ikinci dereceden denklemin kökleri:

disc == 0.0 yerine fabs(disc) < 1e-12 olduğuna dikkat edin - daha önceki tolerans kuralının aynısı, ölçülmüş değerlerden hesaplanmış bir diskriminantın neredeyse hiçbir zaman tam olarak sıfıra düşmeyeceği yerde uygulanmış hâli.

<math.h>, daha büyük bir araç setindeki bir başlıktır; standart kütüphane sayfası gerisini haritalıyor ve rastgele sayılar, burada değil <stdlib.h>'de yaşayan rand'ı ele alıyor.

Sıkça Sorulan Sorular

C'de matematik fonksiyonlarını nasıl kullanırım?

Dosyanın tepesine #include <math.h> ekleyin ve onları çağırın: sqrt(16.0), pow(2.0, 10.0), fabs(-3.5). double alır ve double döndürürler. Linux'ta ayrıca matematik kütüphanesini -lm ile bağlamanız gerekir: gcc program.c -o program -lm.

Derlerken neden 'undefined reference to sqrt' alıyorum?

Başlık derleyiciye bildirimi verdi, ama gerçekleştirim, bağlayıcının Linux'ta otomatik olarak çekmediği ayrı bir kütüphanede yaşar. Komutun sonuna -lm ekleyin: gcc program.c -o program -lm. macOS'ta ve Windows'ta MinGW ile matematik kodu standart C kütüphanesinin parçasıdır, dolayısıyla bayrak gerekmez.

C'de abs ile fabs arasındaki fark nedir?

<stdlib.h>'deki abs() bir int alır ve bir int döndürür. <math.h>'deki fabs() bir double alır ve bir double döndürür. abs(-3.7) çağırmak argümanı önce int'e dönüştürür ve kesri sessizce atarak 3 verir - kayan noktalı değerler için fabs kullanın.

C'de NaN'ı nasıl kontrol ederim?

<math.h>'deki isnan(x) kullanın. x == NAN ile test edemezsiniz, çünkü NaN kendisi dahil her şeye eşitsiz karşılaştırılır - o tuhaflık aslında yedek testtir: x != x yalnızca NaN için doğrudur. Sonsuzluklar için isinf(x), sıradan bir sayı olup olmadığını kontrol etmek için isfinite(x) kullanın.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA