Buat kalkulator omnifix

16

Inspirasi. Terbalik.

Mengevaluasi ekspresi omnifix yang diberikan.

Omnifix seperti notasi infiks matematika normal, tetapi dengan salinan tambahan dari setiap simbol yang mengelilingi argumen. Simbol luar menggantikan kurung, dan karenanya tidak perlu kurung tambahan.

Anda harus mendukung penambahan, pengurangan, perkalian, pembagian, dan bilangan real positif (yang negatif dapat ditulis -0-n-) dalam rentang yang masuk akal untuk bahasa Anda.

Plus dan minus harus +dan -, tetapi Anda dapat menggunakan *atau ×untuk kali dan /atau ÷untuk membagi. Simbol wajar lainnya akan diizinkan berdasarkan permintaan.

Brownie menunjukkan penjelasan dan fitur tambahan (seperti operasi tambahan, angka negatif, string, dll.) Bahkan jika jawaban Anda tidak memiliki fitur ini, jangan ragu untuk menunjukkan bagaimana mungkin.

Harap berikan tautan untuk menguji solusi Anda jika memungkinkan.

Contohnya

Untuk kejelasan, penjelasan di bawah ini menggunakan minus tinggi ( ¯) untuk menunjukkan angka negatif. Anda dapat mengembalikan angka negatif menggunakan format apa pun yang masuk akal.

-5-2-3

+2+×3×2×+8 ( +2+×3×2×++2+6+8)

-14--3-1--12 ( -4--3-1---14-2-12)

+2.1+×3.5×2.2×+9.8 ( +2.1+×3.5×2.2×++2.1+7.7+9.8)

×3×÷-0-6-÷2÷×-9 ( ×3×÷-0-6-÷2÷××3×÷¯6÷2÷××3ׯ3ׯ9)

÷4÷-3-÷1÷2÷-÷1.6 ( ÷4÷-3-÷1÷2÷-÷÷4÷-3-0.5-÷÷4÷2.5÷1.6)

Adm
sumber
1
The explanations below use high minus (`¯`) to indicate negative numbers.Anda pasti menyukai APL.
Erik the Outgolfer
@EriktheOutgolfer Anda punya saran yang lebih baik? Juga, TI-BASIC menggunakan minus tinggi.
Adám
Sebenarnya tidak karena -s dapat dikacaukan dengan -s sedangkan ¯s tidak dapat dikacaukan dengan -s.
Erik the Outgolfer
Bah, saya baru memperhatikan persyaratan bilangan real. Begitu banyak untuk solusi Retina aritmatika integer 290-byte saya ...
Neil
@Neil Mengapa Anda tidak mempostingnya sebagai jawaban?
Adám

Jawaban:

4

C # (.NET Core) , 198 197 188 byte

float O(string s){try{return float.Parse(s);}catch{var f=s[0];int i=s.IndexOf(f,1);float a=O(s.Substring(1,i-1)),b=O(s.Substring(i+1,s.Length-i-2));return f<43?a*b:f<44?a+b:f<46?a-b:a/b;}}

Cobalah online!

Penggunaan *dan /.

Fungsi rekursif. Pertama mencoba mengurai string input sebagai a float. Jika gagal, ia menyebut dirinya secara berulang lewat sebagai argumen operan pertama dan kedua dan kemudian melakukan operasi yang dipilih pada hasil.

  • 1 byte disimpan berkat Tn. Xcoder!
  • 9 byte disimpan berkat TheLethalCoder!
Charlie
sumber
IndefOf(f, 1)bisaIndexOf(f,1)
Tn. Xcoder
1
Gunakan floats sebagai gantinya, gunakan kode char, ketika Anda memilikinya mungkin dapat mempersingkat dengan >dan <di beberapa tempat.
TheLethalCoder
Anda dapat golf byte berubah i+1,s.Length-i-2ke ++i,s.Length+~i.
Kevin Cruijssen
4

Python 3, 159 158 152 144 136 135 132 byte

def t(i,a=1):
 while'-'<l[i]!='/':i+=1;a=0
 if a:l[i]='(';i=t(t(i+1));l[i-1]=')'
 return-~i
*l,=input()
t(0)
print(eval(''.join(l)))

Cobalah online!

Tidak mengizinkan angka negatif (meskipun -0-5-berfungsi tentu saja) dan memerlukan operator python.

Arfie
sumber
Bisakah Anda menambahkan tautan TIO?
Adám
1
while~-(l[i]in'+-*/'):i+=1;a=1dan *l,=input()untuk 152 byte
Felipe Nardi Batista
1
dengan semua kotak uji: tautan
Felipe Nardi Batista
1
144 byte
Felipe Nardi Batista
1
if a:l[i]='(';i=t(t(i+1));l[i-1]=')'dengan return-~iuntuk 135 byte: P
Felipe Nardi Batista
3

