Hesap makinesinde islemlerin oncelik siralamasi

Başlatan z, 14 Temmuz 2013, 15:46:40

z

Hesap makinesi arayuzu yaziyorum.

Kullanici 1+2*3+4= tuslarina sira ile basmis olsun.

Bu islem 1 + (2*3) + 4 = 11 sonucunu vermelidir.

Bu problemi, basilan tuslari basit bir algoritmayla ikili operandi ve bir operatoru olan basit islemler olarak ele alamiyoruz.

Yani 1+2=3, 3*3=9, 9+4=13 olmuyor.

Bu islemi en az degisken kullanarak yapmak istiyorum.

Konu hakkinda konusmak isteyenler buyursun.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

MrDarK

Hocam string ifade içersinde operatörleri arayarak yapılamaz mı bu iş ?

Ben olsam oyle yapardım.
Picproje Eğitim Gönüllüleri ~ MrDarK

gumush

Bilgisayardaki hesap meakinesinde 1+2=3, 3*3=9, 9+4=13 seklinde oluyor. Yani tusa basilinca hesapliyor o ana kadarkini , bu sekilde ikili ikili gitmis oluyor..
Hikmet Gumus  izmir


hasankara

örnek olarak "1+12*34+4" girilirken sırasıyla bir char dizisinin 7 hücresini ascii karakterleri ile doldururuz. entere basıldığında bu dizi hesap fonksiyonuna sokulur.

örnek olarak 12 ile 34 çarpılır sonuç * karakterinin yerine koyulur. bunu call return gibi düşünebilirsin. bu karakter yerine öyle bir karakter ekleyeceksin ki hesap fonksiyonu bu karakteri call komutu gibi algılayacak ve karakterin içerisinde adreslenen ram bölgesindeki veriyi okuyup yıldız yerinde o sayı varmış gibi davranabilecek. 1-2 ve 3-4 karakterlerin bulunduğu hücrelere geciştir komutu niteliğindeki veriyi yükleriz.

hesap fonksiyonu işlem önceliğine göre karakter araması yapar. mesela * ilk arama olur. * ile karşılaştığında bir önceki değer ile bir sonraki değerin sayı olduğu kontrolü yaparız eğer bu koşulu sağlamıyorsa syntax error deriz. koşulu sağlıyorsa bir sonraki aşama olarak, solundaki sayı ile sağındaki sayıyı decimale çevirmek olur, bu biraz zahmetli iş olacak gibi.

** işlemin solundaki sayıyı bulalım
yıldızın bulunduğu hücreden bir önceki hücre ascii verisi ise ascii-decimal dönüştür dgr1 e yükle, komut verisi ise komutu yerine getir, yani call komutu varsa dgr1 e direk adreslenen ram verisini yükletip bu aşama sonlandırılır. yoksa bu aşamada devam edilir.
iki önceki hücreyi ascii-decimal dönüştür 0_9 arasında ise 10^(2-1) katını dgr1 e ekle , üç önceki veriyi ascii_decimal dönüştür 0-9 arasında ise 10^(3-1) katını dgr1 e ekle. dönüşen sayı 0_9 arasında değil durumuyla karşılaşınca soldaki sayıyı hesaplamış olduk bir sonraki aşama olarak sağındaki sayıları hesaplamaya geldi sıra. örnek üzerinden düşünecek olursak dgr1=12 değeri oldu. 10^(3-1) şeklinde yazmamın sebebi tek bir döngü içinde ifade edebilmek için.

**işlemin sağındaki sayıyı bulalım
yıldızın bulunduğu hücreden bir sonraki hücre ascii verisi ise ascii-decimal dönüştür dgr2 e yükle, komut verisi ise komutu yerine getir, yani call komutu varsa dgr1 e direk adreslenen ram verisini yükletip bu aşama sonlandırılır. yoksa bu aşamada devam edilir.
yıldızın bulunduğu hücreden iki sonraki hücreyi ascii_decimal dönüştür 0_9 arasında ise bsmk=2 yükle, üç sonraki hücreyi ascii_decimal dönüştür 0_9 arasında ise bsmk=3 yükle, else gelene kadar döngü bu şekilde ilerliyor. 0_9 arasında olmadığında yani else geldiğinde, dgr2 e yıldızın bulunduğu hücreden bsmk kadar sonraki değerin 10^(bsmk-bsmk) ile çarpılmış halini yüklet, ... 10^(bsmk-(bsmk-1)) çarpılmış halini eklet. döngü bu şekilde bsmk sayısı kadar sürünce dgr2 değerinide elde etmiş oluruz.

