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


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
⍎¯11↓⍵M

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

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

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

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

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

Пояснення

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

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

(⎕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.