Retina , 290 287 286 byte

\d+
¦$&$*
¯¦
¯
{`\+([¯¦]1*)\+([¯¦]1*)\+
-$1-¯$2-
-(¯|¦)(1*)-([¯¦]+1*\2)-
-¯$3-¯$1$2-
(×|÷)¯(1*\1)([¯¦]1*\1)
$1¦$2¯$3
צ×[¯¦]1*×|¯¯¦?
¦
¯¦|¦¯
¯
+`-((¯|¦)1*)(1*)-\2\3-
$1
-([¯¦]1*)-[¯¦](1*)-
$1$2
צ1(1*)×([¯¦]1*)×
+צ$1×$2×+$2+
}`÷¦(?=1*÷(¯|¦)(1+)÷)(\2)*1*÷\1\2÷
$1$#3$*
((¯)|¦)(1*)
$2$.3

Cobalah online! Catatan: Hanya mampu integer aritmatika, sehingga beberapa kasus uji telah dihapus. Menerima dan mengembalikan angka negatif menggunakan ¯awalan. Sunting: Disimpan 3 4 byte berkat @Cowsquack. Penjelasan:

\d+
¦$&$*

Saya membutuhkan beberapa cara untuk menangani nol, jadi saya menggunakan ¦awalan angka positif. Angka-angka tersebut kemudian dikonversi ke unary.

¯¦
¯

Tetapi angka negatif hanya perlu ¯awalan.

{`\+([¯¦]1*)\+([¯¦]1*)\+
-$1-¯$2-

Mengutip +menjadi jelek, jadi saya mengubah penambahan menjadi pengurangan.

-(¯|¦)(1*)-([¯¦]+1*\2)-
-¯$3-¯$1$2-

Jika nilai absolut dari LHS dari pengurangan kurang dari RHS, alihkan mereka dan meniadakan kedua sisi.

(×|÷)¯(1*\1)([¯¦]1*\1)
$1¦$2¯$3

Juga jika LHS dari perkalian atau pembagian adalah negatif, meniadakan kedua belah pihak.

צ×[¯¦]1*×|¯¯¦?
¦

Juga jika LHS dari perkalian adalah nol, maka hasilnya adalah nol. Juga, dua minus menghasilkan nilai tambah.

¯¦|¦¯
¯

Tapi minus dan plus (atau sebaliknya) menghasilkan minus.

+`-((¯|¦)1*)(1*)-\2\3-
$1

Kurangi dua angka dari tanda yang sama. Lakukan ini berulang kali hingga tidak ada pengurangan yang tersisa.

-([¯¦]1*)-[¯¦](1*)-
$1$2

Jika masih ada pengurangan, tanda-tandanya harus berbeda, jadi tambahkan jumlahnya. (Tetapi hanya lakukan ini sekali saja, karena ini dapat mengungkapkan pengurangan dua angka dari tanda yang sama lagi.)

צ1(1*)×([¯¦]1*)×
+צ$1×$2×+$2+

Lakukan penggandaan dengan penambahan berulang.

}`÷¦(?=1*÷(¯|¦)(1+)÷)(\2)*1*÷\1\2÷
$1$#3$*

Lakukan pembagian integer. Salah satu langkah di atas akan menyederhanakan ekspresi, jadi putar kembali hingga tidak ada operasi yang tersisa.

((¯)|¦)(1*)
$2$.3

Konversi kembali ke desimal.

