Створіть універсальний калькулятор


16

Натхнення. Зворотний.

Оцініть заданий вираз універсального значення.

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

Ви повинні підтримувати додавання, віднімання, множення, ділення та додатні реальні числа (негативні можна записати -0-n-) у розумному діапазоні для вашої мови.

Плюс і мінус повинні бути +і -, але ви можете використовувати *або ×для разів, /або ÷для розділення. Інші розумні символи будуть дозволені на запит.

Brownie вказує на пояснення та додаткові функції (наприклад, додаткові операції, негативні цифри, рядки тощо). Навіть якщо у вашій відповіді немає цих функцій, сміливо покажіть, як це могло.

Будь ласка, надайте посилання для тестування свого рішення, якщо це можливо.

Приклади

Для наочності в поясненнях нижче використовується високий мінус ( ¯) для позначення негативних чисел. Ви можете повернути негативні цифри у будь-якому розумному форматі.

-5-2- → 3

+2+×3×2×+→ 8 ( +2+×3×2×+→ +2+6+→ 8)

-14--3-1--→ 12 ( -4--3-1--→ -14-2-→ 12)

+2.1+×3.5×2.2×+→ 9.8 ( +2.1+×3.5×2.2×+→ +2.1+7.7+→ 9.8)

×3×÷-0-6-÷2÷×→ -9 ( ×3×÷-0-6-÷2÷×→ ×3×÷¯6÷2÷×→ ×3ׯ3×→ → ¯9)

÷4÷-3-÷1÷2÷-÷→ 1.6 ( ÷4÷-3-÷1÷2÷-÷→ ÷4÷-3-0.5-÷→ ÷4÷2.5÷→ → 1.6)


1
The explanations below use high minus (`¯`) to indicate negative numbers.Ви точно любите APL.
— Ерік Аутгольфер

@EriktheOutgolfer У вас є краща пропозиція? Також TI-BASIC використовує високий мінус.
— Adám

Насправді ні, оскільки -s можна плутати з -s, тоді як ¯s не можна плутати з -s.
— Ерік Аутгольфер

Ба, я щойно помітив справжню вимогу до кількості. Стільки за мій арифметичний розчин сітківки на 290 байт ...
— Ніл

@Neil Чому ви не опублікуєте це як відповідь?
— Адам

Відповіді:


4

C # (.NET Core) , 198 197 188 байт

float O(string s){try{return float.Parse(s);}catch{var f=s[0];int i=s.IndexOf(f,1);float a=O(s.Substring(1,i-1)),b=O(s.Substring(i+1,s.Length-i-2));return f<43?a*b:f<44?a+b:f<46?a-b:a/b;}}

Спробуйте в Інтернеті!

Використання *та /.

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

  • 1 байт збережено завдяки панові Xcoder!
  • 9 байт збережено завдяки TheLethalCoder!

IndefOf(f, 1)можнаIndexOf(f,1)
— Містер Xcoder

1
floatНатомість використовуйте s, використовуйте char-коди, коли у вас їх, ймовірно, можна скоротити за допомогою >та <в декількох місцях.
— TheLethalCoder

Ви можете перейти i+1,s.Length-i-2на байт, змінивши на ++i,s.Length+~i.
— Kevin Cruijssen

4

Python 3, 159 158 152 144 136 135 132 байт

def t(i,a=1):
 while'-'<l[i]!='/':i+=1;a=0
 if a:l[i]='(';i=t(t(i+1));l[i-1]=')'
 return-~i
*l,=input()
t(0)
print(eval(''.join(l)))

Спробуйте в Інтернеті!

Не дозволяє негативні числа (хоча це -0-5-працює, звичайно) і вимагає операторів python.


Чи можете ви додати посилання TIO?
— Adám

1
while~-(l[i]in'+-*/'):i+=1;a=1і *l,=input()на 152 байти
— Феліпе Нарді Батіста

1
з усіма тестовими прикладами: посилання
— Феліпе Нарді Батіста


