Temel Hesap Makinesi


20

Hesap makinesine girilecek dizeyi değerlendirmek için bir program yazmalısınız.

Programın girişi kabul etmesi ve doğru cevabı vermesi gerekir. Standart giriş / çıkış fonksiyonları yoktur diller için, işlevlerini üstlenebilir readLineve print.

Gereksinimler

  • Herhangi bir "eval" işlevi kullanmaz
  • Kayan nokta ve negatif sayıları işleyebilir
  • En azından +, -, * ve / operatörlerini destekler
  • Operatörler ve sayılar arasında bir veya daha fazla boşluk içeren girişi işleyebilir
  • İfadeyi soldan sağa değerlendirir

En kısa program kazanır. Beraberlik durumunda ilk gönderilen program kazanır.

Girişin geçerli olduğunu ve doğru biçimi izlediğini varsayabilirsiniz.

Test Durumları

Giriş

-4 + 5

Çıktı

1


Giriş

-7.5 / 2.5

Çıktı

-3


Giriş

-2 + 6 / 2 * 8 - 1 / 2.5 - 18

Çıktı

-12

Hesap makinem postfix kullanıyor . Ayrıca bkz . Rekabet için Yığın Taşması Üzerindeki Matematiksel İfadeleri Değerlendirme (kuralların aynı olup olmadığını kontrol etmedim).
dmckee

3
Üçüncü test durumu yanlış - ister standart işlem sırasını takip edin, ister tüm işlemleri soldan sağa gerçekleştirin. İkinci test senaryosuna baktığınızda, hesap makineniz her işlemin sonucunu tamamlıyor mu?
Lütfen

İkinci ve üçüncü test durumu düzeltildi, sonuç yuvarlanmadı.
Kevin Brown

Üçüncü test durumu standart işlem sırasına uymaz. Cevaplarımızın olması gerekiyor mu?
John

1
ARGV komut satırı argümanlarını kullanmaya ne dersiniz? çünkü kabuk argümanları otomatik olarak böler ve listeler.
Ming-Tang

Yanıtlar:


7

Ruby - 74 69 67 65 karakter

a=0
("+ "+$<.read).split.each_slice 2{|b,c|a=a.send b,c.to_f}
p a

1
Kullanmak b[0],b[1].to_fyerine |b|onunla değiştirebilirsiniz |b,c|ve kullanabilirsinizb,c.to_f
Nemo157

\teşekkürler ! :-)
Arnaud Le Blanc

1
Bunun yerine a.send(b,c.to_f)kullanın a.send b,c.to_f. Bir char
anonim korkak

1
Bunun $<yerine kullanabilirsinizARGF
Dogbert

9

Befunge - 37 x 5 = 185 38 x 3 = 114 karakter

Befunge'nin kayan nokta desteği olmadığı için bu tam sayılarla sınırlıdır.

&v      /& _ #`&# "-"$# -#<          v
 >~:0`!#v_:" "`! #v_:","`#^_"*"`#v_&*>
 ^      ># $ .# @#<              >&+ 

açıklama

Befunge'nin en büyük ayırt edici özelliği, çoğu dil gibi doğrusal bir talimat kümesi olmak yerine; kontrolün herhangi bir yönde akabildiği tek karakterli talimatların 2d ızgarasıdır.

Birincisi &sadece ilk sayıyı girer. vVe >daha sonra ikinci satırda ana yola yönlendirme kontrolü.

