Sayı doğru, anlamı yanlış
Mars Climate Orbiter, 1999 — kod sayıyı taşır, birimi taşımaz
Bir sayının yanında birimi yoksa ne olabileceğini görmek.
Ne oldu?
23 Eylül 1999. NASA'nın Mars Climate Orbiter sondası, dokuz aylık yolculuğun sonunda Mars'ın etrafında yörüngeye girmeye çalışıyor. Sonda insansız.
Yörüngeye girmesi gereken an geçiyor. Sondadan sinyal gelmiyor. Bir daha da hiç gelmedi.
Sonda Mars'a planlanandan çok daha alçaktan yaklaşmıştı. Muhtemelen atmosferde parçalandı.
Neden?
Sondayı iki farklı ekip yönetiyordu.
- Birinci ekip sondanın küçük motorlarının ne kadar ittiğini hesaplayan yazılımı yazmıştı. Sonucu libre-kuvvet cinsinden veriyordu — Amerika'da kullanılan bir birim.
- İkinci ekip o sayıyı alıp sondanın rotasını hesaplıyordu. Onların yazılımı sayının newton cinsinden geldiğini varsayıyordu — dünyanın geri kalanının kullandığı birim.
Bir libre-kuvvet yaklaşık 4,45 newton.
Yani motor her ateşlendiğinde gerçekte, rota hesabının sandığından dört buçuk kat fazla itiyordu. Tek bir ateşlemede fark küçüktü. Ama dokuz ay boyunca yapılan her küçük ateşlemede birikti.
Sayılar doğruydu. Kod hatasız çalışıyordu. Sadece iki ekip, aynı sayıya farklı anlam veriyordu.
Senin kartında
Sondanın motoru beş kez ateşleniyor. Birinci ekibin fonksiyonu itkiyi veriyor, ikinci ekip onu kullanıp hız değişimini planlıyor.
const float KUTLE_KG = 600.0; // ornek sonda kutlesi
// Birinci ekip yazdi: motorun verdigi itki
// (libre-kuvvet x saniye)
float motorItkisi() {
return 10.0;
}
void setup() {
Serial.begin(9600);
float biriken = 0;
for (int i = 1; i <= 5; i++) {
float itki = motorItkisi();
// Ikinci ekip: bu sayinin newton x saniye oldugunu varsayiyor
float planlanan = itki / KUTLE_KG;
// Fizik ne derse o: motor gercekte bu kadar itti
float gercek = (itki * 4.448) / KUTLE_KG;
biriken = biriken + (gercek - planlanan);
Serial.print("atesleme ");
Serial.print(i);
Serial.print(" plan: ");
Serial.print(planlanan, 4);
Serial.print(" gercek: ");
Serial.print(gercek, 4);
Serial.print(" biriken fark: ");
Serial.println(biriken, 4);
}
}
void loop() {
}
gercek satırına dikkat et. O satır kodun değil, evrenin satırı. Motor ne kadar itiyorsa sonda o kadar hızlanır — yazılımın ne sandığı umurunda değil.
Çalıştı mı?
Serial Monitor'de beş satır görmelisin:
atesleme 1 plan: 0.0167 gercek: 0.0741 biriken fark: 0.0575
atesleme 2 plan: 0.0167 gercek: 0.0741 biriken fark: 0.1149
...
atesleme 5 plan: 0.0167 gercek: 0.0741 biriken fark: 0.2873
Her ateşlemede plan ile gerçek arasında aynı küçük fark var. Ve fark birikiyor.
Beş ateşleme küçük görünüyor. Mars'a giden yolculuk dokuz ay sürdü.
Şimdi sen yaz
İki adımda düzelteceksin.
1. Dönüştür. Libre-kuvveti newtona çeviren bir fonksiyon yaz, sonra planlanan hesabında onu kullan.
float lbfToN(float lbf) {
// ŞİMDİ SEN YAZ:
// 1 libre-kuvvet = 4.448 newton
}
2. Birimi adına yaz. motorItkisi fonksiyonunun adını motorItkisi_lbfs yap. Değişkenleri de öyle: itki_lbfs, itki_Ns.
🔍 İpucu 1
Fonksiyon gelen sayıyı 4.448 ile çarpıp geri vermeli. return kullan — Kodun dili Görev 8.
Sonra planlanan satırında itki yerine lbfToN(itki) yaz.
✅ Cevap
float lbfToN(float lbf) {
return lbf * 4.448;
}
Ve planlanan satırı:
float planlanan = lbfToN(itki) / KUTLE_KG;
Şimdi biriken fark her satırda 0.0000 olmalı.
İkinci adım daha önemli. Dönüşümü bir kez düzeltmek kolay. Ama altı ay sonra biri yeni bir fonksiyon yazıp motorItkisi()'nin sonucunu yine newton sanarsa? Birimi adın içine yazarsan bu hata yapılamaz hale gelir:
float itki_lbfs = motorItkisi_lbfs();
float itki_Ns = lbfToN(itki_lbfs);
float planlanan = itki_Ns / KUTLE_KG;
itki_lbfs / KUTLE_KG yazmak artık göze batar. Yanlış kodu yazmak zorlaşır. Mühendislikte bu, hatayı düzeltmekten daha değerli: hatayı yapılamaz hale getirmek.
📄 Görevin tam kodu
const float KUTLE_KG = 600.0;
float motorItkisi_lbfs() {
return 10.0;
}
float lbfToN(float lbf) {
return lbf * 4.448;
}
void setup() {
Serial.begin(9600);
float biriken = 0;
for (int i = 1; i <= 5; i++) {
float itki_lbfs = motorItkisi_lbfs();
float itki_Ns = lbfToN(itki_lbfs);
float planlanan = itki_Ns / KUTLE_KG;
float gercek = (itki_lbfs * 4.448) / KUTLE_KG;
biriken = biriken + (gercek - planlanan);
Serial.print("atesleme ");
Serial.print(i);
Serial.print(" plan: ");
Serial.print(planlanan, 4);
Serial.print(" gercek: ");
Serial.print(gercek, 4);
Serial.print(" biriken fark: ");
Serial.println(biriken, 4);
}
}
void loop() {
}
Olmadıysa
| Ne görüyorsun | Ne yap |
|---|---|
Sayılar 0.02 gibi kısa |
Serial.print(planlanan, 4) — virgülden sonraki 4 basamak sayısı, unutma |
| Biriken fark düzeltmeden sonra da sıfır değil | planlanan satırında lbfToN(itki) kullanmayı unutmuşsun |
lbfToN was not declared |
Fonksiyonu setup'ın dışına, üstüne yaz |
Biriken fark -0.0000 |
Normal. Ondalık sayılarda çok küçük yuvarlama farkları olur, sıfır demek |
Kendini test et
Soru: Sayılar doğruydu, iki ekibin kodu da hatasız çalıştı. Hata tam olarak neredeydi?
Cevabı gör
İki ekibin arasında.
Kod bir sayıyı bir yerden öbür yere taşıdı. Ama sayının ne anlama geldiğini taşımadı. "10" yazan bir değişken, kendi kendine 10 libre mi 10 newton mu olduğunu söylemez.
Soruşturmada ortaya çıktı ki iki ekip arasındaki anlaşma belgesi newton kullanılmasını zaten istiyordu. Ama belge koda girmemişti. Yolculuk sırasında bazı mühendisler rotanın beklenenden farklı olduğunu fark etti — sebebi bulunamadı.
Bu yüzden iyi mühendisler birimi değişkenin adına yazar. Belge unutulabilir; değişkenin adı her satırda gözünün önündedir.
Bu hata nerede karşına çıkar
Akıllı Sera kitinin ilk görevinin bütün konusu bu: toprak sensörü sana "%40 nemli" demez, sadece bir sayı verir. O sayıya anlamı sensör vermez, sen verirsin. Kalibrasyon dediğimiz şey, bir sayıya doğru anlamı vermenin adı.
Takıldın, hata tablosu da yetmedi mi?
WhatsApp'tan sor — hangi görevdesin, ekranda ne yazıyor, devrenin fotoğrafı.