Neil
sumber
Wow, itu - epik. Posting Retina terbesar di PPCG? Namun, biasanya solusi QuadR dan Retina sangat mirip satu sama lain. Bisakah saya menginspirasi?
Adám
Di baris ini +`-(([¯¦])1*)(1*)-\2\3-, [¯¦]bisa menjadi¯|¦
Kritixi Lithos
@Cowsquack Terjadi tiga kali, terima kasih!
Neil
Ada satu yang Anda lewatkan ([×÷]);)
Kritixi Lithos
1
@Cowsquack Anda sebaiknya tidak menemukan yang lain, kalau tidak saya harus mencoret 4 ...
Neil
2

PHP , 116 114 109 byte

Terima kasih kepada Martin Ender

for($s=$argv[$o=1];$o!=$s;)$s=preg_replace('#([*+/-])(([\d.]+|(?R))\1(?3))\1#','($2)',$o=$s);eval("echo$s;");

Penggunaan *untuk perkalian dan/ untuk pembagian. Angka-angka negatif berhasil meskipun saya tidak berusaha keras untuk itu.

Cobalah online!

Tidak Dijelaskan dan Dijelaskan

for($s=$argv[$o=1];   # Initialize with $s = input and $o = 1;
    $o!=$s;)          # While $o != $s
    # Set $o to $s and set $s to be $s after this regex replacement:
    $s=preg_replace('#([*+/-])(([\d.]+|(?R))\1(?3))\1#','($2)',$o=$s);
    # i.e., continue to do this replacement until the result is the same on two consecutive
    # steps (no replacement was made)
# Once $o == $s (i.e. no more replacement can be made), eval the result and print
eval("echo$s;"); 

Saya juga akan menjelaskan regex karena agak ajaib:

([*+/-])(([\d.]+|(?R))\1(?3))\1


([*+/-])

Pertama, kami ingin mencocokkan salah satu dari empat operator: *+/-

([\d.]+|(?R))

Kemudian, kita harus mencocokkan nomor [\d.]+atau ekspresi omnifix yang valid lainnya (?R).

\1

Kemudian, kami mencocokkan operator yang sama dengan yang ada di awal.

(?3)

Lalu kami melakukan hal yang sama yang kami lakukan di grup 3: cocokkan angka atau ekspresi omnifix.

\1

Akhirnya, cocokkan lagi dengan operator awal.

Apa pun yang cocok ini diganti dengan ($2). Ini mengambil bagian di dalam operator sekitarnya dan memasukkannya ke dalam tanda kurung, sehingga tampak seperti notasi infiks normal.

Kucing Bisnis
sumber
2

QuadR , 33 32 27 byte

-1 terima kasih kepada Sapi Dukun . Terima kasih kepada Erik the Outgolfer .

((.)[\d¯\.]+){2}\2
⍎¯11↓⍵M

dengan argumen / bendera

Cobalah online!

Ini setara dengan solusi Dyalog APL 40-byte:

'((.)[\d¯\.]+){2}\2'R{⍕⍎1↓¯1↓⍵.Match}⍣≡

Cobalah online!

Penjelasan

(teks tanda kurung mengacu pada Dyalog APL, bukan QuadR)

(... ){2}\2 pola berikut dua kali, dan seluruh pertandingan dua kali juga:
  (.) karakter apapun
  [... ]+ diikuti oleh satu atau lebih dari set karakter berikut:
   \dd igits,
   ¯ dikurangi tinggi (tanda negatif)
   \. periode

( ⎕R Adalah R eplaced dengan :)

( {... } hasil dari fungsi anonim berikut ini diterapkan ke namespace ⍵ :)

⍵M ( ⍵.Match) Teks M atch
¯1↓ menjatuhkan karakter terakhir (simbol + - ×atau ÷)
1↓ menjatuhkan karakter pertama (simbol)
 mengeksekusi sebagai kode APL
 (  stringify)

 ( ⍣≡) ulangi penggantiannya sampai tidak ada lagi perubahan yang terjadi

Adm
sumber
Saya pikir Anda dapat menjatuhkan
Kritixi Lithos
@Cowsquack Anda benar tentang QuadR. ⎕Rtidak dapat beroperasi pada data numerik. Terima kasih.
Adám
1

Haskell , 132 karakter

(134 byte, karena ×dan ÷mengambil dua byte di UTF-8)

f y|(n@(_:_),r)<-span(`elem`['.'..'9'])y=(read n,r)
f(c:d)|(l,_:s)<-f d,(m,_:r)<-f s=(o[c]l m,r)
o"+"=(+)
o"-"=(-)
o"×"=(*)
o"÷"=(/)

Cobalah online!

fmem-parsing sebanyak mungkin input dan menghasilkan hasilnya serta string yang tersisa (yang kosong dalam kasus uji). Jika itu tidak sesuai aturan, lucuti string sisa yang tidak dapat dihapus

Haskell , 139 karakter

...
g=fst.f
tidak lagi mengaktifkan counterclockwis
sumber
0

Perl, 64 53 byte

Termasuk +1untuk-p

perl -pe 's%([*-/])(([\d.]+|(?0))\1(?3))\1%($2)%&&redo;$_=eval' <<< "/4/-3-/1/2/-/"

Secara tidak sengaja juga mengimplementasikan ,(membuang argumen pertama) dan kadang-kadang .(menambahkan argumen bersama). .tidak berfungsi dengan sangat andal karena mengganggu titik desimal baik pada level parsing maupun pada level evaluasi

Ton Hospel
sumber
0

Java 8, 205 200 byte

float O(String s){try{return new Float(s);}catch(Exception e){int f=s.charAt(0),i=s.indexOf(f,1);float a=O(s.substring(1,i)),b=O(s.substring(i+1,s.length()-1));return f<43?a*b:f<44?a+b:f<46?a-b:a/b;}}

Port jawaban C # dari @Charlie .
-5 byte terima kasih kepada @ceilingcat .

Cobalah online.

Kevin Cruijssen
sumber