~:0`!#v_

Bu, bir karakter ( ~) girer , çoğaltır ( :), yığına sıfır iter ( 0), ilk iki öğeyi ` açar ve ikincinin birinciden büyük olup olmadığını belirler ( şaşırtmak için `` ` backticks kodunu girin. ), üst öğenin ( !) doğruluğunu tersine çevirir , sonra sıfırsa sağa, aksi takdirde aşağıya doğru gider ( #v_).

Temel olarak, girdinin artık girişi -1temsil edip etmediğini kontrol eder.

># $ .# @

Giriş daha -1sonra yinelenen giriş değeri atılır ( $), yığının üst kısmı bir tamsayı ( .) olarak çıkar ve program durdurulur ( @).

:" "`! #v_

Aksi takdirde, girişin bir boşluktan küçük veya ona eşit olup olmadığını belirlemek için benzer bir işlem tekrarlanır. Eğer bir boşluksa, kontrol aşağı iner, aksi takdirde kontrol kafaları sağa.

^      ># $ .# @#<

Bir boşluksa sola ( <) yönlendirilir ; program durdurma ( @), çıkış ( .) ve sağ yönlendirme ( >) kullanılarak tümü atlanır #; ancak atılan alanı yığından kaldırmak için yürütülür. Sonunda bir sonraki çalıştırmaya ( ^) başlamak için yönlendirilir .

:","`#^_

Aynı süreci ise üzerinde bölmek için kullanılan bir boşluk olmasaydı [+, *]ya da [-, \]sağa ve yukarı sırasıyla gidiyor.

 >~                         "*"`#v_&*>
 ^                               >&+

Çünkü [+, *]a +veya a olup olmadığını belirlemek için tekrar bölünür *. Eğer +aşağı yönlendirilirse, bir sonraki sayı girilir ( &) ve eklenir ( +), kontrol daha sonra etrafına sarılır ve bir sonraki karakter için ana yola yönlendirilir. Eğer *öyleyse ( &) girer ve çarpar ( *) sonra doğrudan etrafı sarar.

/& _ #`&# "-"$# -#<

Çünkü [-, \]sağdan sola başlar. #'İlk bir yol olacak şekilde onlara karakteri atlama s "-"`_bunun ise sadece belirler -ya da /. Eğer öyleyse, /input ( &) ve divide ( /) için sola devam eder . Eğer öyleyse -sağa dönüyorsa, karakterlerin atlanması için tekrar atlanır, böylece &"-"$-sayı girilir ( &) -, yığına itilen karakterin ardından atılır ( "-"$) ve ardından çıkarma ( -) hesaplanır . Kontrol daha sonra ana yola geri yönlendirilir.


6

Python 3, 105 bayt

Dört temel işlemleri yönetir, ancak yalnızca 5 karakter her eklemek için maliyeti ^ya %.

f=float
x,*l=input().split()
while l:o,y,*l=l;x,y=f(x),f(y);x=[x+y,x-y,x*y,x/y]['+-*/'.find(o)]
print(x)

Operasyonların önceliği soldan sağa doğrudur.


5

Python (156)

from operator import*
while 1:
 l=raw_input().split();f=float
 while len(l)>2:l[:3]=({'*':mul,'/':div,'+':add,'-':sub}[l[1]](f(l[0]),f(l[2])),)
 print l[0]

1
Python 3'ü kullanmak daha kolay
jamylak

5

C - 168126 karakter

main(c){float a,b;scanf("%f",&a);while(scanf("%s%f",&c,&b)!=-1)c=='+'?a+=b:c=='-'?(a-=b):c=='*'?(a*=b):(a/=b);printf("%f",a);}

5

Tcl 8.6, 57 48 karakter.

  • Bağımsız değişkenlerden girdi:

    lm o\ b [las $argv a] {set a [exp $a$o$b]};pu $a
    
  • Stdin Gönderen ( 64 53 )

    lm o\ b [las [ge stdin] a] {set a [exp $a$o$b]};pu $a
    

Her iki çözüm için de etkileşimli kabuğu kullanmanız gerekir.

Ben liste olarak girdi tedavi ilk elemanını alıp atamak (Tcl boşlukla kullanır) a, sonra gerisini üzerinde yürümek, 2 elemanları her seferinde, operatör ve ikinci sayı alarak üzerinde operatörü uygulayacaktır $ave $bve atamak sonuç a. Sonunda sonuç geldi a.


Ideone en azından stdin'i destekliyor.
Johannes Kuhn

Sonunda Ruby'yi yendim. Ne yazık ki Idone Tcl 8.6'yı desteklemiyor, ancak sonuca ihtiyacım yok, lmapbu yüzden foreachiyi bir yedek.
Johannes Kuhn

4

Haskell: 124 114 karakter

j[o]=o
j(u:m:b:o)=j$show((case m of{"+"->(+);"-"->(-);"*"->(*);"/"->(/)})(read u)(read b)):o
main=interact$j.words

Desen eşleştirme ve ağır kaldırma için basit bir durum ifadesi kullanan oldukça basit bir cevap. Kullanımı:

> ./calc <<< "123 - 12 + -12 / 12.124 * 9.99 - 1"
80.57456285054437

1
Bunun yerine 2 karakter daha az ((case m of{..})(read u)(read b))yazabilirsiniz ((case m of{..}$read u)$read b).
homoseksüel

4

C: 111108 karakter

main(c){float a,b;for(scanf("%f ",&a);~scanf("%c%f ",&c,&b);a=c^43?c%5?c%2?a/b:a*b:a-b:a+b);printf("%f",a);}

Tüm gereksinimleri, kullanımı yerine getirir:

> ./calc <<< "-43 - 56 + 14.123 / -13.22"
6.420348

1
~scanfdeğiştirebilirsiniz +1. Ayrıca, c^45-> c%5ve c^42-> c%2çalışmalıdır.
ugoren

@MDXF makinemde değil, buradaki her test senaryosunu geçiyor. Clang ile oldukça modern bir Intel Macbook üzerinde derliyorum ve çok iyi çalışıyor (şimdi tekrar test ettim, kodu buradan kopyaladım ve herhangi bir bayrak olmadan derledim). Hangi derleyici, işlemci mimarisi ve işletim sistemini kullanıyorsunuz?
Fors

@Fors Ben garip davranış teşvik bazı garip bayrakları olduğuna inanıyorum; benim hatam, şimdi benim için çalışıyor. Sizi rahatsız ettiğimiz için özür dileriz.
MD XF

3

C ++ 0 x 205 203 198 194 karakter

#include<iostream>
#define P [](F l,F r){return l
int main(){typedef float F;F r,v,(*a[])(F,F)={P*r;},P+r;},0,P-r;},0,P/r;}};std::cin>>r;for(char o;std::cin>>o>>v;)r=a[o-42](r,v);std::cout<<r;}

