Błędy zaokrąglania poza kontrolą

14

tło

Zostałeś niedawno zatrudniony przez małą firmę księgową. Świat rachunkowości jest dla Ciebie nieco obcy, więc nie masz pewności, czy przestrzegasz wszystkich profesjonalnych wskazówek. W szczególności nie wiesz, kiedy powinieneś zaokrąglić wszystkie te liczby i w jakim kierunku, więc przez większość czasu po prostu je przeskakujesz i masz nadzieję na najlepsze.

Wejście

Twój wkład jest pojedynczym ciągiem, który reprezentuje proste obliczenie. Zawiera pewną liczbę nieujemnych liczb całkowitych rozdzielonych znakami +-*/. Ciąg jest odczytywany od lewej do prawej, a normalne reguły pierwszeństwa są ignorowane, co "23+1*3/4"oznacza „zacznij od 23, dodaj 1, pomnóż przez 3 i podziel przez 4”, co daje wynik 18. Wartość wejściowa nie będzie zawierać liczb rozpoczynających się od 0(oprócz 0siebie), ani dzielenie przez zero.

Wynik

Na każdym etapie obliczeń można zaokrąglić wynik w górę lub w dół do najbliższej liczby całkowitej lub zachować go bez zmian. Na koniec zaokrąglasz w górę lub w dół, aby uzyskać wynik w postaci liczby całkowitej. Twoje dane wyjściowe to lista liczb całkowitych, które mogą wynikać z takiego obliczenia, posortowane i bez duplikatów.

Zasady

Możesz napisać pełny program lub funkcję. Wygrywa najniższa liczba bajtów, a standardowe luki są niedozwolone.

Przypadki testowe

"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
źródło
Czy program musi działać dla wszystkich możliwych danych wejściowych (niezależnie od wielkości liczbowej), danych wejściowych o ograniczonym rozmiarze lub tylko dla przypadków testowych?
lub
@orlp Powinno działać przynajmniej wtedy, gdy wszystkie liczby wejściowe i wyniki pośrednie są poniżej, powiedzmy, 10 milionów wartości bezwzględnej. W końcu firma księgowa jest mała.
Zgarb,
Zanotuj przypadek testowy 1/3*9, który może się nie powieść, jeśli użyjesz liczb zmiennoprzecinkowych.
Claudiu
@Claudiu Dzięki, dodałem to do wyzwania.
Zgarb,

Odpowiedzi:

4

J, 84 bajtów

Zaczynając od listy 1-elementowej, funkcja zachowuje wszystkie możliwe liczby pośrednie na liście, sprawdzając następne wyrażenie i dodając je w górę iw dół zaokrąglonych kopii.

Czy golf będzie dalej i jutro doda wyjaśnienie. Nie mogę znaleźć bardziej oczywistych sposobów na grę w golfa.

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

Przechodzi wszystkie testy.

Stosowanie:

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

Wypróbuj tutaj.

randomra
źródło
Jak traktujesz je jako racjonalne zamiast zmiennoprzecinkowe - czy jest to wbudowane w J? (Wypełnij J noob tutaj)
Claudiu
@Claudiu Przy każdej ewaluacji wymuszam rozszerzone liczby precyzji (w tym przypadku racjonalne), dołączając literę xna końcu listy.
randomra
3

Python 2, 220 znaków

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

Prowadzi listę wszystkich możliwych liczb i na każdym kroku generuje trzy liczby dla każdej liczby na liście, nawet jeśli są duplikaty. Zatem złożoność w czasie wykonywania jest wykładnicza. Działa to jednak natychmiast dla tych małych przykładów. Duplikaty są usuwane na końcu.

Wykorzystuje fractions.Fractionsię do dokładnego dzielenia, unikając niedokładności zmiennoprzecinkowych.

Dodaj 5 znaków ( r=map(X,g)-> r=set(map(X,g))), aby znacznie zwiększyć wydajność.

Claudiu
źródło
Oto prosty golf, od którego można zacząć: \Djest predefiniowaną klasą postaci do dopasowywania znaków innych niż cyfry
Sp3000,
@orlp: Naprawiono teraz! (Myślę ...)
Claudiu,
@Claudiu: które powinny być r"(\D)"albo "(\\D)". Ponadto, jeśli używasz Python 3, możesz zamienić indeksowanie na Fprzypisanie oznaczone gwiazdką, np .: A,B,*F=Fużyj, Aa Bzamiast F[0]i F[1], i pozbądź się F=F[2:].
Mac
@Mac: "\D"i tak działa i jest krótszy. To nie jest poprawna sekwencja ucieczki, więc Python zawiera po prostu \ i Ddosłownie. Dobra wskazówka dla Python3, sprawdzę to, choć będę musiał zastąpić backticks repr()i przekształcić mapwynik w listę. Zadanie oznaczone gwiazdką to coś, co chciałbym, aby Python 2 miał ...
Claudiu
2

Python, 421 370 354 bajtów

Przepraszam, proszę o wyrozumiałość. Jestem naprawdę nowy w Pythonie (szukałem tylko języka obsługującego Fractiosn) i wykorzystałem wszystkie nieliczne sztuczki, które znałem do skracania kodu, ale wciąż jest to potwór, biorąc pod uwagę, że istnieje rozwiązanie python prawie o połowę mniejsze. Wiele się nauczyłem i myślałem, że mimo to go prześlę =)

Nowa wersja dzięki @ kirbyfan64sos i @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)))

Stara wersja

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
wada
źródło
Po pierwsze, możesz zamienić niektóre wcięcia spacji na tabulatory (ogólnie jest do bani, ale działa dobrze w golfie kodowym: tab = = 1 znak). Możesz także użyć dict zamiast kilku ifs ( d={'+': operator.add, '-': operator.sub, ...}; d[op](a, b)). Ponadto, [floor(k) for k in n]można skrócić do map(floor, n), a n.addpołączenia mogą stać n.extend([floor(f), ceil(f), f]).
kirbyfan64sos
Wow dziękuję bardzo, postaram się je wdrożyć! Już teraz liczyłem wcięcia jako tabulatory, ale tutaj musiałem przekonwertować je na spacje.
flawr
Możesz także użyć pojedynczych spacji; powinni pracować.
kirbyfan64sos
O ile widzę, używasz Ftylko raz, więc możesz zrobić from fractions import*i zapisać niektóre bajty. To samo z math. Usuń spacje wokół =, są niepotrzebne. Ponadto należy przypisać dane wejściowe szamiast kodowania na stałe.
Zgarb
@flawr Usuń wszystkie opcjonalne spacje. Musisz także być w stanie zaakceptować dowolne dane wejściowe. Użyj s=input()zamiast s = "1/3*9", usuń swoje komentarze itp.
mbomb007 13.04.15
1

Mathematica, 134

Union@Flatten@{Floor@#,Ceiling@#}&@ToExpression@StringReplace[#,x:("+"|"-"|"*"|"/"~~NumberString):>"//{Floor@#,#,Ceiling@#}"~~x~~"&"]&
alephalpha
źródło
0

MATLAB, 283 znaków

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

Nie golfowany:

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

Pisząc to, zdałem sobie sprawę, że istnieje jeszcze krótszy sposób na zrobienie tego, co dodam, gdy skończę pisać.

AJMansfield
źródło
0

VBA, 347 bajtów

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
źródło
1
Trzeba tutaj grać w golfa, usuwając zbędne białe spacje i wybierając krótsze nazwy var
cat