HI-TECH C'de Matematiksel işlem sorunu?

Başlatan papylon, 07 Ekim 2009, 07:16:22

papylon

Aşağıda ki gibi bir matematiksel işlem yaptığımda hatalı sonuç alıyorum.
Normalde int tanımlı sonuc değişkenin içinde, bu değişkene sığabilecek büyüklükde 990 değeri olması gerekirken, ya da en azından ben öyle düşünüyorum. :?  fakat 65216 değeri çıkıyor.

unsigned char ch1=250;
unsigned char ch2=99;
unsigned int sonuc;

    	sonuc= (ch1*ch2*4/100);// Hatalı sonuç (sonuc = 65216)


Sonuc değişkeninin tanımlamasını long olarak yapıyorum fakat yine hatalı sonuç alıyorum. Sonuç yine 65216
unsigned char ch1=250;
unsigned char ch2=99;
unsigned long sonuc;

    	sonuc= (ch1*ch2*4/100);// Hatalı sonuç (sonuc = 65216)

Sonuc değişkeninin tanımlamasını int yapıyorum ve matematiksel işlemin şeklini değiştiriyorum. Bu sefer de sonuç 334
unsigned char ch1=250;
unsigned char ch2=99;
unsigned int sonuc;

    	sonuc= (ch1*ch2);
    	sonuc= (sonuc*4/100);// Hatalı sonuç (sonuc = 334)

Bu sefer de Sonuc değişkeninin tanımlamasını short long yapıyorum ve matematiksel işlemin şekli de yine yukarıda ki gibi. Ve bu sefer DOĞRU Sonuç 990
unsigned char ch1=250;
unsigned char ch2=99;
unsigned short long sonuc;

    	sonuc= (ch1*ch2);
    	sonuc= (sonuc*4/100);// Doğru sonuç (sonuc = 990)

Anlayamadığım 990 değeri, int tanımlı sonuc değişkenine sığabilecek büyüklükte ki zaten 990 değerinden çok daha büyük olan 65216 sığıyor. Ve neden sonuc değişkenini long olarak tanımladığım halde ve tek işlem satırında doğru sonuca ulaşamıyorum da, şekilden şekle girip cambazlıklar yaparak doğru sonuca ancak ulaşabiliyorum.

Bu C beni çok üzüyor çoook... :(

X-Fi

bende çok sıkıntı çekmiştim bu konuda CCS de hesaplanan formülleri hi-tech de hesaplayamıyorum çok basite indirip satır satır formülü açmam gerekti çözümü bende merakla bekliyorum.

örneğin bu kod ccs de çalışırken hi-tech de çalışmadı üzerinde çok uğraştım birsürü işlemle başdan hesaplatabilmişdim.

#define FREQ(freq)	((freq-430.0)/0.0025);
http://www.coskunergan.dev/    (Yürümekle varılmaz, lakin varanlar yürüyenlerdir.)

Elektroemre

Bende aynı sorunla karşılaştım ve aynı şekilde işlemleri bikaç satıra bölerek çözüm buldum.
Neden böyle bir sorun olduğunu çok merak ediyorum, olay Hi-Tech'in bir bug'ımı, yoksa gözden kaçırdığımız bir nokta mı var?

Ustadlardan gelecek cevapları merakla bekliyorum bende.

Saygılar...

z

unsigned long ch1=250;
unsigned long ch2=99;
unsigned long sonuc;

sonuc= (ch1*ch2*4/100);

yada

unsigned char ch1=250;
unsigned char ch2=99;
unsigned long sonuc;

sonuc= (unsigned long) (ch1) * (unsigned long) (ch2) * 4/100);

denenebilir.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

papylon

İki satır kodu sabahlara kadar da uğraşsak iki büklüm olup altından girip üstünden de çıksak, eh işte bir şekilde yazılıyor. Acemiyiz ya.  :)
Ama gel gelelim ki işin kötü tarafı zaten matematiksel işlem yaparken bolca RAM'den feragat ediyoruz, üstüne üslük bir de atama yapacağım değişkeni, hatta yerine göre hiç değişken atamadan halledeceğim işi caracter yerine long olarak tanımlamak adamın sinirlerini iyice bozuyor.  Ve zaten kısıtlı olan hafıza alanın da israftan başka bir şey değil.
Olur, gibi görünen şeye büyük bir inatla olmaz diyor, ben olur diyorum o olmaz diyor. C ile daha yeni tanıştık ama çok üzüyor, hatta bazen çıldırtıp çileden çıkartıyor. Bakalım daha da kullandıkça neler neler çıkacak.

papylon

@Z hocam Cevap için çok teşekkürler.

Anladığım kadarıyla altta yazdığınız kod da geçici olarak tür dönüşümü yapıyoruz ve yine anladığım kadarıyla HI-TECH bunu kekendi yapamıyor.
Matematiksel işlemi parçalayıp yazmaktansa gösterdiğiniz yol daha akla yatkın.

Fakat yine anlayamadığım şey sonuç 990 olduğu halde, yani int türünden bir değişkene sığabildiği halde neden sonuç değişkenini de long olarak tanımlamak zorunda kalıyoruz?

z

Onerdigim metodlar ise yaradimi? Ozellikle de 2 yontem. Ben demedim sonucu merak ettim.

Sonuc 990 olmasina ragmen, ara islemler asamasinda char terimlerinin carpim sonucu 16 biti asiyor. (250*99*4=99000)

Bu da sikinti yaratiyor. Bunun icin fonksiyonun elemanlarini bir ust seviyedeki uzunluga cikartmaya zorlamak gerekiyor. (
type castingin gorevlerinden birisi de bu)
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

papylon

