Kalkulator Dasar

20

Anda harus menulis program untuk mengevaluasi string yang akan dimasukkan ke dalam kalkulator.

Program harus menerima input dan mengeluarkan jawaban yang benar. Untuk bahasa yang tidak memiliki fungsi input / output standar, Anda dapat mengasumsikan fungsi readLinedan print.

Persyaratan

  • Tidak menggunakan segala jenis fungsi "eval"
  • Dapat menangani floating point dan angka negatif
  • Mendukung setidaknya +, -, *, dan / operator
  • Dapat menangani input yang berisi satu atau beberapa ruang antara operator dan angka
  • Mengevaluasi ekspresi dari kiri ke kanan

Program yang merupakan kemenangan tersingkat. Dalam hal seri, program yang diajukan menang terlebih dahulu.

Anda dapat mengasumsikan bahwa input tersebut valid dan mengikuti format yang benar

Uji Kasus

Memasukkan

-4 + 5

Keluaran

1


Memasukkan

-7.5 / 2.5

Keluaran

-3


Memasukkan

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

Keluaran

-12
Kevin Brown
sumber
Kalkulator saya menggunakan postfix . Lihat juga Mengevaluasi Ekspresi Matematika pada Stack Overflow untuk kompetisi (meskipun saya belum memeriksa apakah aturannya sama).
dmckee
3
Kasing uji ketiga salah - apakah Anda mengikuti urutan operasi standar atau menjalankan semua operasi dari kiri ke kanan. Melihat kasus uji kedua, apakah kalkulator Anda membulatkan hasil setiap operasi?
PleaseStand
Memperbaiki kasus uji kedua dan ketiga, hasilnya tidak bulat.
Kevin Brown
Kasing uji ketiga tidak mengikuti urutan operasi standar. Apakah jawaban kita seharusnya?
John
1
Bagaimana dengan menggunakan argumen baris perintah ARGV? karena shell auto-split dan daftar argumen.
Ming-Tang

Jawaban:

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
Arnaud Le Blanc
sumber
1
Alih-alih menggunakan b[0],b[1].to_fAnda dapat mengganti |b|dengan |b,c|dan menggunakanb,c.to_f
Nemo157
\ o / terima kasih! :-)
Arnaud Le Blanc
1
Alih-alih a.send(b,c.to_f), gunakan a.send b,c.to_f. Ini menghemat char
pengecut anonim
1
Anda dapat menggunakan $<sebagai gantinyaARGF
Dogbert
9

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

Ini terbatas pada angka integer karena Befunge tidak memiliki dukungan floating point.

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

Penjelasan

Fitur pembeda terbesar dari Befunge adalah bahwa alih-alih menjadi seperangkat instruksi linier seperti kebanyakan bahasa; itu adalah kotak 2d instruksi karakter tunggal, di mana kontrol dapat mengalir ke segala arah.

Yang pertama &hanya memasukkan angka pertama. The vdan >kemudian kontrol redirect ke jalan utama di baris kedua.

~:0`!#v_

Ini menginput karakter ( ~), menduplikatnya ( :), mendorong nol ke tumpukan ( 0), muncul dua elemen teratas dan menentukan apakah yang kedua lebih besar dari yang pertama ( ` saya terkejut Anda tidak dapat menggunakan `` `untuk mendapatkan kode backticks. ), membalikkan kebenaran dari elemen atas ( !), lalu berbelok ke kanan jika nol, turun sebaliknya ( #v_).

Pada dasarnya memeriksa apakah input -1mewakili tidak ada input lagi.

># $ .# @

Jika input -1kemudian nilai input duplikat dibuang ( $), bagian atas tumpukan adalah output sebagai integer ( .) dan program dihentikan ( @).

:" "`! #v_

Kalau tidak, proses serupa diulang untuk menentukan apakah input kurang dari atau sama dengan spasi. Jika itu adalah ruang maka kontrol turun, jika tidak kontrol kepala kanan.

^      ># $ .# @#<