dgr1*dgr2 işlemi yapıldıktan sonra * karakterinin bulunduğu hücreye, bulduğumuz işlemin sonucunu kaydettirdiğimiz ram adresinin komut bilgisini yazarız.

işlem yapıldıktan sonra başka * karakteri kalmayana kadar bu işlem sürer. sonra / işlemi için benzer şekilde + için - için ... en son aratılacak başka işlem kalmadığında bu dizide sadece 1 sayı olacak ve diğer değerler geçiştir komut verileri ile dolu olacak. bu sayı sonucumuz olacak.

MC_Skywalker

Peki ya kullanıcı 1+2*3+4 işlemini yapmak istiyorsa.

Yani 1ile 2 yi topla 3 le çarp 4 le topla. Bence kullanıcıya () girişi sunulmalı. 1+(2*3)+4 şeklinde giriş yapsın.

z

Dediginiz islem gerekiyorsa zaten ( ) kullanilmali. Bahsettigim durum parantez kullanilmamasi durumunda gecerli.

Bir ton kod yazmadan bu isi halletmek istiyorum.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

hasankara

1+2*3+4 bu işlemi hesaplatmanın yanı sıra kullanıcı ne yapmak istemiş bunu çözümlemek giriyor işin içine bu yüzden kodların şişmesi doğal. dediğim gibi kullanıcı bu şekilde karışık bir dizin girdiğinde ne zaman çarpma ne zaman toplama isteyeceğini bilemediğimiz için önce isteğini kayıt edip daha sonra çözümlemek gerekir.daha sonrasında parantezleri de çözümleyebilen bir yapı haline getirilebilinir.

ancak standart bir hesap makinesi gibi iki değişkeni de kullanıcıdan isteyip yapmak istediği işlemi de isteyip bu şekilde işlem yaptırmak çok daha basit olur.

Icarus

Basit bir top down parser yazmanız yeterli, hatta rescusive yapın çok daha kolay olur. Sonra gerekirse iterative çevirin

z

Alıntı yapılan: MrDarK - 14 Temmuz 2013, 15:49:39
Hocam string ifade içersinde operatörleri arayarak yapılamaz mı bu iş ?

Ben olsam oyle yapardım.

Olaylar gercek zamanda gelişecek. Yani bir stringe dizilmiş veriler yok. 1+2*3+4= gibi katakterler sözkonusu değil.

Şu anki durumda, klavyeden basılan nümerik tuşları depolayan bir rutinim var. Bu rutin, ekrana sığdığı sürece gelen nümerik verileri paketliyor.
Eğer ekrana sığmayacak uzunlukta nümerik değerler gelmeye devam ediyorsa yeni gelenleri görmemezlikten geliyor ve + - * / sin cos log vs tuşları bekliyor.

İşte bu noktada öncelik tespit eden rutini devreye girecek ve mevcut verilerle hesap yapılacakmı yoksa bu verilerden bazıları stack'a mı atılacak yorumunu yapacak.


İki adet değişken ve stack array ile bu işi çözecem gibime geldi.

Örnek: 1+2x3-4=

Yeni bir işlem yapıyoruz S=0 yaparak stack indexi sıfırlayalım

var1=1
fonk=+

mantık sonucu

Stack(S)=var1, S=S+1, Stack(S)=fonk, S=S+1

var1=2
fonk=x

yazacagım program diyecekki çarpma işlemi oncelikli

var2=3, var1=var1 fonk var2
var2 = var1, 

Ara işlem bitti. Stackta veri varmı diye bakalım

S sıfırdan faklı olduğuna göre stacta bir şeyler var bakalım neler var

S=S-1, fonk=Stack(S),

Hala S sıfırdan faklı

S=S-1, var1=Stack(S)

var2=var1 fonk var2

gibi bir kod yazayım diyorum. Kimin stack'a atılacağını kimin o an işleneceğini if then mantık silsilesiyle programa yaptırırım diye düşünüyorum.

Düşünce tarzında hata gördüyseniz uyarırsanız sevinirim.


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

ahmets

