Résoudre une expression mathématique à partir de côtés alternés

9

Créez un programme qui résout une expression mathématique en utilisant les éléments des côtés alternés de l'expression. Au lieu de lire de gauche à droite, vous lisez le premier caractère, puis le dernier, puis le deuxième, puis l'avant-dernier, etc. Cela vous donnera une nouvelle expression que vous devez évaluer et produire.

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

Exemple:

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

Si l'expression ne «marche» pas, un 1doit être inséré dans les positions nécessaires pour le faire fonctionner.

Quelques exemples l'illustreront probablement mieux:

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

Les opérateurs qui doivent être pris en charge sont + - * /. Il n'y aura pas de parenthèses. Les règles mathématiques normales et la "syntaxe" sont utilisées, donc par exemple **ne signifie pas l'exponentiation. a++++1est équivalent à a+1(ie style MATLAB, pas C ++).

En cas de doute, certaines opérations valides sont:

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

Bien que tous les éléments suivants ne soient pas valides. Il est montré avec quoi ils devraient être remplacés:

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

Règles:

  • Le code peut être une fonction ou un programme complet
  • L'entrée peut être STDIN ou un argument de fonction
  • L'entrée doit être une expression mathématique valide, sans guillemets, ''ou"" .
  • La sortie doit être la réponse à la nouvelle expression, sous forme d'entier, décimal ou fraction simplifiée.
  • Au moins trois chiffres après la virgule décimale doivent être pris en charge. Alors 1/3 = 0.333non 0.33. 0.333333333est accepté.
  • ans = ... est accepté.
  • Les nouvelles lignes et les espaces de début et de fin sont acceptés.
  • L'entrée ne sera que des entiers
  • La division par zéro peut entraîner une erreur, NaN, Inf etc. La sortie d'un nombre n'est pas acceptée.

Comme toujours, le code le plus court en octets gagne. Un gagnant sera sélectionné une semaine après le jour où le défi a été affiché. Les réponses publiées plus tard peuvent toujours gagner si elles sont plus courtes que le leader actuel.

Stewie Griffin
la source
y a-t-il une longueur maximale sur la chaîne d'entrée ou le nombre d'opérateurs / entiers entrés? aussi, dois-je prendre en charge les mathématiques jusqu'à 2^64, et faut-il une erreur ou un bouclage si vous passez?
chat
"la sortie devrait être la réponse [...] fraction simplifiée ..." alors puis-je simplement retourner 0/0si l'expression est égale à une division entière ou modulo par zéro?
chat
2
Si la réponse donne une division par zéro, alors x/0c'est une sortie valide. Tant qu'il ne génère pas de réponse incorrecte, c'est OK. L'erreur et "Pas un nombre" est par définition correcte, et l'infini est "assez correct",
Stewie Griffin
Juste pour être sûr - eval peut être utilisé, non?
orlp
Oui, eval est ok.
Stewie Griffin

Réponses:

3

Perl, 108100 octets

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

Le code est de 96 octets, plus 4 pour l'argument de ligne de commande -pF//, où

  • -pinserts while (<>) { .. } continue { print }et
  • -F//divise l'entrée et la met @F.

Notez que l'entrée ne doit pas avoir de retour à la ligne, utilisez donc /bin/echo -n 'formula' | perl ...

Moins 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

Essai

Mettez ce qui précède dans un fichier appelé 114.plet le script de test ci-dessous dans un fichier à côté:

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

Le lancer génère:

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

Notez que cela 1/0provoque une division par zéro d'erreur: les evalsorties undef, qui sont représentées par la chaîne vide.

Kenney
la source
Encore quelques cas de test! Je vais les utiliser
edc65
3

JavaScript ES6, 105 106

Modifier un octet enregistré 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)
}

Extrait de test

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
la source
Vous avez enregistré un octet: p < '0' ? ( c=='/' | c<'+' || ' ' )+c : c ;.
Kenney