Debi Hesabımda Zaman Sıfır Oldu, Sayfa NaN Gösterdi
Debiyi 'hacim / zaman' olarak hesaplıyordum; makine durduğunda zaman sıfıra yaklaştı, sayfa 'NaN' gösterdi. Sıfıra bölmenin neden 'sonsuz' değil 'NaN' (sayı değil) ürettiğini, NaN'ın her karşılaştırmada 'yanlış' sayılıp alarmımı susturduğunu ve 'zaman < 0.1 ise bölme yapma' kuralını kendi vaka üzerinden anlatıyorum.

Pazartesi, öğle. Debi gösterge ekranı “NaN” yazıyordu. Normalde litre/dakika gösteriyordu. Operatör “abi sayfa bozuldu mu” dedi. Bozulmamıştı; sayfa, benim yazdığım bir satırın, bir sabah, “zaman” değişkeninin sıfıra yaklaştığı anda ürettiği bir değeri gösteriyordu. Ben de o gün, “sıfıra bölme”nin PLC’de ne yaptığını, ekranda “NaN” olarak otururken öğrendim.
Hacim Bölü Zaman, Zaman Sıfıra Gittiğinde
Debiyi şöyle hesaplıyordum: bir zaman diliminde geçen hacmi, o zaman dilimine bölüyordum.
#debi := #gecen_hacim / #zaman;
#gecen_hacim, bir sayaçtan alınıyordu, her scan’da artıyordu. #zaman (zaman), turlar arasındaki gerçek süreydi. Makine çalışırken, zaman küçük ama sıfır değildi, debi makul bir sayıydı. Ama makine durduğunda, sayaç duruyordu, zaman da neredeyse sıfıra iniyordu. Bir scan’da #zaman tam 0.0’a düştü. bir sayı / 0.0.
İşte tuhaf olan yer. Okulda “sıfıra bölme tanımsızdır” derlerdi, “sonsuz” derdik. Ama REAL’de, 0.0 / 0.0 sonsuz değil, NaN üretir — “Not a Number,” sayı değil. #gecen_hacim de o anda sıfırdı (sayaç durmuştu), yani 0.0 / 0.0 → NaN. Sayfa, NaN’ı gördü, “NaN” yazdı.
NaN, Her Karşılaştırmada “Yanlış” Söyler
NaN’ın en sinsi özelliği bu: NaN’ı herhangi bir şeyle karşılaştırırsan, sonuç hep yanlış (false) olur. NaN > 10? Yanlış. NaN < 10? Yanlış. NaN = 0? Yanlış. Hatta NaN <> 0 bile yanlış. NaN, “ben sayı değilim” der, sen de “o halde hangi aralıkta” diye sorduğunda “hiçbirinde” der.
Benim programda bir “debi yüksek” alarmı vardı:
if (#debi > 50.0) alarm_debi_yuksek := true;
Debi NaN olduğunda, NaN > 50.0 yanlış. Alarm, yanlışlıkla söndü. Yani tam da debinin “bilinemez” olduğu, tehlikenin olduğu anda, alarmım sessizdi. O “sessizlik,” sahada en pahalı türdür: sorun var, alarm yok, operatör rahat.
Çözüm: Bölmeden Önce Paydaya Bak
Kural şu: bir bölme yapıyorsan, paydaya (böldüğün değer) önce bak. Sıfıra yakınsa, bölme yapma; ya son iyi değeri tut, ya da “ölçüm yok” işareti ver.
if (#zaman > 0.1) then
#debi := #gecen_hacim / #zaman;
else
#debi := #debi; // son iyi değeri tut, bölme yapma
#debi_olcume_yok := true;
end if;
#zaman > 0.1 eşiği, “zaman bu kadar küçükse, bölme gürültü üretir” demektir. O eşiğin altında, bir önceki debiyi korur, “ölçüm yok” bayrağını yakar. Sayfa artık NaN yazmaz; ya son değeri, ya da “ölçüm yok”u gösterir.
Bir de ek: karşılaştırmada NaN’ı önceden ele et. if (not (#debi = #debi)) — bu, “debi kendine eşit mi?” sorusu, NaN için hep yanlış, yani sadece NaN’da not doğru olur. Bu, “bu değer NaN mı?“nın tek güvenli testidir. Onu bir “debi geçersiz” alarmına bağla; öyleyse NaN, sessizce alarmı söndürmez, tersine alarmı yakar.
O pazartesi, o “NaN,” bir if (#zaman > 0.1) ile gitti. Operatör “abi sayfa artık bozulmuyor” dedi. Ben de o an anladım ki, sıfıra bölme bana “sonsuz” değil “sayı değil” vermişti; ve “sayı değil,” her soruma “bilmiyorum” diye cevap veriyordu. Ben de o “bilmiyorum”u, alarm susturmak için değil, alarm yakmak için kullanmaya başladım.
Bir sonraki yazıda, “kazanç 0.75 ile çarptım, INT’te hep 0 çıktı” diye anlatıyorum. 4.7 × 0.75’in neden 0’a yuvarlandığını, çarpmanın INT’te yapıldığını, ve REAL’e çevirirken (cast) nerede kesildiğini.