Kesalahan Pembulatan Tidak Terkendali

14

Latar Belakang

Anda baru-baru ini disewa oleh perusahaan akuntansi kecil. Dunia akuntansi agak asing bagi Anda, jadi Anda tidak yakin apakah Anda mengikuti semua pedoman profesional. Secara khusus, Anda tidak tahu kapan Anda harus membulatkan semua angka-angka itu, dan ke arah mana, sehingga sebagian besar waktu Anda hanya sayap itu dan berharap untuk yang terbaik.

Memasukkan

Input Anda adalah string tunggal yang mewakili perhitungan sederhana. Ini berisi beberapa bilangan bulat non-negatif yang dibatasi oleh karakter +-*/. String membaca dari kiri ke kanan, dan aturan diutamakan normal diabaikan, jadi "23+1*3/4"berarti "mulai dengan 23, tambahkan 1, kalikan dengan 3, dan bagi dengan 4", hasilnya adalah 18. Input tidak akan berisi angka yang dimulai dengan 0(kecuali 0dirinya sendiri), atau pembagian dengan nol.

Keluaran

Pada setiap tahap perhitungan, Anda dapat membulatkan hasil ke atas atau ke bawah ke bilangan bulat terdekat, atau menyimpannya apa adanya. Akhirnya, Anda membulatkan ke atas atau ke bawah untuk mendapatkan hasil bilangan bulat. Output Anda adalah daftar bilangan bulat yang mungkin dihasilkan dari perhitungan seperti itu, diurutkan dan tanpa duplikat.

Aturan

Anda dapat menulis program lengkap atau fungsi. Hitungan byte terendah menang, dan celah standar tidak diizinkan.

Uji Kasus

"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
sumber
Apakah program harus bekerja untuk semua input yang mungkin (terlepas dari ukuran angka), input ukuran terbatas, atau hanya kasus uji?
orlp
@ orlp Ini harus berfungsi setidaknya ketika semua angka input dan hasil antara di bawah, katakanlah, 10 juta dalam nilai absolut. Bagaimanapun, perusahaan akuntansi itu kecil.
Zgarb
Perhatikan case uji 1/3*9, yang mungkin gagal jika Anda menggunakan angka floating point.
Claudiu
@Claudiu Terima kasih, saya menambahkannya ke tantangan.
Zgarb

Jawaban:

4

J, 84 byte

Mulai dari daftar elemen 1 fungsi menyimpan semua angka antara yang mungkin ada dalam daftar dengan mengubah ekspresi berikutnya dan menambahkannya ke atas dan ke bawah salinan bulat.

Akan bermain golf lebih lanjut dan menambahkan penjelasan besok. Tidak dapat menemukan cara yang jelas untuk golf lebih banyak.

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

Lewati semua tes.

Pemakaian:

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

Coba di sini.

randomra
sumber
Bagaimana Anda berurusan dengan mereka sebagai rasional daripada mengapung - apakah itu dibangun untuk J? (Lengkap J noob di sini)
Claudiu
@ Claudiu Pada setiap eval saya memaksakan angka presisi yang diperluas (dalam hal ini rasional) dengan menambahkan huruf xdi akhir daftar.
randomra
3

Python 2, 220 karakter

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

Itu membuat daftar semua angka yang mungkin dan pada setiap langkah, menghasilkan tiga angka untuk setiap angka dalam daftar, bahkan jika ada duplikat. Dengan demikian kompleksitas run-time adalah eksponensial. Namun, ini bekerja secara instan untuk contoh kecil ini. Dupes dihapus di akhir.

Ini digunakan fractions.Fractionuntuk melakukan pembagian yang tepat, menghindari tidak ada floating point.

Tambahkan 5 karakter ( r=map(X,g)-> r=set(map(X,g))) untuk secara dramatis meningkatkan kinerja.

Claudiu
sumber
Inilah golf yang mudah untuk memulai: \Dadalah kelas karakter yang telah ditentukan untuk mencocokkan non-digit
Sp3000
@ orlp: Tetap sekarang! (Saya pikir ..)
Claudiu
@Cudiudiu: itu bisa berupa r"(\D)"atau "(\\D)". Selain itu, jika Anda menggunakan Python 3, Anda dapat mengganti pengindeksan Fdengan penugasan berbintang, misalnya:, A,B,*F=Fgunakan Adan Balih-alih F[0]dan F[1], dan singkirkan F=F[2:].
Mac
@ Mac: "\D"akhirnya tetap bekerja dan lebih pendek. Ini bukan urutan pelarian yang valid sehingga Python hanya menyertakan \ dan Dkata demi kata. Tip Python3 yang baik sebenarnya, saya akan memeriksanya, meskipun saya harus mengganti backticks dengan repr()dan mengubah maphasilnya menjadi daftar. Tugas yang berkilau bintangnya adalah sesuatu yang saya harap dimiliki oleh Python 2 ..
Claudiu
2

Python, 421 370 354 byte

Maaf, tolong tahan dengan saya. Saya benar-benar baru untuk python (saya hanya mencari bahasa yang mendukung fractiosn) dan menggunakan semua trik yang saya tahu untuk memperpendek kode tetapi masih monster mengingat ada solusi python hampir setengah ukuran. Saya belajar banyak dan berpikir saya akan tetap mengirimkannya =)

Versi Baru berkat @ kirbyfan64sos dan @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)))

Versi lama

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
cacat
sumber
Untuk satu hal, Anda bisa mengganti beberapa indentasi ruang dengan tab (biasanya menyebalkan, tetapi berfungsi dengan baik dalam kode golf: tab == 1 karakter). Anda juga dapat menggunakan dict bukannya beberapa ifs ( d={'+': operator.add, '-': operator.sub, ...}; d[op](a, b)). Juga, [floor(k) for k in n]dapat disingkat menjadi map(floor, n), dan n.addpanggilan bisa menjadi n.extend([floor(f), ceil(f), f]).
kirbyfan64sos
Wow terima kasih banyak, saya akan mencoba dan menerapkannya! Saya sudah menghitung indentasi sebagai tab tetapi saya harus mengubahnya menjadi spasi di sini.
flawr
Anda juga bisa menggunakan spasi tunggal; mereka harus bekerja.
kirbyfan64sos
Sejauh yang saya bisa lihat, Anda Fhanya menggunakan sekali, sehingga Anda bisa melakukan from fractions import*dan menyimpan beberapa byte. Sama dengan math. Hapus spasi di sekitar =, mereka tidak perlu. Selain itu, Anda harus menetapkan input ke salih-alih hard-coding.
Zgarb
@ flawr Hapus setiap ruang opsional. Anda juga harus dapat menerima input apa pun . Gunakan s=input()daripada s = "1/3*9", hapus komentar Anda, dll.
mbomb007
1

Mathematica, 134

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

MATLAB, 283 karakter

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

Tidak Disatukan:

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

Saat menulis ini, saya menyadari bahwa ada cara yang lebih pendek untuk melakukan ini, yang akan saya tambahkan setelah saya selesai menulisnya.

AJMansfield
sumber
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
Alex
sumber
1
Ada cukup banyak permainan golf yang harus dilakukan di sini, terutama menghilangkan ruang kosong yang sangat besar dan memilih nama var yang lebih pendek
cat