Ayrıca az önce sizin verdiğiniz şekilde aşağıda ki gibi programı derledim ve gayet düzgün çalışıyor.
unsigned char ch1=250;
unsigned char ch2=99;
unsigned short long sonuc;

    	sonuc= ((unsigned short long)(ch1)*(unsigned short long)(ch2)*4/100);

Fakat sonuc değişkenini aşağıda ki kod da int olarak tanımladım sonuç hatalı. 222 çıkıyor.
unsigned char ch1=250;
unsigned char ch2=99;
unsigned int sonuc;

    	sonuc= ((unsigned short long)(ch1)*(unsigned short long)(ch2)*4/100);

İşin garibi bu seferde sonuc değişkenini caracter olarak tanımladım ve işlemde 100 yerine 1000'e yani character içine sığabilecek büyüklükte bölme işlemi yaptım ve bura da sonuç 99 olarak doğru çıkıyor.
unsigned char ch1=250;
unsigned char ch2=99;
unsigned char sonuc;

    	sonuc= ((unsigned short long)(ch1)*(unsigned short long)(ch2)*4/1000);

İşte anlayamadığım ve iyice kafamı karıştıran şey bu. Short long'un içindeki character'e sığabilecek değeri doğru olarak yazıyor fakat short long'un içindeki integer'a sığabilecek büyüklükteki değeri doğru olarak yazamıyor. Neden?

z

Sen sonucun degisken icine sigip sigmadigina bakiyorsun. Halbuki ara islemlerin de sigip sigamadigina bakmak gerekli.

250*99*4=99000 ara islemi unsigned int alana sigamayacak kadar buyuk.

Normalde iyi bir derleyici bu sorunun ustesinden gelebilir yada en azindan warning verir.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

papylon

Söylediklerinizi anladım fakat bu durumda character ile tanımladığım en altta verdiğim kod da sonuç neden doğru çıkıyor?
Aynı matematiksel işlemler (250*99*4=99000) orada da yapılıyor. İşte anlayamadığım şey bu.

Erol YILMAZ

Type Casting C de çok önemlidir.
Bu yüzden dikkatli olunmalı,
yalnız...  başka konularda da dikkatli olmalıyız !
Mesela

unsigned char ch1=250; 
unsigned char ch2=99; 
unsigned long sonuc; 

       sonuc= (ch1*ch2); 
       sonuc= (sonuc*4/100);// Doğru sonuç (sonuc = 990)


sonuc = sonuc *4 / 100;


yerine

sonuc /=25;


dememiz yeterli.

z

char tanimda neden dogru cikiyora kafa yormak lazim.

Daha onceki sorunuzda

unsigned char ch1=250;
unsigned char ch2=99;
unsigned int sonuc;

       sonuc= (ch1*ch2);
       sonuc= (sonuc*4/100);// Hatalı sonuç (sonuc = 334)


islemlerinin neden 334 ciktigini soyleyeyim.

250*99*4=99000 yani 182b8H -> 16 bit icine 82b8H diye atilir.

82b8H ondalik sistemde 33464 demektir. Bunu da 100 e bolersen 334 cikar.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

papylon

Bu güzel ayrıntı için de ayrıca teşekkür ederim @Allegro hocam.

papylon

Bu arada az önce kurcalarken başka bir sorunla daha karşılaştım. Yukarıda bahsettiğim kodları sprintf fonksiyonunu kullanarak ISIS'de LCD ile simülasyonu gerçekleştiriyordum.
Rakamları 5 haneden fazla yazamadığını fark ettim ve aşağıda ki gibi sonuc değişkenine 125000 atadım ve sonuç simülasyonda hatalı çıktı. Yani int değerinden (65535) büyük bir değeri yazamıyor. Belki diger hatalara da bu sorun sebep olmuş olabilir. Sprintf fonksiyonunda nasıl bir hata yapıyorum peki?
(%d, %i, %f, %e, %s, %c, %u, %x) hepsini denedim ama hepsinde de olumsuz sonuç.
#include <htc.h>
#include <stdio.h>
#include "lcd4.h"
 /* PIC16F628 konfigürasyon tanımlamaları*/ 
__CONFIG(UNPROTECT & INTIO & MCLRDIS & WDTDIS & LVPDIS & PWRTEN & BOREN );

unsigned char outString[10];

void main(void)
{	
	TRISB=0x00;
	TRISA=0x00;
	PORTB=0x00;
	PORTA=0x00;
	OPTION = 0x00;
	CMCON = 0x07;
unsigned short long sonuc= 65536;

    lcd_init(); 
    lcd_puts("Sonuc Degeri=");
			sprintf(outString,"%u",sonuc);
			lcd_gotoxy(2,5);
			lcd_puts(outString);
		for(;;);

ahmet2004

papylon 32bit sayılarıda kullanabiliyoruz.

#include <htc.h>
#include <stdio.h>
#include "delay.h"
#include "lcd.h"

__CONFIG(UNPROTECT & WDTDIS & LVPDIS & PWRTEN & BOREN );

unsigned char outString[20];

void main(void)		// Ana fonksiyon alanı
{
	unsigned long sonuc = 4294967295; //Maksimum 32bit sayı: 4,294,967,295
	TRISB=0x00;
	TRISC=0x00;
	PORTB=0x00;
	PORTC=0x00;
	OPTION = 0x00; 
	CMCON = 0x07; 

	lcd_init();
	
	lcd_yaz("  ahmet2004  ");
	lcd_gotoxy(2,1);
	lcd_yaz("  YIL: 2009");
	DelayMs(2000);
	lcd_clear();
	
	while(1)
	{
	    sprintf(outString,"%lu",sonuc); 
	    lcd_gotoxy(0,1); 
	    lcd_yaz(outString);	
	}
}