1
if a:l[i]='(';i=t(t(i+1));l[i-1]=')'з return-~iза 135 байт: P
— Феліпе Нарді Батіста

3

Сітківка , 290 287 286 байт

\d+
¦$&$*
¯¦
¯
{`\+([¯¦]1*)\+([¯¦]1*)\+
-$1-¯$2-
-(¯|¦)(1*)-([¯¦]+1*\2)-
-¯$3-¯$1$2-
(×|÷)¯(1*\1)([¯¦]1*\1)
$1¦$2¯$3
צ×[¯¦]1*×|¯¯¦?
¦
¯¦|¦¯
¯
+`-((¯|¦)1*)(1*)-\2\3-
$1
-([¯¦]1*)-[¯¦](1*)-
$1$2
צ1(1*)×([¯¦]1*)×
+צ$1×$2×+$2+
}`÷¦(?=1*÷(¯|¦)(1+)÷)(\2)*1*÷\1\2÷
$1$#3$*
((¯)|¦)(1*)
$2$.3

Спробуйте в Інтернеті! Примітка. Здатний лише до цілої арифметики, тому деякі тестові приклади були вилучені. Приймає та повертає негативні числа за допомогою ¯префікса. Редагувати: збережено 3 4 байти завдяки @Cowsquack. Пояснення:

\d+
¦$&$*

Мені потрібен був спосіб обробки нуля, тому я використовую ¦як префікс додатного числа. Потім числа перетворюються на одинакові.

¯¦
¯

Але негативним числам потрібен лише ¯префікс.

{`\+([¯¦]1*)\+([¯¦]1*)\+
-$1-¯$2-

Цитування +s стає некрасивим, тому я перетворюю додавання на віднімання.

-(¯|¦)(1*)-([¯¦]+1*\2)-
-¯$3-¯$1$2-

Якщо абсолютне значення LHS віднімання менше, ніж RHS, перемикайте їх навколо і заперечуйте обидві сторони.

(×|÷)¯(1*\1)([¯¦]1*\1)
$1¦$2¯$3

Також якщо LHS множення чи ділення негативні, заперечте обидві сторони.

צ×[¯¦]1*×|¯¯¦?
¦

Також якщо LHS множення дорівнює нулю, то результат дорівнює нулю. Також два мінуси складають плюс.

¯¦|¦¯
¯

Але мінус і плюс (або навпаки) становлять мінус.

+`-((¯|¦)1*)(1*)-\2\3-
$1

Відніміть два числа одного знака. Робіть це повторно, поки не залишиться таких віднімань.

-([¯¦]1*)-[¯¦](1*)-
$1$2

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

צ1(1*)×([¯¦]1*)×
+צ$1×$2×+$2+

Виконай множення повторним складанням.

}`÷¦(?=1*÷(¯|¦)(1+)÷)(\2)*1*÷\1\2÷
$1$#3$*

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

((¯)|¦)(1*)
$2$.3

Перетворити назад у десятковий.


Нічого собі, це - епопея. Найбільший пост сітківки на PPCG? Однак зазвичай рішення QuadR і Retina дуже схожі між собою. Чи можу я надихнутись?
— Adám

