Tüm yazılar
Programlama İpucu

Kazanç 0.75 ile Çarptım, INT'te Hep 0 Çıktı

Analog değeri 0.75 kazançla çarptım, sonuç hep 0 geldi. Çarpmanın INT'te yapıldığını, 4.7'nin önce 4'e yuvarlandığını, ve REAL'e çevirirken (cast) nerede kesildiğini; 'çarpma INT'te kalırsa ondalık kaybolur' kuralını kendi vaka üzerinden anlatıyorum.

Kazanç 0.75 ile Çarptım, INT'te Hep 0 Çıktı

Cuma, sabah. Bir analog giriş, 0-10 V veriyordu, ben onu 0-100 ölçeğine çekmek için bir kazanç çarpması yapıyordum. Basit bir işti: değeri 0.75 ile çarp, tamam. Ama çıktı hep 0’dı. Değer 4.7 gelince, 4.7 × 0.75 = 3.5 olmalıydı; ekranda 0 yazıyordu. Değer 9.9 gelince, 7.4 olmalıydı; yine 0. Hep 0. Ben de “kazanç bozuk mu?” diye iki saat uğraştım. Bozuk değildi; çarpma, ben düşünmeden önce, INT’te yapılmıştı.

Çarpma INT’te Yapıldı, Ondalık Erken Koptu

Sorun, değişkenin tipindeydi. #analog_deger bir INTti. Kazancı da 0.75 yazmıştım, ama çarpma satırı şöyleydi:

#sonuc := #analog_deger * 0.75;

#analog_deger INT olduğu için, 4.7 aslında 4 idi — ondalık, okuma anında INT’e girerken kesilmişti. Sonra 4 * 0.75 → 3.0. Ama #sonuc da INT’ti, 3.0 INT’e girince 3 değil… bekleyin, 3 gelmeliydi, 0 değil. Gerçekten 0 geldi, çünkü #analog_deger küçük değerlerde 0.75’ten küçük sayı taşıyordu: değer 0.3 gelince, INT’e girer girmez 0 oldu, 0 * 0.75 = 0. Değer 4.7 gelince INT’e 4 girdi, 4 × 0.75 = 3, ama ben o gün 0.3-0.6 arası küçük değerlerle uğraşıyordum; hepsi INT’te 0’a inmişti.

Kök mesele şu: INT, ondalık tutmaz. Bir 4.7yi INT’e koyarsan, 4 kalır; 0.3ü INT’e koyarsan, 0 kalır. Kazanç çarpması, ondalığı sonra eklemeye çalışıyorsa, çok geç — ondalık, INT’e girmeden önce zaten gitmiştir.

REAL’e Çevir (Cast), Ama Doğru Sırada

Çözüm: değeri okuduğun anda REAL’e çevir, çarpmayı REAL’de yap, sonucu REAL’de tut.

#deger_real  : REAL;
#sonuc_real  : REAL;

#deger_real := INT_TO_REAL(#analog_deger);   // INT -> REAL, ondalık korunur
#sonuc_real := #deger_real * 0.75;           // REAL çarpma

INT_TO_REAL, bir INT’i REAL’e çevirir. Ama dikkat: INT_TO_REAL(4) = 4.0’tır, 4.7 değil. Yani INT’e girmiş olan bir değerden ondalık kurtaramazsın. Onun için, analog girişi baştan REAL olarak oku. Giriş modülü, 0-27648 ham değerini verir; onu REAL’e çevirip ölçekle:

#ham_real  := INT_TO_REAL(#ham_deger);
#deger     := (#ham_real - 0.0) / (27648.0 - 0.0) * 10.0;   // 0-10 V
#sonuc     := #deger * 0.75;                                  // 0-7.5

Burada her şey REAL. Ondalık, hiçbir yerde INT’e düşmüyor. 0.3 × 0.75 = 0.225, ekranda 0.23 görürsün, 0 değil.

Kural: Ondalık Hesap, Ondalık Tip’te Başlar

Artık kuralım şu: bir hesapta ondalık varsa, o hesabın her adımı REAL’de (ya da LREAL’de) olmalı. INT, yalnızca “tam sayı” dünyasıdır; adım sayacı, sayaç, adres. Ondalık, REAL dünyasıdır; kazanç, ölçek, debi, sıcaklık. İkisini aynı satırda karıştırırsan, INT kazanır — çünkü INT, ondalığı sessizce keser, hata vermez.

Bir de ek: INT_TO_REAL gibi bir çeviriyi gördüğünde, “bu INT’e ne zaman girdi?” diye sor. Eğer INT’e girmeden önce ondalık varsa, o ondalık gitmiştir. Çeviri, gitmemiş olanı kurtarır; gitmiş olanı değil.

O cuma, o “hep 0,” bir REAL ile gitti. Operatör “abi küçük değerler artık görünüyor” dedi. Ben de o an anladım ki, INT bana ondalığı vermemişti; vermemişti çünkü INT’in ondalık diye bir odası yoktu. Kazancı REAL’e taşıdığım an, o oda belirdi.

Bir sonraki yazıda, “zamanlayıcıya start verdim, reset’i unuttum, bir daha hiç kapanmadı” diye anlatıyorum. Bir zamanlayıcının neden “bir kez tetiklenip donduğunu,” ve reset girişini unutmanın neden zamanlayıcıyı sonsuza kadar ON bıraktığını.