Erreurs d'arrondi hors de contrôle

14

Contexte

Vous avez récemment été embauché par un petit cabinet comptable. Le monde de la comptabilité vous est quelque peu étranger, vous ne savez donc pas si vous suivez toutes les directives professionnelles. En particulier, vous ne savez pas quand vous devez arrondir tous ces chiffres et dans quelle direction, donc la plupart du temps, vous vous contentez de l'ailer et d'espérer le meilleur.

Contribution

Votre entrée est une chaîne unique qui représente un calcul simple. Il contient un certain nombre d'entiers non négatifs délimités par les caractères +-*/. La chaîne se lit de gauche à droite et les règles de priorité normales sont ignorées, ce qui "23+1*3/4"signifie "commencez par 23, ajoutez 1, multipliez par 3 et divisez par 4", le résultat étant 18. L'entrée ne contiendra pas de nombres commençant par 0(sauf 0lui-même), ni une division par zéro.

Production

À chaque étape du calcul, vous pouvez soit arrondir le résultat vers le haut ou vers le bas à l'entier le plus proche, soit le conserver tel quel. Enfin, vous arrondissez vers le haut ou vers le bas pour obtenir un résultat entier. Votre sortie est la liste des entiers pouvant résulter d'un tel calcul, triés et sans doublons.

Règles

Vous pouvez écrire soit un programme complet soit une fonction. Le nombre d'octets le plus bas gagne et les failles standard sont interdites.

Cas de test

"42" -> [42]
"2+0+4-0" -> [6]
"23+1*3/4" -> [18]
"5/2" -> [2,3]
"5/2+7/3*6-1" -> [17,18,19,23]
"23/2/2*30-170/3" -> [-7,-6,-2,-1,0,1,3,4]
"1/3*2*2*2*2*2*2" -> [0,16,20,21,22,24,32,64]
"1/3*9" -> [0,3,9]
Zgarb
la source
Le programme doit-il fonctionner pour toutes les entrées possibles (quelle que soit la taille du nombre), une entrée de taille limitée ou uniquement les cas de test?
orlp
@orlp Cela devrait fonctionner au moins lorsque tous les nombres d'entrée et les résultats intermédiaires sont inférieurs, par exemple, à 10 millions en valeur absolue. Le cabinet comptable est petit, après tout.
Zgarb
Prenez note du cas de test 1/3*9, qui peut échouer si vous utilisez des nombres à virgule flottante.
Claudiu
@Claudiu Merci, je l'ai ajouté au défi.
Zgarb

Réponses:

4

J, 84 octets

À partir d'une liste à 1 élément, la fonction conserve tous les nombres intermédiaires possibles dans la liste en évaluant l'expression suivante et en ajoutant ses copies arrondies de haut en bas.

Va jouer au golf plus loin et ajouter des explications demain. Impossible de trouver des façons évidentes de jouer au golf plus.

f=.3 :'/:~~.<.>((,>.,<.)@".@(":@],''x'',;@[))&.>/|.(>@{.;_2<\}.);:y rplc''/'';''%'''

Réussit tous les tests.

Usage:

   f '1/3*2*2*2*2*2*2'
0 16 20 21 22 24 32 64
   f '1/3*9'
0 3 9

Essayez-le ici.

randomra
la source
Comment les traitez-vous en tant que rationnels au lieu de flottants - est-ce intégré à J? (Terminez J noob ici)
Claudiu
@Claudiu À chaque évaluation, je force les nombres à précision étendue (dans ce cas, les justifications) en ajoutant la lettre xà la fin de la liste.
randomra
3

Python 2, 220 caractères

import re,sys,math as m,fractions as f
X=f.Fraction
M=map
F=['+']+re.split("(\D)",sys.argv[1])
r=[X(0)]
while F:U=[eval('f.'+`n`+F[0]+F[1])for n in r];r=M(X,U+M(m.floor,U)+M(m.ceil,U));F=F[2:]
print sorted(set(M(int,r)))

Il conserve une liste de tous les numéros possibles et, à chaque étape, génère trois numéros pour chaque numéro de la liste, même s'il y a des doublons. La complexité d'exécution est donc exponentielle. Cependant, cela fonctionne instantanément pour ces petits exemples. Les doublons sont retirés à la fin.

Il utilise fractions.Fractionpour faire une division exacte, en évitant les inexactitudes en virgule flottante.

Ajoutez 5 caractères ( r=map(X,g)-> r=set(map(X,g))) pour augmenter considérablement les performances.

Claudiu
la source
Voici un golf facile pour commencer: \Dest une classe de caractères prédéfinie pour faire correspondre les non-chiffres
Sp3000
@orlp: corrigé maintenant! (Je pense ..)
Claudiu
@Claudiu: cela devrait être soit r"(\D)"ou "(\\D)". De plus, si vous utilisez Python 3, vous pouvez remplacer l'indexation dans Favec une affectation étoilée, par exemple:, A,B,*F=Futilisez Aet Bau lieu de F[0]et F[1], et supprimez-les F=F[2:].
Mac du
@Mac: "\D"finit quand même par fonctionner et c'est plus court. Ce n'est pas une séquence d'échappement valide, donc Python inclut juste le \ et Dtextuellement. Bon conseil Python3 en fait, je vais le vérifier, bien que je doive remplacer les backticks par repr()et transformer le maprésultat en liste. Je souhaite que Python 2 ait une affectation préférée.
Claudiu
2

Python, 421 370 354 octets

