Rundungsfehler außerhalb der Kontrolle


14

Hintergrund

Sie wurden kürzlich von einer kleinen Wirtschaftsprüfungsgesellschaft eingestellt. Die Welt des Rechnungswesens ist für Sie etwas fremd. Sie sind sich also nicht sicher, ob Sie alle professionellen Richtlinien einhalten. Insbesondere wissen Sie nicht, wann Sie all diese Zahlen runden sollten und in welche Richtung. In den meisten Fällen drehen Sie also einfach los und hoffen auf das Beste.

Eingang

Ihre Eingabe ist eine einzelne Zeichenfolge, die eine einfache Berechnung darstellt. Es enthält eine Anzahl nichtnegativer Ganzzahlen, die durch die Zeichen begrenzt werden +-*/. Die Zeichenfolge liest von links nach rechts und die normalen Prioritätsregeln werden ignoriert. Das "23+1*3/4"bedeutet also "Beginnen Sie mit 23, addieren Sie 1, multiplizieren Sie mit 3 und dividieren Sie mit 4". Das Ergebnis ist 18. Die Eingabe enthält keine Zahlen, die mit beginnen 0(außer sich 0selbst), noch eine Division durch Null.

Ausgabe

In jeder Stufe der Berechnung können Sie das Ergebnis entweder auf die nächste Ganzzahl auf- oder abrunden oder es so lassen, wie es ist. Zuletzt runden Sie entweder auf oder ab, um ein ganzzahliges Ergebnis zu erhalten. Ihre Ausgabe ist die Liste der Ganzzahlen, die sich aus einer solchen Berechnung ergeben können, sortiert und ohne Duplikate.

Regeln

Sie können entweder ein vollständiges Programm oder eine Funktion schreiben. Die niedrigste Byteanzahl gewinnt, und Standardlücken sind nicht zulässig.

Testfälle

"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]

Muss das Programm für alle möglichen Eingaben (unabhängig von der Anzahl der Größen), für eine Eingabe mit begrenzter Größe oder nur für die Testfälle funktionieren ?
Orlp

@orlp Es sollte zumindest funktionieren, wenn alle eingegebenen Zahlen und Zwischenergebnisse unter dem absoluten Wert von 10 Millionen liegen. Die Wirtschaftsprüfungsgesellschaft ist schließlich klein.
Zgarb

Beachten Sie den Testfall 1/3*9, der fehlschlagen kann, wenn Sie Gleitkommazahlen verwenden.
Claudiu

@Claudiu Danke, ich habe es der Herausforderung hinzugefügt.
Zgarb

Antworten:


4

J 84 Bytes

Ausgehend von einer Liste mit 1 Elementen behält die Funktion alle möglichen Zwischennummern in der Liste bei, indem sie den nächsten Ausdruck auswertet und die auf- und abgerundeten Kopien hinzufügt.

Werde weiter Golf spielen und morgen eine Erklärung hinzufügen. Es gibt keine offensichtlichen Möglichkeiten, mehr Golf zu spielen.

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

Besteht alle Tests.

Verwendung:

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

Probieren Sie es hier aus.


Wie geht man mit ihnen als Rationalspiel statt als Floats um - ist das in J eingebaut? (Beende J noob hier)
Claudiu

@Claudiu Bei jeder Auswertung erzwinge ich erweiterte Präzisionszahlen (in diesem Fall Rational), indem ich den Buchstaben xam Ende der Liste anhänge .
Randomra

3

Python 2, 220 Zeichen

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

Es führt eine Liste aller möglichen Nummern und generiert bei jedem Schritt drei Nummern für jede Nummer in der Liste, auch wenn es Duplikate gibt. Somit ist die Laufzeitkomplexität exponentiell. Bei diesen kleinen Beispielen funktioniert es jedoch sofort. Dupes werden am Ende entfernt.

Es wird verwendet fractions.Fraction, um eine exakte Division durchzuführen, wobei Gleitkommaungenauigkeiten vermieden werden.

Fügen Sie 5 Zeichen ( r=map(X,g)-> r=set(map(X,g))) hinzu, um die Leistung erheblich zu steigern.


Hier ist ein einfacher Einstieg in das Golfspiel: \D
Dies

@orlp: Jetzt behoben! (Ich denke ..)
Claudiu

@Claudiu: das sollte entweder sein r"(\D)"oder "(\\D)". Auch, wenn Sie Python 3 verwenden, können Sie die Indizierung in ersetzen Fmit Sterne - Zuordnung, zum Beispiel: A,B,*F=F, Verwendung Aund Bstatt F[0]und F[1], und loszuwerden F=F[2:].
Mac,

@Mac: "\D"funktioniert trotzdem und es ist kürzer. Es ist keine gültige Escape-Sequenz, daher enthält Python nur \ und Dwörtlich. Tatsächlich ein guter Python3-Tipp, ich werde es überprüfen, obwohl ich Backticks durch ersetzen repr()und das mapErgebnis in eine Liste umwandeln muss . Markierte Zuordnung ist etwas, was ich Python 2
gewünscht

2

Python, 421 370 354 Bytes

Entschuldigung, bitte tragen Sie mit mir. Ich bin wirklich neu in Python (ich habe nur nach einer Sprache gesucht, die Fraktiosn unterstützt) und habe all die wenigen Tricks angewendet, die ich zum Kürzen des Codes kannte, aber es ist immer noch ein Monster, wenn man bedenkt, dass es eine Python-Lösung von fast der Hälfte der Größe gibt. Ich habe viel gelernt und dachte, ich würde es trotzdem einreichen =)

Neue Version dank @ kirbyfan64sos und @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)))

Alte 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

Zum einen könnten Sie einige der Leerzeichen durch Tabulatoren ersetzen (das ist im Allgemeinen nicht gut, funktioniert aber im Code-Golf: ein Tab == 1 Zeichen). Sie können auch ein Diktat anstelle mehrerer ifs ( d={'+': operator.add, '-': operator.sub, ...}; d[op](a, b)) verwenden. Auch [floor(k) for k in n]kann auf gekürzt werden map(floor, n), und die n.addAnrufe können werden n.extend([floor(f), ceil(f), f]).
kirbyfan64sos

Wow, vielen Dank, ich werde versuchen, sie umzusetzen! Ich habe die Einzüge bereits als Tabulatoren gezählt, musste sie aber hier in Leerzeichen umwandeln.
Fehler

Sie können auch nur einzelne Leerzeichen verwenden. sie sollten arbeiten.
kirbyfan64sos

Soweit ich sehen kann, benutzt du Fnur einmal, damit du ein from fractions import*paar Bytes machen und sparen kannst . Gleiche mit math. Entfernen Sie die Leerzeichen =, sie sind nicht erforderlich. Außerdem sollten Sie die Eingabe sanstelle der Hardcodierung zuweisen .
Zgarb

@flawr Entfernen Sie alle optionalen Leerzeichen. Außerdem müssen Sie akzeptieren können jede Eingabe. Verwenden Sie s=input()anstatt s = "1/3*9", entfernen Sie Ihre Kommentare usw.
mbomb007

1

Mathematica, 134

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

0

MATLAB, 283 Zeichen

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

Ungolfed:

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

Als ich dies schrieb, wurde mir klar, dass es eine noch kürzere Möglichkeit gibt, die ich hinzufügen werde, sobald ich damit fertig bin.


0

VBA, 347 Bytes

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

1
Hier gibt es viel zu golfen, vor allem, um überflüssige Leerzeichen zu entfernen und kürzere Var-Namen zu wählen
Kat.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.