Rozwiąż wyrażenie matematyczne z naprzemiennych stron

9

Utwórz program, który rozwiązuje wyrażenie matematyczne, używając elementów z naprzemiennych stron wyrażenia. Robi się to tak, że zamiast czytać od lewej do prawej, czytasz pierwszy znak, potem ostatni, potem drugi, potem od drugiego do ostatniego itd. To da ci nowe wyrażenie, które musisz ocenić i wygenerować.

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

Przykład:

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

Jeśli wyrażenie nie «działa», 1należy wstawić a w niezbędne pozycje, aby działało.

Kilka przykładów prawdopodobnie lepiej to zilustruje:

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

Obsługiwani są operatorzy + - * /. Nie będzie nawiasów. Stosowane są normalne reguły matematyczne i „składnia”, więc na przykład **nie oznacza to potęgowania. a++++1jest równoważne a+1(tj. styl MATLAB, a nie C ++).

W razie wątpliwości niektóre prawidłowe operacje to:

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

Chociaż wszystkie poniższe elementy są nieprawidłowe. Pokazano, co należy zastąpić:

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

Zasady:

  • Kod może być funkcją lub pełnym programem
  • Danymi wejściowymi może być STDIN lub argument funkcji
  • Dane wejściowe muszą być prawidłowym wyrażeniem matematycznym bez cudzysłowów ''lub"" .
  • Wynik powinien być odpowiedzią na nowe wyrażenie, jako liczbę całkowitą, dziesiętną lub ułamek uproszczony.
  • Muszą być obsługiwane co najmniej trzy cyfry po przecinku. Więc 1/3 = 0.333nie 0.33. 0.333333333jest akceptowane.
  • ans = ... jest akceptowane.
  • Wiodące i końcowe znaki nowej linii i spacje są akceptowane.
  • Dane wejściowe będą tylko liczbami całkowitymi
  • Dzielenie przez zero może skutkować błędem, NaN, Inf itp. Podanie liczby nie jest akceptowane.

Jak zawsze wygrywa najkrótszy kod w bajtach. Zwycięzca zostanie wybrany tydzień po opublikowaniu wyzwania. Odpowiedzi zamieszczone później mogą nadal wygrywać, jeśli są krótsze niż aktualny lider.

Stewie Griffin
źródło
czy istnieje maksymalna długość ciągu wejściowego lub liczba wejściowych operatorów / liczb całkowitych? ponadto, czy muszę wspierać matematykę 2^64, czy powinienem ją zawinąć lub zawinąć, jeśli przejdziesz?
kot
„wyjście powinno być odpowiedzią [ ... ] uproszczoną frakcją ...” więc czy mogę po prostu wrócić, 0/0jeśli wyrażenie zmienia się na dzielenie całkowite lub modulo przez zero?
kot
2
Jeśli odpowiedź daje podział przez zero, to x/0jest to poprawny wynik. Dopóki nie wyświetli niepoprawnej odpowiedzi, jest OK. Błąd i „Brak liczby” jest z definicji poprawny, a nieskończoność jest „wystarczająco poprawna”,
Stewie Griffin
Dla pewności - eval można zastosować, prawda?
lub
Tak, eval jest w porządku.
Stewie Griffin,

Odpowiedzi:

3

Perl, 108 100 bajtów

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

Kod ma 96 bajtów plus 4 dla argumentu wiersza poleceń -pF//, gdzie

  • -pwkładki while (<>) { .. } continue { print }i
  • -F//dzieli wejście i wstawia je @F.

Zauważ, że wejście nie powinno mieć końcowego nowego wiersza, więc użyj /bin/echo -n 'formula' | perl ...

Mniej golfa:

$_='';              # 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

Testowanie

Umieść powyższe w pliku o nazwie 114.pl, a poniższy skrypt testowy w pliku obok:

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

Uruchomienie go powoduje:

++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

Zauważ, że 1/0powoduje błąd dzielenia przez zero: evalwyjścia undef, które są reprezentowane przez pusty ciąg.

Kenney
źródło
Jeszcze kilka przypadków testowych!
Użyję
3

JavaScript ES6, 105 106

Edytuj Zapisany 1 bajt 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)
}

Testowy fragment kodu

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
źródło
Zapisane ci bajt: p < '0' ? ( c=='/' | c<'+' || ' ' )+c : c ;.
Kenney,