Jika ini adalah spasi maka dialihkan ke kiri ( <); program halt ( @), output ( .) dan redirection kanan ( >) semuanya dilewati menggunakan #; tetapi buangan dijalankan untuk menghilangkan ruang dari tumpukan. Akhirnya diarahkan untuk memulai eksekusi berikutnya ( ^).

:","`#^_

Jika itu bukan ruang, proses yang sama digunakan untuk membagi jika itu dalam [+, *]atau di [-, \]masing-masing naik dan naik.

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

Untuk [+, *]itu lagi dibagi untuk menentukan apakah itu a +atau a *. Jika +diarahkan ke bawah maka angka berikutnya adalah input ( &) dan mereka ditambahkan ( +), kontrol kemudian membungkus dan diarahkan ke jalur utama untuk karakter berikutnya. Jika *kemudian input ( &) dan dikalikan ( *) maka langsung membungkus.

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

Untuk [-, \]itu dimulai di sebelah kanan menuju kiri. Itu #melewatkan karakter setelah mereka sehingga jalur awal adalah "-"`_yang hanya menentukan apakah itu -atau /. Jika ya /maka terus ke input ( &) dan bagi ( /). Jika itu -kemudian mengarah ke kanan, sekali lagi melewatkan karakter sehingga dieksekusi &"-"$-menghasilkan angka yang menjadi input ( &) -karakter didorong ke tumpukan kemudian dibuang ( "-"$) dan kemudian pengurangan dihitung ( -). Kontrol kemudian diarahkan kembali ke jalur utama.

Nemo157
sumber
6

Python 3, 105 byte

Mengelola empat operasi dasar, tetapi masing-masing hanya menambah 5 karakter untuk ditambahkan ^atau %.

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)

Presedensi operasi dibiarkan dari kanan ke kanan.

daniero
sumber
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]
Hoa Long Tam
sumber
1
Mungkin saja lebih mudah menggunakan Python 3
jamylak
5

C - 168 126 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);}
Arnaud Le Blanc
sumber
5

Tcl 8.6, 57 48 karakter.

  • Masukan dari argumen:

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

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

Anda harus menggunakan shell interaktif untuk kedua solusi.

Saya memperlakukan masukan sebagai daftar (Tcl menggunakan spasi sebagai pembatas) mengambil elemen pertama dan menetapkan ke a, maka saya berjalan sisanya, mengambil 2 elemen setiap kali, operator dan nomor kedua, menerapkan operator pada $adan $bdan menetapkan hasil ke a. Pada akhirnya hasilnya adalah a.

Johannes Kuhn
sumber
Ideone mendukung setidaknya stdin.
Johannes Kuhn
Akhirnya, saya mengalahkan Ruby. Sayangnya Idone tidak mendukung Tcl 8.6, tapi saya tidak perlu hasil dari lmapitu foreachadalah pengganti yang baik.
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

Jawaban yang agak mudah, menggunakan pencocokan pola dan pernyataan kasus sederhana untuk pengangkatan berat. Pemakaian:

> ./calc <<< "123 - 12 + -12 / 12.124 * 9.99 - 1"
80.57456285054437
Untuk S
sumber
1
Alih-alih ((case m of{..})(read u)(read b))Anda dapat menulis ((case m of{..}$read u)$read b), 2 karakter lebih sedikit.
desir
4

C: 111 108 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);}

Itu memenuhi semua persyaratan, penggunaan:

> ./calc <<< "-43 - 56 + 14.123 / -13.22"
6.420348
Untuk S
sumber
1
~scanfdapat menggantikan +1. Juga, c^45-> c%5dan c^42-> c%2harus berfungsi.
ugoren
@ MDXF tidak di mesin saya, melewati setiap test case di sini. Saya mengkompilasi dengan Dentang pada Intel Macbook yang cukup modern, dan bekerja dengan sangat baik (saya mengujinya lagi sekarang, saya menyalin kode dari sini dan hanya mengkompilasinya tanpa bendera). Kompiler, arsitektur prosesor, dan OS apa yang Anda gunakan?
Fors
@ Untuk Aku percaya aku punya beberapa bendera aneh yang mendorong perilaku aneh; kesalahan saya, ini bekerja untuk saya sekarang. Maaf mengganggu Anda.
MD XF
3

