Memecahkan ekspresi matematika dari sisi yang berganti-ganti

9

Buat program yang memecahkan ekspresi matematika menggunakan elemen-elemen dari sisi bergantian ekspresi. Cara melakukannya adalah, alih-alih membaca dari kiri ke kanan, Anda membaca karakter pertama, lalu yang terakhir, lalu yang kedua, lalu yang kedua ke yang terakhir dll. Ini akan memberi Anda ekspresi baru yang harus Anda evaluasi dan hasilkan.

a*b/c+d-e
135798642  <-- Order you read the expression in
ae*-bd/+c  <-- Order of operation. 

Contoh:

1*3/2+4-5
15*-34/+2 = -255

Jika ungkapan itu tidak berfungsi, a 1harus dimasukkan ke posisi yang diperlukan untuk membuatnya berfungsi.

Beberapa contoh mungkin akan menggambarkannya dengan lebih baik:

Input: 1+1+1+1+1
Result: 23     // Because 1+1+1+1+1 -> 11++11++1 -> 23

Input: 1+2-3+12-5
Result: -19    // Because 1+2-3+12-5 -> 15+-22-13+ -> 15+-22-13+1 -> -19
               //                                 |
               //                                 Not valid expression

Input: 2*2*2*2*2
Result: 968    // Because 2*2*2*2*2 -> 22**22**2 -> 22*1*22*1*2 -> 968
               //                        ||  ||
               //                        Not valid, 1 must be inserted

Input: 17/2
Output: 127    // Because 17/2 = 127/ -> 127/1 -> 127

Operator yang harus didukung adalah + - * /. Tidak akan ada tanda kurung. Aturan matematika normal dan "sintaks" digunakan, jadi misalnya **tidak berarti eksponensial. a++++1setara dengan a+1(yaitu gaya MATLAB, bukan C ++).

Jika ada keraguan, beberapa operasi yang valid adalah:

-a
+a
a++b
a+-b
a*-b
a*+b
a*++b
a/b
a/-b
a/+b
-a/--b

Sementara semua hal berikut ini tidak valid. Ini menunjukkan apa yang harus diganti dengan:

a+      | a+1
a-      | a-1
a++++   | a++++1   (This is equivalent to a+1)
a*+++   | a*+++1   (This is equivalent to a*1)
a**b    | a*1*b
a*/b    | a*1/b
a/*b    | a/1*b
a*      | a*1
*a      | 1*a
***a    | 1*1*1*a

Aturan:

  • Kode dapat berupa fungsi atau program lengkap
  • Input dapat berupa STDIN atau argumen fungsi
  • Input harus berupa ekspresi matematika yang valid, tanpa tanda kutip, ''atau"" .
  • Keluaran harus menjadi jawaban untuk ekspresi baru, sebagai bilangan bulat, desimal atau fraksi yang disederhanakan.
  • Setidaknya tiga digit setelah titik desimal harus didukung. Jadi 1/3 = 0.333tidak 0.33. 0.333333333diterima.
  • ans = ... diterima.
  • Jalur dan spasi baru dan terdepan diterima.
  • Input hanya berupa bilangan bulat
  • Pembagian dengan nol dapat menghasilkan kesalahan, NaN, Inf, dll. Mengeluarkan angka tidak diterima.

Seperti biasa, kode terpendek dalam byte menang. Pemenang akan dipilih satu minggu dari hari tantangan diposting. Jawaban yang diposkan nanti mungkin masih menang jika lebih pendek dari pemimpin saat ini.

Stewie Griffin
sumber
apakah ada panjang maksimal pada string input atau jumlah input operator / integer? juga, apakah saya harus mendukung matematika hingga 2^64, dan haruskah itu kesalahan atau membungkus jika Anda pergi?
kucing
"output harus menjadi jawaban [...] fraksi yang disederhanakan ..." jadi bisakah saya kembali 0/0jika ekspresi bernilai untuk pembagian integer atau modulo dengan nol?
kucing
2
Jika jawabannya memberikan pembagian dengan nol, maka itu x/0adalah output yang valid. Selama tidak menghasilkan jawaban yang salah tidak apa-apa. Kesalahan dan "Bukan angka" menurut definisi benar, dan tak terhingga "cukup benar",
Stewie Griffin
Hanya untuk memastikan - eval dapat digunakan, bukan?
orlp
Ya, eval tidak apa-apa.
Stewie Griffin

Jawaban:

3

Perl, 108 100 byte

$_="";while(@F){$_.=shift@F;$_.=pop@F}s@(\*|/)\1+@\1@g;s@^[*/]@1$&@;s@\D$@$&1@;s@\D@$&@g;$_=eval