Güzel biçimlendirilmiş:

#include<iostream>

int main()
{
    float r,v;
    float (*a[])(float,float)   ={  [](float l,float r){return l*r;},
                                    [](float l,float r){return l+r;},
                                    0,
                                    [](float l,float r){return l-r;},
                                    0,
                                    [](float l,float r){return l/r;}
                                 };

    std::cin>>r;
    for(char o;std::cin>>o>>v;)
        r=a[o-42](r,v);

    std::cout<<r;
}

3

Perl (97)

$b=shift;eval"\$b$r=$s"while($r=shift,$s=shift);print$b

tartışmalardan oku

$b=shift;$b=($r eq'+'?$b+$s:$r eq'-'?$b-$s:$r eq'*'?$b*$s:$b/$s)while($r=shift,$s=shift);print$b;

girişten oku

@_=split/ /,<>;$b=shift@_;$b=($r eq'+'?$b+$s:$r eq'-'?$b-$s:$r eq'*'?$b*$s:$b/$s)while($r=shift@_,$s=shift@_);print$b

3

PostScript (145)

Başka bir PostScript girişi (PostScript için ilginç golfleri kazmaya yarayan luser droog!):

[/+{add}/-{sub}/*{mul}/{div}>>begin(%stdin)(r)file
999 string readline
pop{token not{exit}if
count 4 eq{3 1 roll
4 1 roll
cvx exec}if
exch}loop
=

Un-golfed:

[/+{add}/-{sub}/*{mul}/ {div}>>begin
% Read the input
(%stdin)(r)file 999 string readline pop
{                        % .. string
  token not{exit}if      % .. string token
  % If we have 4 objects on the stack, we have two operands, one operator
  % and the input string. This means, we can calculate now.
  count 4 eq{            % a op string b
    % perform operation a op b = c (where op can be +,-,*,/)
    3 1 roll             % a b op string
    4 1 roll             % string a b op 
    cvx exec             % string c
  }if                    % string token (or c)
  exch                   % token string
}loop
=

Beni dövmeye devam ediyorsun! +1 Bu çok heyecan verici.
luser droog

Eğer bulmacamı yenebilirsen , sana bir lütuf vereceğim! Not: Gönderi CW haline gelmeden ve oylar size puan kazandırmadan 10 kez düzenleyebilirsiniz.
luser droog

Nerede ben sadece olanları seçti çünkü seni dövmeye devam edebilir seni yendim ;-). Bulmaca ızgara ile yapabilir miyim emin değilim. Belki deneyeceğim, ama sadece birkaç hafta içinde.
Thomas

1
Topluluk Wiki. Bu, yayının şimdi topluluğa ait olduğu kadar çok kez düzenlendiği anlamına gelir. Herhangi bir kullanıcı bunu düzenleyebilir (normal önerilen düzenlemeler için gerekli olan moderatör onayını atlayarak ) ve başka puan kullanamaz . Ne yaparsanız yapın, Rev 9'da durun. Neredeyse gitar sekmesinde birinci patladım.
luser droog

1
Tüm bu CW kavramalarını dikkate almayın. Düzeltdiler!
luser droog

3

Python - 308

import sys;i=sys.argv[1].split();o=[];s=[];a=o.append;b=s.pop;c=s.append
for t in i:
 if t in"+-*/":
  if s!=[]:a(b())
  c(t)
 else:a(t)
if s!=[]:a(b())
for t in o:
 if t=="+":c(b()+b())
 elif t=="-":m=b();c(b()-m)
 elif t=="*":c(b()*b())
 elif t=="/":m=b();c(b()/m)
 else:c(float(t))
print(b())

Okunabilir sürüm:

# Infix expression calc

import sys

# Shunting-yard algorithm
input = sys.argv[1].split()
output = []
stack = []

for tkn in input:
    if tkn in "+-*/":
        while stack != []:
            output.append(stack.pop())
        stack.append(tkn)
    else:
        output.append(tkn)

while stack != []:
    output.append(stack.pop())

# Eval postfix notation
for tkn in output:
    if tkn == "+":
        stack.append(stack.pop() + stack.pop())
    elif tkn == "-":
        tmp = stack.pop()
        stack.append(stack.pop() - tmp)
    elif tkn == "*":
        stack.append(stack.pop() * stack.pop())
    elif tkn == "/":
        tmp = stack.pop()
        stack.append(stack.pop()/tmp)
    else:
        stack.append(float(tkn))

print(stack.pop())

İfadeyi komut satırı argümanı olarak alır, standart çıktıda çıktı alır.


2

PostScript (340)

/D<</+{add}/-{sub}/*{mul}/ {div}>>def/eval{/P null def{token not{exit}if exch/rem exch def
dup D exch known{/P load null ne{D/P load get exch/P exch def exec}{/P exch def}ifelse}if
rem}loop/P load null ne{D/P load get exec}if}def {(> )print flush{(%lineedit)(r)file
dup bytesavailable string readline pop eval == flush}stopped{quit}if}loop

Ve biraz daha okunabilir:

%!
/oper<</+{add}/-{sub}/*{mul}/ {div}>>def

/eval{
    /op null def
    {
        token not {exit} if
        exch /rem exch def
        dup oper exch known {
            /op load null ne {
                oper /op load get
                exch /op exch def
                exec
            }{
                /op exch def
            } ifelse
        } if
        rem
    } loop
    /op load null ne { oper /op load get exec } if
} def

{
    (> )print flush
    {
    (%lineedit)(r)file
    dup bytesavailable string readline pop
    eval == flush
    } stopped { quit } if
} loop

2

JavaScript (208 karakter sıkıştırılmış)

Açıklık için, ben onu sıkıştırmadan önce kod ( JS-Fiddle ):

function math(match, leftDigit, operator, rightDigit, offset, string) {
    var L = parseFloat(leftDigit)
    var R = parseFloat(rightDigit)
    switch (operator)
    {
        case '*': return L*R;
        case '/': return L/R;
        case '+': return L+R;
        case '-': return L-R;
    }
};

str = prompt("Enter some math:", "-2 + 6 / 2 * 8 - 1 / 2.5 - 18").replace(/ /g, "");
var mathRegex = /(\-?\d+\.?\d*)([\*\/\+\-])(\-?\d+\.?\d*)/;
while(mathRegex.test(str)) {
    str = str.replace(mathRegex, math);
}
alert(str)

Burada 208 karaktere kadar sıkıştırılmıştır ( JS-Fiddle ):

function m(x,l,o,r){
    L=(f=parseFloat)(l);
    R=f(r);
    return o=='*'?L*R:o=='/'?L/R:o=='+'?L+R:L-R;
};

M=/(\-?\d+\.?\d*)([\*\/\+\-])(\-?\d+\.?\d*)/;
for(s=prompt().replace(/ /g, "");M.test(s);s=s.replace(M,m)){};
alert(s)

Çizgileri noktalı virgülle bitirdiğim için, tüm sayılabilir boşluk karakter sayımı için yok sayıldı, ancak netlik için bırakıldı.


2

Haskell - 124

let p=let f[x]=Just$read x;f(x:o:r)=lookup o[("-",(-)),("+",(+)),("*",(*)),("/",(/))]<*>f r<*>Just(read x)in f.reverse.words

Sonuç Maybemonad'a sarılacak

λ: p"-2 + 6 / 2 * 8 - 1 / 2.5 - 18"
Just (-12.0)

Ayrıca ithal gerektirir <*>gelen Control.Applicative, ancak İzin verilen umut böylece ithalat, kod dışında yapılabilir.


2

C # (234) (231) (229) (223) (214)

class A{void Main(string[]s){var n=1;var o="";var r=0F;foreach(var t in s){if(n>0){var v=float.Parse(t);if(o=="")r=v;if(o=="+")r+=v;if(o=="-")r-=v;if(o=="*")r*=v;if(o=="/")r/=v;}o=t;n=-n;}System.Console.Write(r);}}

class A{
    void Main(string[] s)
    {
      var n = 1;
      var o = "";
      var r = 0F;

      foreach (var t in s)
      {
        if (n > 0)
        {
          var v = float.Parse(t);
          if (o == "") r = v;
          if (o == "+") r += v;
          if (o == "-") r -= v;
          if (o == "*") r *= v;
          if (o == "/") r /= v;
        }
        o = t;
        n = -n;
      }
      System.Console.Write(r);
    }
}

'1 + 1' için '0' alıyorum. IDEONE
Rob

@Mike Girdilerini bağımsız değişken olarak girin, stdin değil.
Johannes Kuhn

1

JavaScript (87 karakter)

alert(prompt().split(/ +/).reduce((a,b,i)=>i%2?(o=b,a):o+1-0?a-b*-(o+1):o<'/'?a*b:a/b))

1

Java 11, 151 (lambda işlevi olarak)

s->{float r=0,t;int o=43,q;for(var x:s.split(" ")){if(x.length()>1|(q=x.charAt(0))>47){t=new Float(x);r=o<43?r*t:o<44?r+t:o<46?r-t:r/t;}o=q;}return r;}

Bir String girişi alarak ve bir float çıkışı veren Lambda işlevi.

Çevrimiçi deneyin.

Java 11, 241 bayt (istenen G / Ç ile tam program olarak)

interface M{static void main(String[]a){float r=0,t;int o=43,q;for(var x:new java.util.Scanner(System.in).nextLine().split(" ")){if(x.length()>1|(q=x.charAt(0))>47){t=new Float(x);r=o<43?r*t:o<44?r+t:o<46?r-t:r/t;}o=q;}System.out.print(r);}}

STDIN üzerinden bir String-line alarak ve STDOUT'a çıkış yapan tam program.

Çevrimiçi deneyin.

Açıklama:

interface M{                  // Class
  static void main(String[]a){//  Mandatory main-method
    float r=0,                //   Result float, starting at 0
          t;                  //   Temp float
    int o=43,                 //   Operator flag, starting at '+'
        q;                    //   Temp operator flag
    for(var x:new java.util.Scanner(System.in)
                              //   Create an STDIN-reader
               .nextLine()    //   Get the user input
               .split(" ")){  //   Split it on spaces, and loop over it:
      if(x.length()>1         //    If the current String length is larger than 1
                              //    (work-around for negative values)
         |(q=x.charAt(0))>47){//    Or the first character is an operator
                              //    (and set `q` to this first character at the same time)
        t=new Float(x);       //     Convert the String to a float, and set it to `t`
        r=                    //     Change `r` to:
          o<43?               //      If `o` is a '*':
            r*t               //       Multiply `r` by `t`
          :o<44?              //      Else-if `o` is a '+':
            r+t               //       Add `r` and `t` together
          :o<46?              //      Else-if `o` is a '-':
            r-t               //       Subtract `t` from `r`
          :                   //      Else (`o` is a '/'):
            r/t;}             //       Divide `r` by `t`
      o=q;}                   //    And at the end of every iteration: set `o` to `q`
    System.out.print(r);}}    //    Print the result `r` to STDOUT

1

05AB1E , 30 bayt

#ćs2ôívy`…+-*sk©i-ë®>i+ë®<i*ë/

Çevrimiçi deneyin veya tüm test senaryolarını doğrulayın .

Açıklama:

#           # Split the (implicit) input-string by spaces
 ć          # Pop the list, and push the remainder and first item separated to the stack
  s         # Swap so the remainder is at the top of the stack
   2ô       # Split it into parts of size 2 (operator + number pairs)
     í      # Reverse each pair so the numbers are before the operators
v           # Loop over each of the pairs:
 y`         #  Push the number and operator separated to the stack
   …+-*     #  Push a string "+-*"
       sk   #  Get the index of the operator in this string
         ©  #  Store this index in the register (without popping)
   i        #  If the index is 1 (the "-"):
    -       #   Subtract the numbers from each other
   ë®>i     #  Else-if the index is 0 (the "+"):
       +    #   Add the numbers together
   ë®<i     #  Else-if the index is 2 (the "*"):
       *    #   Multiply the numbers with each other
   ë        #  Else (the index is -1, so "/"):
    /       #   Divide the numbers from each other
            # (and output the result implicitly)

Bir evalyerleşime izin verildiyse , bu alternatif bir yaklaşım olabilir ( 16 bayt ):

#ćs2ôJv…(ÿ)y«}.E

Çevrimiçi deneyin veya tüm test senaryolarını doğrulayın .

Açıklama:

#ćs2ô    # Same as above
     J   # Join each operator+number pair together to a single string
v        # Loop over the operator+number strings:
 …(ÿ)    #  Surround the top of the stack in parenthesis
     y«  #  And append the operator+number string
}.E      # After the loop: evaluate the string using a Python-eval

Bu değiştirecek "-2 + 6 / 2 * 8 - 1 / 2.5 - 18"için "((((((-2)+6)/2)*8)-1)/2.5)-18"kullanmadan önce evalyerleşiği (kullanarak .Eoperatöre ait söz konusu olacak, doğrudan */üzerinde +-, parantez nedenle dönüşüm önce).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.