Float veri tipine alternatif

Başlatan exmachine, 02 Ağustos 2018, 10:14:02

exmachine

Merhaba arkadaşlar.

8 bitlik MCU'larda float veri tipi ile işlem yaptığımızda çok fazla sistem kaynağı kullanıyor.
Bu veri tipini kullanmadan ondalık işlemleri yapabileceğimiz başka bir teknik var mı?

foseydon

#1
anahtar kelime "fixed point math"

edit: yine de istediğin hızı elde edemeyebilirsin. imkan varsa integral tiplerle çalışmak. sorun ve hesap tam olarak nedir, onu da paylaşabilirseniz belki daha hızlı olacak bir yöntem bulabiliriz.

mistek

Ondalık işlem yaparken hassasiyeti düşürerek float kullanmadan sorunu çözebilirsiniz.

Örneğin. 1000/30 sonucunu 33.33 olarak görmek sizin için yeterliyse payı 100 ile çarpın bunu int16 bir değişkene kaydedin.

1000 * 100 / 30 = 3333 sonucu elde edilir. İşlemlerinizi artık 100 kat fazla üzerinden devam ettirip sonunda,

Sayı basamaklarını almak için 10-100... gibi adımlara bölün veya mod alma işlemi yapın. Sonuç olarak Elinizde 33.33 değeri olmuş olur. Ekranda gösterirken sayıyı bölmüş olursunuz.
boş işlerin adamı ---- OHM Kanunu: I = V/R ---- Güç Formülü: P = V*I = I^2*R = V^2/R

exmachine

@mistek önerin için sağol. Virgülden sonra iki basamak hassasiyet benim için yeterli. Bu yöntemi uygulayacağım.

exmachine

@foseydon amaç sadece analog kanaldan okunan değeri gerilim bilgisine çevirmek. Kullandığım işlemcide(16f1937)
FPU, DSP ya da 17X17 donanımsal çarpma modülü yok.

Hız şimdilik çok önemli değil. Float veri tipini printf ile formatlı bir şekilde gönderdiğimizde çok fazla program hafızası yiyordu. Şimdilik iki basamak hassasiyet yeterli olduğu için Fixed point ile de uğraşmasam daha iyi heralde.

Cevap için teşekkürler.

foseydon

ben başka birşeyler önereyim. Sen bu float sayıyı ekrana basmak istiyorsun. Senin arkada yaptığın işlemin önemi yok yani, önemli olan kullanıcının ne gördüğü.

adc'nin belirli bir çözünürlüğü var, her biri belirli bir değere denk geliyor. bunu bir tablo yapıp buna göre ekrana veri basabilirsin. en iptidai çözüm.

adc'de okuduğun değeri bir şekilde dönüştürüyorsun. bu hesabı ondalıksız yapıp, noktayı ekrana basarken koyabilirsin. Misal, adc değeri olarak okuduğun 100 değeri ekranda 123.33 e denk geliyor. yani sen okuduğun değeri 1.2333 ile çarpıyorsun gerçek değeri bulmak için. Bunun yerine 12333 ile çarp, noktayı ekrana basarken koy. bu sayede hiç float işlem yapmamış olursun.

ha sen bulduğun float değeri işlem yapmak ve çıkan sonucu kontrol için kullanıyorsan, bu ayrı hikaye.

kimlenbu

8 bit mcu'da hangi marka/model kullandığına göre 16bitlik bir register olmayabilir veya sınırlı sayıda olabilir. misal 8051'de DPTR var, alt ve üst byte'lara da DPH ve DPL registerları ile ulaşılabiliyor.

kodu c ile yazarsan float kadar olmasa da sana oldukça fazla cyle'a malolacak. Bunun yerine inline assembly için derleyicilerin direktifleri oluyor, bölme işleminin istediğin hassasiyet için optimize bir şekilde asm kullanarak yaz. bu sayede kac cycle harcayacağını da net olarak bilebilirsin.

Misal 8051 için algoritması şurada var, kullandığın işlemciye göre arama yapıp mantığını anladıktan sonra kendin yazarsan oldukça fazla zaman kazanırsın.

http://www.edsim51.com/8051Notes/8051/16bitAddition.html

exmachine

En son söyle bir şey yaptım.

struct fake_float
{
    uint8_t tam,ondalik;    
};

struct fake_float parcala(uint16_t sayi , uint8_t olcek)
{
    struct fake_float x;
    x.tam = sayi/olcek;
    x.ondalik = sayi-(x.tam*olcek);
    
    return x;
}

Okan AKÇA

Hmi ekranlar int16 bölme işlemi yaparak ondalıklı sayı formatında gösterim yapılıyor.

Cemre.

#9
Alıntı yapılan: exmachine - 02 Ağustos 2018, 13:04:15En son söyle bir şey yaptım.

struct fake_float
{
    uint8_t tam,ondalik;    
};

struct fake_float parcala(uint16_t sayi , uint8_t olcek)
{
    struct fake_float x;
    x.tam = sayi/olcek;
    x.ondalik = sayi-(x.tam*olcek);
    
    return x;
}

Ölçek sayısına bölmek/çarpmak yerine left shift ve right shift yaparak daha da taşın suyunu sıkabilirsiniz. Zaten fixed point arithmetic de temelde bundan çok farklı birşey yapmıyor.

exmachine

Alıntı yapılan: Cemre. - 02 Ağustos 2018, 17:49:35Ölçek sayısına bölmek/çarpmak yerine left shift ve right shift yaparak daha da taşın suyunu sıkabilirsiniz. Zaten fixed point arithmetic de temelde bundan çok farklı birşey yapmıyor.

Evet hocam, bu da iyi bir fikir.

foseydon

yalnız shift işlemi sadece 2'nin katlarında işlem yapıyor.

Cemre.

Alıntı yapılan: foseydon - 03 Ağustos 2018, 09:51:52yalnız shift işlemi sadece 2'nin katlarında işlem yapıyor.

Doğrudur. Bu da yaptığımız işlemlerdeki basamak hassasiyetini belirliyor. Örneğin 10 bit kaydırma ile çalıştığımız durumda 1/1024 hassasiyetle çalışıyor oluyoruz. Şu sayfayı öneririm konu ile ilgili: https://alikhuram.wordpress.com/2013/05/20/implementing-fixed-point-numbers-in-c/

tekosis

adc özelinde konuşursam eğer;
verileri ham olarak değerlendirmek yani 10 yada 12 bitlik adc verisinde işlem (filtreleme, sıralama algoritmaları vs.)yaptıktan sonra en son sonucu float yada diğer cinslere çevirmek mcu'ya daha az yük bindirir diye düşünüyorum.
unsigned int16 hamVeri[10];
unsigned int16 adcOrtalama=0;
for(int i=0 ; i<10 ; i++)
 {
hamVeri[i]=read_adc1();
 }
 
for(int i=0 ; i<10 ; i++)
 {
adcOrtalama=adcOrtalama+hamVeri[i];
 }
 adcOrtalama=adcOrtalama/10;
 // mV cinsinden voltaj hesabı için çarpan(10 bit adc için) : (5/2014) * 1000
 unsigned int16 voltaj = adcOrtalama*4.882;//Bu işlem voltaj değerini mV olarak verir.
 // float işlemine gerek kalmaz.
İlim ilim bilmektir, ilim kendin bilmektir, sen kendin bilmezsin, bu nice okumaktır.