Kode 96 byte, ditambah 4 untuk argumen baris perintah -pF//, di mana

  • -psisipan while (<>) { .. } continue { print }dan
  • -F//memisahkan input dan memasukkannya ke dalam @F.

Perhatikan bahwa input seharusnya tidak memiliki baris baru, jadi gunakan /bin/echo -n 'formula' | perl ...

Kurang golf:

$_='';              # reset $_
while(@F) {         # reorder input
   $_.=shift @F;    # take first element off of @_
   $_.=pop @F       # idem for last; if @F is empty, undef is appended
}

s@(\*|/)\1+@\1@g;   # replace 2 or more '*' or '/' with just one: *1 and /1 = nop
s@^[*/]@1$&@;       # if expression starts with * or / prepend a 1
s@\D$@$&1@;         # if expression doesn't end with a number, append 1
s@\D@$& @g;         # eval doesn't like '++1': add spaces after operators
$_ = eval           # set $_ to 3v1l, so the `-p` will print the new value

Pengujian

Masukkan yang di atas dalam file yang disebut 114.pl, dan script tes di bawah ini dalam file di sebelahnya:

%test = (
    '1+1+1+1+1' =>   23,
    '1*3/2+4-5' => -255,
    '1+2-3+12-5'=>  -19,
    '2*2*2*2*2' =>  968,
    '17/2'      =>  127,
    '--/-1-2-'  =>   -2,
    '**2*'      =>    2,
    '++1++'     =>    1,
    '/2/'       =>  0.5,
    '10/'       =>   '',
);

printf "%-20s -> %5s: %5s\n", $_, $test{$_}, `/bin/echo -n '$_' | perl -pF// 114.pl`
for keys %test;

Menjalankannya menghasilkan:

++1++                ->     1:     1
**2*                 ->     2:     2
17/2                 ->   127:   127
10/                  ->      :
1+1+1+1+1            ->    23:    23
1*3/2+4-5            ->  -255:  -255
2*2*2*2*2            ->   968:   968
1+2-3+12-5           ->   -19:   -19
--/-1-2-             ->    -2:    -2
/2/                  ->   0.5:   0.5

Catatan yang 1/0menyebabkan pembagian dengan kesalahan nol: evaloutput undef, yang diwakili oleh string kosong.

Kenney
sumber
Beberapa kasus uji lagi! Saya akan menggunakannya
edc65
3

JavaScript ES6, 105 106

Sunting Disimpan 1 byte thx @ Kenney

t=>eval("for(t=[...t],p=o='';c=t.reverse().pop();p=c)o+=p<'0'?(c=='/'|c<'+'||' ')+c:c;eval(p<'0'?o+1:o)")

// Less golfed
t=>{
  for(t = [...t], p = o = '';
      c = t.reverse().pop();
      p = c)
    o += p<'0' 
     ? (c=='/' | c=='*' || ' ')+c  // '1' or ' '
     : c;
  return eval(p<'0' ? o+1 : o)
}

Cuplikan tes

f=t=>eval("for(t=[...t],p=o='';c=t.reverse().pop();p=c)o+=p<'0'?(c=='/'|c<'+'||' ')+c:c;eval(p<'0'?o+1:o)")

console.log=x=>O.innerHTML+=x+'\n'

function test() { console.log(I.value + ' -> '+f(I.value)) }

;['1+1+1+1+1', '1*3/2+4-5', '1+2-3+12-5', '2*2*2*2*2',
  '17/2', '--/-1-2-', '**2*', '++1++', '/2/', '10/' ]
.forEach(t=>console.log(t+' -> '+f(t)))
Your test <input id=I><button onclick="test()">-></button>
<pre id=O></pre>

edc65
sumber
Disimpan Anda byte: p < '0' ? ( c=='/' | c<'+' || ' ' )+c : c ;.
Kenney