Désolé, veuillez me supporter. Je suis vraiment nouveau sur python (je cherchais juste un langage qui supporte la fractiosn) et j'ai utilisé toutes les quelques astuces que je connaissais pour raccourcir le code mais c'est toujours un monstre étant donné qu'il existe une solution python de presque la moitié de la taille. J'ai beaucoup appris et j'ai pensé le soumettre quand même =)

Nouvelle version grâce à @ kirbyfan64sos et @Zgarb

from fractions import*
from math import*
import re,operator as z
s=input()
N=re.split(r'[\*\/\-\+]',s)
O=re.split(r'[0-9]+',s)[1:-1]
d={'+':z.add,'-':z.sub,'*':z.mul,'/':z.truediv}
l=[int(N[0])]#list of inters up to now
for i in range(len(O)): #iterate over all operations
    n=set()
    for f in l:
        f=d[O[i]](f,Fraction(int(N[i+1])))
        n.update([floor(f),ceil(f),f])
    l=n
print(set(map(floor,n)))

Ancienne version

from fractions import Fraction as F
from math import floor,ceil
import re
s=input()
N=re.split(r'[\*\/\-\+]',s)   #Numbers
O=re.split(r'[0-9]+',s)[1:-1] #Operators
l=[int(N[0])]
for i in range(len(O)): #Iterate over all operators
    n=set()
    for f in l:           #Iterate over all possible numbers
        g=F(int(N[i+1]))
        o=O[i]
        if o=='/':
            f/=g
        elif o=='*':
            f*=g
        elif o=='-':
            f-=g
        else:
            f+=g
        n.add(floor(f))  #Add all possible numbers to a new set 
        n.add(ceil(f))   # the 'set' structure prevents from having multiple copies
        n.add(f)         # which is a really nice feature
    l=n                #repeat
print(set([floor(k) for k in n])) #also remove the unrounded ones
flawr
la source
D'une part, vous pouvez remplacer certains des retraits d'espace par des tabulations (cela craint généralement, mais fonctionne bien dans le code golf: un tab == 1 caractère). Vous pouvez également utiliser un dict au lieu de plusieurs ifs ( d={'+': operator.add, '-': operator.sub, ...}; d[op](a, b)). En outre, [floor(k) for k in n]peut être raccourci map(floor, n)et les n.addappels peuvent devenir n.extend([floor(f), ceil(f), f]).
kirbyfan64sos
Wow merci beaucoup, je vais essayer de les implémenter! J'ai déjà compté les tirets comme des tabulations mais j'ai dû les convertir en espaces ici.
flawr
Vous pouvez également simplement utiliser des espaces simples; ils devraient travailler.
kirbyfan64sos
Pour autant que je sache, vous n'utilisez Fqu'une seule fois, vous pouvez donc le faire from fractions import*et enregistrer quelques octets. Même chose avec math. Supprimez les espaces autour =, ils sont inutiles. En outre, vous devez affecter l'entrée à sau lieu du codage en dur.
Zgarb
@flawr Supprimez tous les espaces facultatifs. De plus, vous devez pouvoir accepter n'importe quelle entrée. Utilisez s=input()plutôt que s = "1/3*9", supprimez vos commentaires, etc.
mbomb007
1

Mathematica, 134

Union@Flatten@{Floor@#,Ceiling@#}&@ToExpression@StringReplace[#,x:("+"|"-"|"*"|"/"~~NumberString):>"//{Floor@#,#,Ceiling@#}"~~x~~"&"]&
alephalpha
la source
0

MATLAB, 283 caractères

function[u]=w(s)
s=[' ' strsplit(regexprep(s,'\D',' $& '))];s=reshape(s,[2,size(s,2)/2]);o=s(1,:);d=cellfun(@str2num,s(2,:));a=d(1);for n=2:size(o,2)switch o{n}case'+';a=a+d(n);case'-'a=a-d(n);case'/'a=a/d(n);case'*'a=a*d(n);end;a=[ceil(a);a;floor(a)];end;u=unique(a(mod(a,1)==0))end

Non golfé:

function [u] = WingitRound(i)
    i=[' ' strsplit(regexprep(i,'\D',' $& '))];
    i=reshape(i,[2,size(i,2)/2]);

    o=i(1,:);
    n=cellfun(@str2num,i(2,:));

    a=n(1);

    for n=2:size(o,2)
        switch o{n}
            case '+'
                a = a + n(n);
            case '-'
                a = a - n(n);
            case '/'
                a = a / n(n);
            case '*'
                a = a * n(n);
        end
        a = [ceil(a);a;floor(a)];
    end

    u=unique(a(mod(a,1)==0)));
end

En écrivant ceci, j'ai réalisé qu'il y avait une manière encore plus courte de le faire, que j'ajouterai une fois que j'aurai fini de l'écrire.

AJMansfield
la source
0

VBA, 347 octets

Function OoCRE(inp As String)
ct = 0
i = 1
Do While i < Len(inp)
c = Mid(inp, i, 1)
If Not IsNumeric(c) Then
ct = ct + 1
If ct = 2 Then
inp = Round(Application.Evaluate(Left(inp, i - 1))) & Right(inp, Len(inp) - (i - 1))
i = InStr(1, inp, c)
ct = 1
End If
End If
OoCRE = Round(Application.Evaluate(inp))
i = i + 1
Loop
End Function
Alex
la source
1
Il y a beaucoup de golf à faire ici, en supprimant principalement les espaces superflus et en choisissant des noms de var plus courts
cat