C ++ 0x 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;}

Diformat dengan baik:

#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;
}
Martin York
sumber
3

Perl (97)

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

baca dari argumen

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

baca dari input

@_=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
Ming-Tang
sumber
3

PostScript (145)

Entri PostScript lain (terima kasih kepada luser droog untuk menggali golf yang menarik untuk PostScript!):

[/+{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
=

Tidak golf:

[/+{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
=
Thomas W.
sumber
Anda terus memukuli saya! +1 Ini sangat menarik.
luser droog
Jika Anda bisa mengalahkan teka-teki silang saya , saya akan memberi Anda hadiah! NB Anda hanya dapat mengedit 10 kali sebelum posting menjadi CW dan suara tidak memberi Anda poin rep.
luser droog
Aku terus memukulmu karena aku hanya memilih yang bisa kukalahkan ;-). Saya tidak yakin apakah saya bisa menggunakan kisi teka-teki silang. Saya mungkin akan mencoba, tetapi hanya dalam beberapa minggu.
Thomas W.
1
Wiki Komunitas. Ini berarti pos telah diedit berkali-kali sekarang menjadi milik komunitas. Setiap pengguna dapat mengeditnya (melewati persetujuan moderator yang diperlukan untuk pengeditan yang disarankan ), dan tidak ada lagi poin. Jadi, apa pun yang Anda lakukan, berhentilah pada Rev 9. Saya hampir gagal di tab gitar.
luser droog
1
Abaikan semua keluhan CW itu. Mereka memperbaikinya!
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())

Versi yang dapat dibaca:

# 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())

Mengambil ekspresi sebagai argumen baris perintah, output pada output standar.

pegolf9338
sumber
2

Catatan tambahan (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

Dan sedikit lebih mudah dibaca:

%!
/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
luser droog
sumber
2

JavaScript (208 karakter dipadatkan)

Untuk lebih jelasnya, ini adalah kode sebelum saya memadatkannya ( 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)

Ini dia dipadatkan menjadi 208 karakter ( 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)

Karena saya mengakhiri garis dengan titik koma, semua spasi putih yang dapat dilepas diabaikan untuk penghitungan karakter, tetapi ditinggalkan untuk kejelasan.

IQAndreas
sumber
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

Hasilnya akan dibungkus dalam Maybemonad

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

Juga memerlukan impor <*>dari Control.Applicative, tetapi impor dapat dilakukan di luar kode, jadi saya harap itu diizinkan.

desir
sumber
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);
    }
}
Sklivvz
sumber
Saya mendapatkan '0' untuk '1 +1'. IDEONE
Rob
@Mike Input sebagai argumen, bukan stdin.
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))
Yair Rand
sumber
1

Java 11, 151 (sebagai fungsi lambda)

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;}

Fungsi Lambda mengambil input String dan menghasilkan float.

Cobalah online.

Java 11, 241 byte (sebagai program lengkap dengan tanya I / O)

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);}}

Program lengkap mengambil String-line melalui STDIN dan mengeluarkan ke STDOUT.

Cobalah online.

Penjelasan:

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
Kevin Cruijssen
sumber
1

05AB1E , 30 byte

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

Cobalah secara online atau verifikasi semua kasus uji .

Penjelasan:

#           # 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)

Jika evalbuiltin diizinkan, ini bisa menjadi pendekatan alternatif ( 16 byte ):

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

Cobalah secara online atau verifikasi semua kasus uji .

Penjelasan:

#ć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

Ini akan berubah "-2 + 6 / 2 * 8 - 1 / 2.5 - 18"menjadi "((((((-2)+6)/2)*8)-1)/2.5)-18"sebelum menggunakan evalbuiltin (menggunakan .Esecara langsung akan memberikan operator diutamakan */lebih +-, maka konversi dengan tanda kurung terlebih dahulu).

Kevin Cruijssen
sumber