Errori di arrotondamento fuori controllo


14

sfondo

Di recente sei stato assunto da una piccola società di contabilità. Il mondo della contabilità è in qualche modo estraneo a te, quindi non sei sicuro di seguire tutte le linee guida professionali. In particolare, non sai quando dovresti arrotondare tutti quei numeri e in quale direzione, quindi la maggior parte delle volte lo fai semplicemente e speri per il meglio.

Ingresso

Il tuo input è una singola stringa che rappresenta un semplice calcolo. Contiene un numero di numeri interi non negativi delimitati dai caratteri +-*/. La stringa legge da sinistra a destra e le normali regole di precedenza vengono ignorate, quindi "23+1*3/4"significa "inizia con 23, aggiungi 1, moltiplica per 3 e dividi per 4", il risultato è 18. L'input non conterrà numeri che iniziano con 0(tranne se 0stesso), né una divisione per zero.

Produzione

In ogni fase del calcolo, è possibile arrotondare il risultato verso l'alto o verso il basso all'intero più vicino o mantenerlo così com'è. Infine, arrotondare per eccesso o per difetto per ottenere un risultato intero. Il tuo output è l'elenco di numeri interi che possono derivare da tale calcolo, ordinati e senza duplicati.

Regole

È possibile scrivere un programma completo o una funzione. Vince il conteggio di byte più basso e non sono consentite scappatoie standard.

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

Il programma deve funzionare per tutti i possibili input (indipendentemente dalla dimensione del numero), un input di dimensioni limitate o solo i casi di test?
orlp,

@orlp Dovrebbe funzionare almeno quando tutti i numeri di input e i risultati intermedi sono inferiori, diciamo, a 10 milioni in valore assoluto. La società di contabilità è piccola, dopo tutto.
Zgarb,

Prendere nota del caso di test 1/3*9, che potrebbe non riuscire se si utilizzano numeri in virgola mobile.
Claudiu,

@Claudiu Grazie, l'ho aggiunto alla sfida.
Zgarb,

Risposte:


4

J, 84 byte

A partire da un elenco di 1 elemento, la funzione mantiene tutti i possibili numeri intermedi nell'elenco valutando l'espressione successiva e aggiungendone copie arrotondate su e giù.

Giocherà ulteriormente a golf e aggiungerò spiegazioni domani. Non riesco a trovare modi ovvi per giocare a golf di più.

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

Supera tutti i test.

Uso:

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

Provalo qui.


Come li gestisci come razionali invece che come float - è incorporato in J? (Completa J noob qui)
Claudiu

@Claudiu Ad ogni evocazione impongo numeri di precisione estesi (in questo caso razionali) aggiungendo la lettera xalla fine dell'elenco.
randomra,

3

Python 2, 220 caratteri

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

Mantiene un elenco di tutti i numeri possibili e ad ogni passaggio, genera tre numeri per ogni numero nell'elenco, anche se ci sono duplicati. Pertanto, la complessità del runtime è esponenziale. Tuttavia, funziona istantaneamente per questi piccoli esempi. I duplicati vengono rimossi alla fine.

Usa fractions.Fractionper fare la divisione esatta, evitando inesattezze in virgola mobile.

Aggiungi 5 caratteri ( r=map(X,g)-> r=set(map(X,g))) per aumentare notevolmente le prestazioni.


Ecco un golf facile con cui iniziare: \Dè una classe di caratteri predefinita per la corrispondenza delle non cifre
Sp3000

@orlp: risolto ora! (Penso ..)
Claudiu

@Claudiu: dovrebbe essere r"(\D)"o "(\\D)". Inoltre, se si utilizza Python 3, è possibile sostituire l'indicizzazione Fcon assegnazione a stella, ad esempio:, A,B,*F=Futilizzare Ae Binvece di F[0]e F[1], e sbarazzarsi di F=F[2:].
Mac

@Mac: "\D"finisce per funzionare comunque ed è più breve. Non è una sequenza di escape valida, quindi Python include solo \ e Dletteralmente. Buon consiglio Python3 in realtà, lo controllerò, anche se dovrò sostituire i backtick con repr()e trasformare il maprisultato in un elenco. L'incarico speciale è qualcosa che vorrei che Python 2 avesse ..
Claudiu,

2

Python, 421 370 354 byte

Scusa, ti prego, abbi pazienza. Sono davvero nuovo a Python (stavo solo cercando un linguaggio che supporti Fractiosn) e ho usato tutti i pochi trucchi che conoscevo per abbreviare il codice, ma è ancora un mostro considerando che esiste una soluzione Python di quasi la metà delle dimensioni. Ho imparato molto e ho pensato di inviarlo comunque =)

Nuova versione grazie a @ kirbyfan64sos e @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)))

Vecchia versione

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

Per prima cosa, potresti sostituire alcuni dei rientri dello spazio con delle schede (generalmente fa schifo, ma funziona bene nel golf del codice: una scheda == 1 carattere). Puoi anche usare un dict invece di diversi ifs ( d={'+': operator.add, '-': operator.sub, ...}; d[op](a, b)). Inoltre, [floor(k) for k in n]può essere abbreviato map(floor, n)e le n.addchiamate possono diventare n.extend([floor(f), ceil(f), f]).
Kirbyfan64sos,

Wow, grazie mille, proverò ad implementarli! Ho già contato i rientri come schede ma ho dovuto convertirli in spazi qui.
Flawr,

Puoi anche usare solo spazi singoli; dovrebbero funzionare.
kirbyfan64sos,

Per quanto posso vedere, si utilizza Fsolo una volta, quindi è possibile fare from fractions import*e salvare alcuni byte. Lo stesso con math. Rimuovi gli spazi intorno =, non sono necessari. Inoltre, è necessario assegnare l'input sinvece di hard-coding.
Zgarb,

@flawr Rimuovi tutti gli spazi opzionali. Inoltre, devi essere in grado di accettare qualsiasi input. Usa s=input()invece di s = "1/3*9", rimuovi i tuoi commenti, ecc.
mbomb007,

1

Mathematica, 134

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

0

MATLAB, 283 caratteri

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

Mentre scrivevo, mi sono reso conto che esiste un modo ancora più breve per farlo, che aggiungerò una volta terminato di scriverlo.


0

VBA, 347 byte

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
C'è molto golf da fare qui, principalmente rimuovendo gli spazi bianchi superflous e scegliendo nomi var più corti
cat
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.