У цій лінії +`-(([¯¦])1*)(1*)-\2\3-, [¯¦]може стати¯|¦
— Kritixi Lithos

@Cowsquack трапляється тричі насправді, дякую!
— Ніл

Одного ви пропустили ([×÷]);)
— Kritixi Lithos

1
@Cowsquack Вам краще не знайти іншого, інакше мені доведеться перекреслити 4 ...
— Ніл

2

PHP , 116 114 109 байт

-5 завдяки Мартину Ендеру

for($s=$argv[$o=1];$o!=$s;)$s=preg_replace('#([*+/-])(([\d.]+|(?R))\1(?3))\1#','($2)',$o=$s);eval("echo$s;");

Використовується *для множення та /для ділення. Негативні цифри спрацьовують, не дивлячись на те, що я не роблю конкретних спроб для цього.

Спробуйте в Інтернеті!

Необов’язаний і пояснений

for($s=$argv[$o=1];   # Initialize with $s = input and $o = 1;
    $o!=$s;)          # While $o != $s
    # Set $o to $s and set $s to be $s after this regex replacement:
    $s=preg_replace('#([*+/-])(([\d.]+|(?R))\1(?3))\1#','($2)',$o=$s);
    # i.e., continue to do this replacement until the result is the same on two consecutive
    # steps (no replacement was made)
# Once $o == $s (i.e. no more replacement can be made), eval the result and print
eval("echo$s;"); 

Я також поясню регулярний вираз, оскільки це трохи магічно:

([*+/-])(([\d.]+|(?R))\1(?3))\1


([*+/-])

По-перше, ми хочемо відповідати будь-якому з чотирьох операторів: *+/-

([\d.]+|(?R))

Тоді нам потрібно відповідати або числом, [\d.]+або іншим дійсним виразом omnifix (?R).

\1

Потім ми співставляємо того самого оператора, який був на початку.

(?3)

Тоді ми робимо те саме, що ми робили в групі 3: співставляємо число або вираз всеобігу.

\1

Нарешті, знову знайдіть початкового оператора.

На які б матчі це не замінювалося ($2). Це займає частину всередині оточуючих операторів і ставить її всередині дужок, так що це виглядає як нормальне позначення інфіксації.


2

QuadR , 33 32 27 байт

-1 спасибі коровам квак . -5 завдяки Еріку Переверху .

((.)[\d¯\.]+){2}\2
⍎¯1↓1↓⍵M

з аргументом / прапором ≡

Спробуйте в Інтернеті!

Це еквівалентно 40-байтовому рішенню Dyalog APL:

'((.)[\d¯\.]+){2}\2'⎕R{⍕⍎1↓¯1↓⍵.Match}⍣≡

Спробуйте в Інтернеті!

Пояснення

(текст у дужках посилається на Dyalog APL замість QuadR)

 (… ){2}\2 Наступний малюнок двічі, а також весь збіг двічі:
  (.) будь-який символ
  [… з ]+ наступним одним або кількома з наступного набору символів:
   \d d запалює,
   ¯ високий мінус (негативний знак)
   \.  період

(⎕R  В R eplaced з :)

({ … } Результат наступної анонімної функції, застосованої до простору імен ⍵ :)

 ⍵M ( ⍵.Match) на текст М атч
 ¯1↓ випадає останній символ (символ + - ×або ÷)
 1↓ випадає перший символ (символ)
 ⍎  виконується як код APL
 ( ⍕ stringify)

≡ ( ⍣≡) повторюйте заміну, поки не відбудеться більше змін


Я думаю, ти можеш кинути⍕
— Kritixi Lithos

@Cowsquack Ви праві щодо QuadR. ⎕Rне може працювати на числових даних. Спасибі.
— Adám


1

Хаскелл , 132 ч

(134 байти, тому що ×і ÷беруть два байти в UTF-8)

f y|(n@(_:_),r)<-span(`elem`['.'..'9'])y=(read n,r)
f(c:d)|(l,_:s)<-f d,(m,_:r)<-f s=(o[c]l m,r)
o"+"=(+)
o"-"=(-)
o"×"=(*)
o"÷"=(/)

Спробуйте в Інтернеті!

fаналізує стільки, скільки може, і дає результат, а також рядок, що залишився (який у тестових випадках порожній). Якщо це не відповідає правилам, зніміть нерозбірний рядок, що залишився

Хаскелл , 139 годин

...
g=fst.f

0

Perl, 64 53 байти

Включити +1для-p

perl -pe 's%([*-/])(([\d.]+|(?0))\1(?3))\1%($2)%&&redo;$_=eval' <<< "/4/-3-/1/2/-/"

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


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.