제어 불능 반올림 오류


14

배경

최근 소규모 회계 회사에서 고용되었습니다. 회계의 세계는 당신에게 다소 외국이므로, 모든 전문적인 지침을 따르고 있는지 확실하지 않습니다. 특히, 모든 숫자를 언제 반올림해야하는지, 어느 방향으로해야하는지 모릅니다.

입력

입력은 간단한 계산을 나타내는 단일 문자열입니다. 문자로 구분 된 음수가 아닌 정수가 포함되어 있습니다 +-*/. 문자열은 왼쪽에서 오른쪽으로 읽으며 일반적인 우선 순위 규칙은 무시되므로 "23+1*3/4""23으로 시작하여 1을 더하고 3을 곱하고 4로 나누십시오"를 의미합니다. 결과는 18입니다. 입력은 다음으로 시작하는 숫자를 포함하지 않습니다. 0( 0자체 제외 ) 또는 0으로 나누기.

산출

계산의 각 단계에서 결과를 가장 가까운 정수로 반올림 또는 내림하거나 그대로 유지할 수 있습니다. 마지막으로 정수 결과를 얻기 위해 반올림 또는 내림합니다. 결과는 이러한 계산으로 인해 정렬되고 중복되지 않은 정수 목록입니다.

규칙

전체 프로그램이나 함수를 작성할 수 있습니다. 가장 낮은 바이트 수가 이기고 표준 허점은 허용되지 않습니다.

테스트 사례

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

프로그램은 가능한 모든 입력 (숫자 크기에 관계없이), 제한된 크기의 입력 또는 테스트 케이스에서만 작동해야합니까?
orlp

@orlp 적어도 모든 입력 숫자와 중간 결과가 절대 값이 천만 미만인 경우 작동합니다. 결국 회계 회사는 규모가 작습니다.
Zgarb

1/3*9부동 소수점 숫자를 사용하면 테스트 사례를 기록해 두십시오 .
Claudiu

@Claudiu 감사합니다. 도전에 추가했습니다.
Zgarb

답변:


4

J, 84 바이트

1 요소 목록에서 시작하여이 함수는 다음 표현식을 회피하고 상하로 반올림 된 사본을 추가하여 목록에 가능한 모든 중간 숫자를 유지합니다.

내일 골프를 더하고 설명을 추가합니다. 더 골프를 칠 수있는 확실한 방법을 찾을 수 없습니다.

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

모든 테스트를 통과합니다.

용법:

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

여기에서 시도하십시오.


수레 대신 합리적으로 처리하는 방법-J에 내장되어 있습니까? (완전한 J 멍청한 놈)
Claudiu

@Claudiu 모든 평가에서 나는 x목록의 끝에 문자 를 추가하여 확장 된 정밀 숫자 (이 경우 합리적인)를 강제 합니다.
randomra

3

파이썬 2, 220 자

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

가능한 모든 숫자의 목록을 유지하고 각 단계에서 중복이 있더라도 목록의 모든 숫자에 대해 세 개의 숫자를 생성합니다. 따라서 런타임 복잡성은 기하 급수적입니다. 그러나 이러한 작은 예제에서는 즉시 작동합니다. 끝에서 듀피가 제거됩니다.

fractions.Fraction부동 소수점의 부정확성을 피하면서 정확한 나누기를 수행 하는 데 사용 됩니다.

성능을 크게 향상 시키려면 5 자 ( r=map(X,g)-> r=set(map(X,g)))를 추가하십시오 .


시작하기 쉬운 골프는 다음과 같습니다. \D숫자가 아닌 문자를 일치시키기위한 사전 정의 된 문자 클래스입니다.
Sp3000

@orlp : 지금 고쳤습니다! (제 생각에는 ..)
Claudiu

@Claudiu : r"(\D)"또는 중 하나 여야합니다 "(\\D)". 파이썬 3 사용하는 경우 또한, 당신은에 색인을 대체 할 수 F별표 할당, 예와 함께 : A,B,*F=F사용 AB대신 F[0]하고 F[1], 그리고 제거하기 F=F[2:].
Mac

@Mac : "\D"어쨌든 작동하고 더 짧습니다. 유효한 이스케이프 시퀀스가 ​​아니기 때문에 Python에는 \ and 및 Dverbatim 만 포함 됩니다. 좋은 Python3 팁은 실제로 확인하겠습니다.하지만 백틱을 대체 repr()하고 map결과를 목록으로 바꿔야 합니다. 별표 할당은 내가 파이썬 2에 원하는 것입니다 ..
Claudiu

2

파이썬 421 370 354 바이트

미안 해요 나는 파이썬을 처음 접했고 (소수점을 지원하는 언어를 찾고있었습니다) 코드를 단축하는 데 알았던 몇 가지 트릭을 모두 사용했지만 거의 절반 크기의 파이썬 솔루션이 있다고 생각하면 여전히 괴물입니다. 나는 많은 것을 배웠고 어쨌든 제출하겠다고 생각했다 =)

@ kirbyfan64sos 및 @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)))

구 버전

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

우선 공백 들여 쓰기 일부를 탭으로 대체 할 수 있습니다 (일반적으로 짜증나지만 코드 골프에서는 잘 작동합니다 : 탭 == 1 문자). ifs ( d={'+': operator.add, '-': operator.sub, ...}; d[op](a, b)) 대신 dict을 사용할 수도 있습니다 . 또한, [floor(k) for k in n]단축 할 수 있습니다 map(floor, n), 그리고 n.add통화가 될 수 있습니다 n.extend([floor(f), ceil(f), f]).
kirbyfan64sos

와, 정말 고마워요, 시도하고 구현하겠습니다! 나는 들여 쓰기를 탭으로 이미 계산했지만 공백으로 변환해야했습니다.
flawr

단일 공백 ​​만 사용할 수도 있습니다. 그들은 작동해야합니다.
kirbyfan64sos

내가 볼 수 F있는 한, 당신은 한 번만 사용 하므로 from fractions import*일부 바이트를 저장하고 저장할 수 있습니다. 와 동일합니다 math. 주변의 공백을 제거하면 =불필요합니다. 또한 s하드 코딩 대신 입력을 할당해야합니다 .
Zgarb

@flawr 모든 선택적 공간을 제거하십시오. 또한 모든 입력 을 승인 할 수 있어야합니다 . 사용 s=input()하기보다는 s = "1/3*9"등 의견을, 제거
mbomb007

1

매스 매 티카, 134

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

0

MATLAB, 283 자

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

언 골프 드 :

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

이것을 쓰는 동안, 나는 이것을하는 더 짧은 방법이 있다는 것을 깨달았습니다. 나는 그것을 쓰고 나면 추가 할 것입니다.


0

VBA, 347 바이트

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
여기에는 주로 수퍼 플로어 공백을 제거하고 더 짧은 var 이름을 선택하는 골프가 많이 있습니다.
cat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.