Resolver una expresión matemática desde lados alternos

9

Cree un programa que resuelva una expresión matemática utilizando los elementos de lados alternos de la expresión. La forma en que se hace es que, en lugar de leer de izquierda a derecha, lee el primer carácter, luego el último, luego el segundo, luego el penúltimo, etc. Esto le dará una nueva expresión que debe evaluar y generar.

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

Ejemplo:

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

Si la expresión no «funciona», 1debe insertarse a en las posiciones necesarias para que funcione.

Algunos ejemplos probablemente lo ilustrarán mejor:

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

Los operadores que deben ser compatibles son + - * /. No habrá paréntesis. Se utilizan reglas matemáticas normales y "sintaxis", por lo que, por ejemplo **, no significa exponenciación. a++++1es equivalente a a+1(es decir, estilo MATLAB, no C ++).

En caso de duda, algunas operaciones válidas son:

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

Si bien todo lo siguiente no es válido. Se muestra con qué se deben sustituir:

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

Reglas:

  • El código puede ser una función o un programa completo.
  • La entrada puede ser STDIN o argumento de función
  • La entrada debe ser una expresión matemática válida, sin comillas, ''o"" .
  • La salida debería ser la respuesta a la nueva expresión, como un entero, decimal o una fracción simplificada.
  • Se deben admitir al menos tres dígitos después del punto decimal. Entonces 1/3 = 0.333no 0.33. 0.333333333es aceptado.
  • ans = ... es aceptado.
  • Se aceptan nuevas líneas y espacios iniciales y finales.
  • La entrada solo serán enteros
  • La división por cero puede provocar un error, NaN, Inf, etc. No se acepta emitir un número.

Como siempre, gana el código más corto en bytes. Se seleccionará un ganador una semana a partir del día en que se publicó el desafío. Las respuestas publicadas más tarde aún pueden ganar si es más corto que el líder actual.

Stewie Griffin
fuente
¿hay una longitud máxima en la cadena de entrada o el recuento de operadores / enteros de entrada? Además, ¿tengo que admitir las matemáticas hasta el final 2^64, y si se produce un error, ¿debería pasar?
gato
"la salida debería ser la respuesta [...] fracción simplificada ..." así que ¿puedo regresar 0/0si la expresión evalúa la división entera o el módulo por cero?
gato
2
Si la respuesta da división por cero, entonces x/0es una salida válida. Mientras no muestre una respuesta incorrecta, está bien. Error y "No es un número" es por definición correcto, y el infinito es "lo suficientemente correcto",
Stewie Griffin
Solo para estar seguro: se puede usar eval, ¿verdad?
orlp
Sí, eval está bien.
Stewie Griffin

Respuestas:

3

Perl, 108100 bytes

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

El código es de 96 bytes, más 4 para el argumento de la línea de comandos -pF//, donde

  • -pinsertos while (<>) { .. } continue { print }y
  • -F//divide la entrada y la coloca @F.

Tenga en cuenta que la entrada no debe tener una nueva línea final, así que use /bin/echo -n 'formula' | perl ...

Menos golfizado:

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

Pruebas

Coloque lo anterior en un archivo llamado 114.pl, y el script de prueba a continuación en un archivo al lado:

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

Ejecutarlo produce:

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

Tenga en cuenta que 1/0causa un error de división por cero: las evalsalidas undef, que se representan con la cadena vacía.

Kenney
fuente
¡Unos cuantos casos de prueba más! Los voy a usar
edc65
3

JavaScript ES6, 105 106

Editar guardado 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)
}

Fragmento de prueba

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
fuente
Ha guardado un byte: p < '0' ? ( c=='/' | c<'+' || ' ' )+c : c ;.
Kenney