Помилки округлення поза контролем


14

Фон

Вас нещодавно найняла невелика бухгалтерія. Світ бухгалтерського обліку для вас дещо чужий, тому ви не впевнені, чи дотримуєтесь ви всіх професійних рекомендацій. Зокрема, ви не знаєте, коли вам слід обійти всі ці цифри і в якому напрямку, тож більшу частину часу ви просто крилате його і сподіваєтесь на краще.

Вхідні дані

Ваш вхід - це один рядок, який представляє простий обчислення. Він містить деяку кількість невід’ємних цілих чисел, розділених символами +-*/. Рядок зчитується зліва направо, а нормальні правила пріоритету ігноруються, тому "23+1*3/4"означає "почати з 23, додати 1, помножити на 3 і ділити на 4", результат 18. Вхід не буде містити цифри, що починаються з 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 Це повинно працювати хоча б тоді, коли всі вхідні числа та проміжні результати нижче, скажімо, 10 мільйонів в абсолютному значенні. Зрештою, бухгалтерська фірма невелика.
Згарб

Візьміть до уваги тестовий випадок 1/3*9, який може вийти з ладу, якщо ви використовуєте числа з плаваючою комою.
Клавдіу

@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 noob тут)
Клавдіу

@Claudiu На кожному етапі я примушую збільшувати точні цифри (в даному випадку раціональні), додаючи лист x в кінці списку.
randomra

3

Python 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: це має бути r"(\D)"або "(\\D)". Крім того, якщо ви використовуєте Python 3, ви можете замінити індексацію на Fпризначення зірочкою, наприклад:, A,B,*F=Fuse AтаB замість F[0]і F[1], і позбутися від F=F[2:].
Мак

@Mac: "\D"все одно закінчує роботу і це коротше. Це не дійсна послідовність втечі, тому Python просто включає \ і Dдослівно. Хороший підказка Python3, я перевірю це, хоча мені доведеться замінити задні repr()точки і перетворити mapрезультат у список. Завдання із зіркою - це те, що я хотів би, щоб Python 2 мав ..
Клавді

2

Пітона, 421 370 354 байт

Вибачте, будь ласка, мати мене. Я насправді новачок у python (я просто шукав мову, яка підтримує fractiosn) і використовував усі декілька відомих мені трюків для скорочення коду, але це все ще монстр, враховуючи, що існує рішення пітона майже в половину розміру. Я багато чого навчився і подумав, що все-таки податиму це =)

Нова версія завдяки @ 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 символ). Ви також можете використовувати dict замість кількох ifs ( d={'+': operator.add, '-': operator.sub, ...}; d[op](a, b)). Крім того, [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замість жорсткого кодування.
Згарб

@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
Тут потрібно зробити дуже багато гольфу, перш за все, видалити чудовий пробіл та вибрати коротші назви вар
кіт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.