Fikir vermesi için çalışan bir Python kodundan sadece size gerekli bölümleri aldım.
reduce() fonksiyonu içindeki eval(left + operator + right) bölümüne takılmayın. Orasını istediğiniz gibi uygularsınız.
Kodu windows'da test etmek için Python installer http://python.org/ftp/python/3.3.2/python-3.3.2.msi adresinde.

def onClear():
    global erase, text
    opnd, optr = [], [] 
    text = "0"
    erase = 1           # clear "0" text next

def onOperand(char):
    global erase, text
    if erase:
        text = char
        erase = 0
    else:
        text += char    # else append to opnd

def onOperator(char):
    global erase, text
    shiftOpnd(text)     # push opnd on left
    shiftOptr(char)     # eval exprs to left?
    text = topOpnd()    # push optr, show opnd|result
    print(text)
    erase = 1           # erased on next opnd|'('

def popOpnd():
    value = opnd[-1]                    # pop/return top|last opnd
    opnd[-1:] = []                      # to display and shift next
    return value                        # or x.pop(), or del x[-1]

def topOpnd():
    return opnd[-1]                     # top operand (end of list)

def shiftOpnd(newopnd):                 # push opnd at optr, ')', eval
    opnd.append(newopnd)

def shiftOptr(newoptr):                 # apply ops with <= priority
    while (optr and optr[-1] not in afterMe[newoptr]):
        reduce()
    optr.append(newoptr)                # push this op above result
                                        # optrs assume next opnd erases
def reduce():
    operator       = optr[-1]           # pop top optr (at end)
    [left, right]  = opnd[-2:]          # pop top 2 opnds (at end)
    optr[-1:] = []                      # delete slice in-place
    opnd[-2:] = []
    result = str(eval(left + operator + right))
    if result == None:
        result = left 
    opnd.append(result)

def onKeyboard(char):
    global text
    if char != '':
        if char in Operators:
            onOperator(char)
        else:
            if char in Operands:
                onOperand(char)
            else:
                if char == '.':
                    self.onOperand(char)
                if char in 'Ee':        # 2e10, no +/-
                    text += char
                elif char == ' ':
                    onClear()           # spacebar=clear
                elif char == '\b':
                    text = text[:-1]    # backspace


afterMe = {'*': ['+', '-', '='],
           '/': ['+', '-', '='],
           '+': ['='],
           '-': ['='],
           '=': [] }
opnd, optr = [], []
Operators = "+-*/="
Operands  = "abcd0123456789"

erase = 0
text = ""
onClear()

onKeyboard('1')
onKeyboard('+')
onKeyboard('2')
onKeyboard('*')
onKeyboard('3')
onKeyboard('+')
onKeyboard('4')
onKeyboard('=')

z

Bela bir ismis bu hesapmakinesi.

Cok sevdigim eski tip Casio hesap makinesinde

2+-x3= islemi 2x3 anlamina geliyor.

Pespese operator degistirirseniz en son operator kullanilacak demektir.

Bu durumda

2+3+x4=  (2+3) x4  anlamina geliyor.
2+3x+4=  (2+3)+4  anlamina geliyor.

Ara islemlerin sonucu da hesaplanip ekranda gosterileceginden bu ozellikleri birebir saglayacak hesapmakinesi kodlarini yazmak iyice zorlasti.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

RaMu

casio fx 5500 LA
ve
casio fx-991ES plus
bilimsel hesap makinaları
bu şekildweki yazıma syntax error veriyor,
doğal olarak.

Bence bu tip yazıma izin verilmemeli.
Sorularınıza hızlı cevap alın: http://www.picproje.org/index.php/topic,57135.0.html

z

Elimdeki makineyi (Fx3600P) kurcalayarak makinenin bazi algoritmalarini olusturmaya calisiyorum.

2+3x=11   = 2+ (3x3)

2 + 3 + x = 25 = (2 + 3) x (2 + 3)
2 + 3 -  x = 25 = (2 + 3) x (2 + 3)
2 + 3 x x = 11   
2 + 4 x / = 3

Yorumlariniz neler?
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

RaMu

2 + 3 x x = 11      = 2 + 3 çarpı 3    = 11
2 + 4 x / = 3         =2 + 4 bölü 4     =  3
olabilir.
Sorularınıza hızlı cevap alın: http://www.picproje.org/index.php/topic,57135.0.html