Давайте сделаем некоторую арифметику местоположения!


22

Из статьи Википедии :

Локальная арифметика (Latin arithmeticæ localis) - это аддитивные (непозиционные) двоичные системы счисления, которые Джон Нейпир исследовал как метод вычисления в своем трактате «Рабдология» (1617), как символически, так и на шахматной решетке.

Какая?

Расположение цифр - это способ написания чисел с использованием букв алфавита.

Двоичная запись еще не была стандартизирована, поэтому Нейпир использовал то, что он называл цифрами местоположения, для представления двоичных чисел. Система Нейпира использует нотацию знак-значение для представления чисел; он использует последовательные буквы английского алфавита для представления последовательных степеней двух: a = 2 ^ 0 = 1, b = 2 ^ 1 = 2, c = 2 ^ 2 = 4, d = 2 ^ 3 = 8, e = 2 ^ 4 = 16 и так далее.

Пример

ab = 1 + 2 = 3 в базе 10

aabb = 1 + 1 + 2 + 2 = 6 в базе 10

Обратите внимание, что aabbэто можно сократить bc, заменив любые 2 экземпляра буквы на более высокий.

прибавление

Вы просто соединяете два числа и упрощаете.

acd+ bde= acdbde= abcdde= acebe= abcf= 39в базе 10

Вычитание

Просто удалите все цифры, появляющиеся одинаково в обеих частях вычитания. Расширение (преобразование bв aa) может быть необходимым

abde- ad= be= 18 в базе 10

умножение

Это немного сложнее.

Допустим, мы хотим умножить acd(13) на def(56). Сначала вы расположите acdвертикально:

a
c
d

Затем вы добавляете defпосле первого a:

a def
c
d

Теперь c на 2 позиции в алфавите позже, чем a, поэтому мы добавляем 2 позиции в алфавите defдля создания fgh. Это добавляется во второй ряд.

a def
c fgh
d

Наконец, d на 1 позицию в алфавите позже, чем c, поэтому мы добавляем 1 позицию в алфавите fghдля создания ghi. Это добавлено в третий ряд.

a def
c fgh
d ghi

Тогда вы берете сумму справа: def+ fgh+ ghi= deffgghhi= deggghhi= deghhhi= deghii= deghj(728)

Еще один пример умножения

Входные данные:

bc * de

Первый:

b
c

затем

b ef
c 

затем

b ef
c fg

Обратите внимание, что мы записали efв первой строке. Это потому, что bcначинается с b, и bявляется второй буквой в алфавите, поэтому нам нужно сместиться deна 1 букву, чтобы она стала ef.

затем

ef+fg

Выход:

eh

разделение

Это не является частью этой проблемы, потому что это может быть очень сложным.

Ваш актуальный вызов

Ваша программа или функция должна принимать входные данные в виде строки, которая выглядит следующим образом:

a + b

И вы должны вывести:

ab

Конечно, ваша программа или функция должна поддерживать число произвольной длины (до строки или входного предела вашего языка) с любым из операторов +, -или *. Еще несколько примеров:

Входные данные:

ab + bd

Выход:

acd

Входные данные:

d - ab

Выход:

ac

Входные данные:

ab * cd

Выход:

cf

Заметки:

  • Порядок букв в выходных данных не имеет значения, но вы всегда можете предположить, что порядок букв в цифрах на входе будет возрастать (от a до z).
  • Вы можете получить ввод с завершающей новой строкой и вывод с завершающей новой строкой.
  • Вы не можете принимать входные данные в виде списка ab, *и bdдля ab * bd.
  • Используется английский алфавит ( abcdefghijklmnopqrstuvwxyz)
  • Ваш вывод должен быть упрощен ( aaне разрешен, bтребуется)
  • Ввод будет упрощен ( b+ c, а не aa+ bbили aa+ aaaa)
  • Вам может потребоваться пробел до и оператор ( +, -или *), или вы можете потребовать, чтобы их не было.
  • Для каждого входа будет только один оператор.
  • Вы можете предположить, что вывод и ввод никогда не пройдут 2 ^ 27-1 ( abcdefghijklmnopqrstuvwxyz)
  • Это , поэтому выигрывает самый короткий ответ в байтах!

2
d is 2 positions later in the alphabet than cэто Райт? не должно ли это быть 1? That is added to the second row.в том же предложении, не так ли third?
Фелипе Нарди Батиста,

1
@FelipeNardiBatista здесь используется английский алфавит, отредактированный.
programmer5000

@ programmer5000 до сих пор, bc*de==efghно efghэто 240не144
Фелипе Nardi Батиста

1
bc*deдолжно бытьeh
Фелипе Нарди Батиста

@ Дада будет только один оператор на вход.
programmer5000

Ответы:


3

Желе , 26 25 байт

i@€Øað’2*S;ḟ.Ḣ
ḲÇ€VBṚTịØa

Использует операторы Jelly ( ×а не *и _вместо -) во входной строке, как это разрешено OP .

(Требуются места вокруг операторов)

Попробуйте онлайн! или посмотрите набор тестов

Как?

i@€Øað’2*S;ḟ.Ḣ - Link 1, transform from input sub-string to value or operator: sub-string
i@€            - 1st index of, for €ach (or 0 if not found) [reversed @rguments] in:
   Øa          -      lowercase alphabet (i.e. a->1, b->2, ..., non-alpha->0)
     ð         - dyadic chain separation i.e. f(result above, substring):
      ’        - decrement (i.e a->0, b->1, ..., non-alpha->-1)
       2*      - 2 raised to that power
         S     - sum
          ;    - concatenate with the substring
           ḟ   - filter out:
            .  -     0.5 (for an operator substring the evaluated 0.5 is removed)
             Ḣ - head (i.e. the evaluation for a location, and the operator otherwise)

ḲÇ€VBṚTịØa - Main link: string                        e.g. 'ab × cd'
Ḳ          - split on spaces                               [['a','b'],['×'],['c','d']]
 Ç€        - last link (1) as a monadic function for €ach  [3,'×',12]
   V       - evaluate as Jelly code                        36
    B      - convert to binary                             [1,0,0,1,0,0]
     Ṛ     - reverse                                       [0,0,1,0,0,1]
      T    - truthy indexes                                [3,6]
       ị   - index into:
        Øa -     lowercase alphabet                        ['c','f'] (i.e. "cf", which is implicitly printed when run as a full program)

7

Mathematica, 168 байт

FixedPoint[StringReplace[x_~~x_:>FromCharacterCode[c@x+1]],Table["a",ToExpression@StringReplace[#,x:LetterCharacter..:>ToString@Tr[2^((c=ToCharacterCode)@x-97)]]]<>""]&

Мое первоначальное решение (до того, как пост был отредактирован, чтобы уточнить, что вывод должен быть упрощен) было на 64байты короче:

Table["a",ToExpression@StringReplace[#,x:LetterCharacter..:>ToString@Tr[2^(ToCharacterCode@x-97)]]]<>""

Это просто изменило это решение для работы. Вероятно, на самом деле короче использовать методы, описанные в задании, но я все равно хотел это поднять.

Объяснение:

Заменяет каждую последовательность букв на соответствующее целое число с помощью арифметики кода символа, затем преобразует результирующую строку в выражение (которое автоматически упростится до целого числа), затем создает строку aсимволов длиной, равной этому целому числу, и, наконец, заменяет смежные идентичные символы с кодом следующего символа, пока не будет достигнута фиксированная точка.


2
О, нет встроенного 1-символа? Удивительно , !
programmer5000

7

JavaScript (ES6), 136 134 133 байта

Сохранено 1 байт благодаря Люку

s=>[...a='abcdefghijklmnopqrstuvwxyz'].filter((c,i)=>eval(s.replace(/\w+/g,s=>[...s].reduce((p,c)=>p|1<<a.search(c),0)))&1<<i).join``

Контрольные примеры


Красиво сделано! Вы победили меня в этом ...
programmer5000

Преобразует ли это в десятичную и обратно? Похоже, так.
programmer5000

1
@ programmer5000 Да, действительно. Я подозреваю, что многие ответы будут. (За исключением, конечно, Mathematica, которая, вероятно, имеет встроенный для него. ^^)
Арно

Похоже, ваш комментарий пропустил ссылку. Что имеет встроенный для этого?
programmer5000

@ programmer5000 (На самом деле, ему не хватало ни слова.)
Арно

5

Perl 5 , 95 байт

94 байта кода + -pфлаг.

s/\w/a x 2**(-97+ord$&)/ge;s/(.*)-\1|\+//;/\*/&&($_=$`x length$');1while s/(.)\1/chr 1+ord$1/e

Попробуйте онлайн!

Три шага здесь:
- s/\w/a x 2**(-97+ord$&)/ge;преобразует ввод в строку aтолько.
- s/(.*)-\1|+//;/*/&&($_=$`x length$')выполнит оператор (который очень прост для строк a): +это конкатенация, -означает удаление из первой части столько, aсколько имеется во второй части, и *означает дублирование первой части столько раз, сколько aво второй часть.
- 1while s/(.)\1/chr 1+ord$1/eскладывает последовательные одинаковые буквы в следующую букву в алфавите.


Единственный ответ, который не конвертируется в десятичную! Хорошая работа!
programmer5000

1
@ programmer5000 Из 2 ответов я бы не назвал это впечатляющим!
Дада

5

05AB1E , 29 байт

ð¡À¬U¦v0yvAyko+}}X.VbRvyiANèJ

Попробуйте онлайн! или как тестовый набор

объяснение

ð¡                             # split input on string
  À                            # rotate left
   ¬U¦                         # get the operator, store it in X and remove it from list
      v                        # for each side of the equation
       0                       # push 0 as an accumulator
        yv                     # for each letter in each side of the equation
          Ayk                  # get its index in the alphabet
             o                 # raise 2 to this power
              +                # add to the accumulator
               }}              # end loops
                 X.V           # apply the operator to the 2 numbers now on the stack
                    bR         # convert to binary and reverse
                      v        # for each binary digit
                       yi      # if it is true
                         ANè   # get the letter at that index in the alphabet
                            J  # join stack to a single string

5

C & x86 asm, 340 байт

Компилировать с -O0

#define G getchar()
g(){int c,a=0;for(;islower(c=G);)a+=1<<(c-97);return a;}
main(){short o[]={[43]=0x4403,[45]=0x442b,[42]=0x6cf7};
mprotect((long)&&l&~4095,4096,7);
for(;;){int c,b=0,a=g();*(short*)&&l=o[G];G;g();asm("xchg %%eax,%0":"+m"(a));
l:asm("addl %1,%%eax":"=a"(c):"m"(a));
for(;a=c>>b;b++)if(a&=1)putchar(97+b);putchar(10);}}

объяснение

Поскольку C не имеет eval(), я использовал вместо него таблицу инструкций x86. Я должен был выбрать инструкции, которые были бы одинаковой длины (или дополнены nops), и которые ожидали src и назначение тех же типов. Особую досаду вызвало то, что MUL может писать только в регистры, а однобайтовые коды операций MUL могут писать только в EAX. Кроме того, казалось, что не было инструкции SUB для записи в регистр, которая вычитала бы из памяти, а не наоборот, отсюда и XCHG.

редактировать

Поскольку это было задано в комментариях, более традиционная оценка будет выглядеть так:

#define G getchar()
#define return r
#define int i
g(){i c,a=0;for(;islower(c=G);)a+=1<<(c-97);r a;}
a(i x,i y){r x+y;}s(i x,i y){r x-y;}m(i x,i y){r x*y;}
main(){i(*o[])(i,i)={[43]=a,[45]=s,[42]=m};
for(;;){i c,b,a=g();b=G;G;g();c=o[b](a,g());
for(b=0;a=c>>b;b++)if(a&=1)putchar(97+b);putchar(10);}}

Это на самом деле немного короче, в 301 символах, по нескольким причинам: 1. Поскольку должно быть много функций, накладные расходы каждой из них можно сократить с помощью некоторых правил препроцессора. 2. Современный linux защищает от выполнения в стеке, поэтому вызов mprotect () отключает эти пожертвованные 34 байта. 3. Вызов XCHG очень неоптимален и стоит еще 30 байтов. Если бы не эти вещи, комбинация x86 выиграла бы примерно на 10-20 байтов.

Также отрезал 2 байта от обоих, улучшив вызов islower () в g.


Я не могу сказать, как это можно сравнить с более классическим подходом с точки зрения размера кода, но мне действительно нравится ваше решение. +1
Арно

5

GNU sed + coreutils, 329 байт

Да, я понятия не имею, что на меня нашло, но, по крайней мере, теперь я знаю, что писать сценарии sed немного лучше. Обратите внимание, что для этого решения требуется eрасширение GNU sed , которое запускает команду оболочки.

/\+/{s/\+//
b S}
/-/{:E
/a+-a+/{s/(a*)(a*)-\2/\1/
b S}
s/.*/echo &|tr b-z- A-Y-/
e
s/([A-Z])/\L\1\1/g
b E}
/\*/{h
:M
/^\*/{x
s/[^\n]*//
s/\n//g
b S}
s/(.).*\*(.*)/echo \2|tr a-z \1-za-z/
e
H
g
s/.(.*)/\1/
h
s/\n.*//
b M}
:S
s/^.*$/echo &|grep -o .|sort|tr -d '\n'/
e
:L
s/(.)\1/\u\1/g
/^[a-z]*$/ q
s/.*/echo &|tr A-Z b-za/;e
b L

Я предполагаю, что вокруг операторов не будет пробелов. Из моего терминала:

$ sed -rf golf.sed <<< a+b
ab
$ sed -rf golf.sed <<< ab+bd
acd
$ sed -rf golf.sed <<< abc+b
ad
$ sed -rf golf.sed <<< d-ab
ca
$ sed -rf golf.sed <<< ab*cd
cf
$ sed -rf golf.sed <<< bc*de
eh
$ sed -rf golf.sed <<< acd*def
deghj

И для тех, кто более здравый, чем я: закомментированная версия!

#!/bin/sed -rf

/\+/ {
    s/\+//
    b simplify
}

/-/ {
    # expand pattern space; everything will now be 'a's
    :E
    /a+-a+/{
        # Remove doubled 'a's on either side of the dash. For example,
        # for input d-ab, space is now 'aaaa-aaa'; substitute this to 'a'
        s/(a*)(a*)-\2/\1/
        b simplify
    }
    # shift letters that aren't 'a' down and double them
    s/.*/echo &|tr b-z- A-Y-/;e
    s/([A-Z])/\L\1\1/g
    b E
}

/\*/ {
    # Hold space: line 1 is pattern, other lines are output
    h
    :M

    # if space starts with *, we've eaten entire arg0; sum and simplify
    /^\*/ {
        x
        s/[^\n]*//      # remove first line, which is our pattern
        s/\n//g         # remove newlines to add results together
        b simplify
    }

    # convert pattern into shifting command
    s/(.).*\*(.*)/echo \2|tr a-z \1-za-z/

    # execute it, append result to hold space
    e
    H

    # restore pattern, with leading char and all output lines removed
    g
    s/.(.*)/\1/
    h
    s/\n.*//

    b M
}

:simplify
# reorder all letters so all 'a's are before all 'b's are before all 'c's
# are before ... etc    
# See /programming/2373874
s/^.*$/echo &|grep -o .|sort|tr -d '\n'/
e

:L
# Replace repeated characters with themselves upper-cased, then translate
# upper-cased characters to what they should be.
s/(.)\1/\u\1/g
/^[a-z]*$/ q
s/.*/echo &|tr A-Z b-za/;e
b L

+1 за код sed и добро пожаловать в PPCG! Соглашение здесь, когда не решается в чистом GNU sed (или в любом другом чистом языке), заключается в добавлении к заголовку используемых системных команд, например, таких как «GNU sed + coreutils», даже если вы упоминаете вызов команды оболочки в описании. , Это сделано для того, чтобы отличать, особенно в задачах с лидерами, от чистых ответов GNU sed.
Сешумара

Кроме того, за исключением флага 'f', необходимого каждый раз, любой другой флаг должен учитываться как 1 байт. Таким образом, ваш счет 329. Вы можете упомянуть это в описании. И в завершение вы можете подумать о добавлении ссылки на онлайн-переводчик sed, такой как TIO .
Сешумара

Чтобы не было всего разговоров и никаких действий, вот на 43 байта короче! версия вашего кода (286 байт, включая -r), которую я нашел, играя в гольф командами. Я уверен, что это может быть даже короче.
Сешумара

Ах, хорошо, приятно знать! Кроме того, приятно играть в гольф! Какую версию sed вы используете? Твой работает в TIO, но в GNU sed 4.4 я просто получаюsed: file golf.sed line 24: ":" lacks a label
charliegreen

Безымянный ярлык - это хорошо известная ошибка в GNU sed, которая была исправлена ​​в версии 4.3. Но на PPCG вы можете писать программы для любого варианта и версии sed, используя ошибки в качестве функций, если это помогает в игре в гольф. Различия между версиями слишком малы, чтобы их упоминать (4.2 против 4.4), но в названии должен быть указан вариант (стандартный POSIX sed против расширенного GNU sed) с упоминанием системных программ, которые называются, если таковые имеются.
Сешумара

4

PHP, 168

Выход по возрастанию с использованием eval

[$a,$o,$b]=explode(" ",$argn);function d($s){for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);return$n;}for(eval("\$k=d($a)$o d($b);");$i<26;)echo$k&2**$i++?chr(96+$i):"";

PHP, 185 байт

Выход по возрастанию

[$a,$o,$b]=explode(" ",$argn);function d($s){for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);return$n;}for(;$i<26;)echo(bc.[mul,add,0,sub][ord($o)-42])(d($a),d($b))&2**$i++?chr(96+$i):"";

Онлайн версия

расширенный

[$a,$o,$b]=explode(" ",$argn); # part the input into variables
function d($s){ # make decimal value
    for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);
    return$n;
}
for(;$i<26;)
echo(bc.[mul,add,0,sub][ord($o)-42])(d($a),d($b))&2**$i++?chr(96+$i):""; # Bitwise Compare and Output

PHP, 201 байт

Выход по убыванию

[$a,$o,$b]=explode(" ",$argn);function d($s){for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);return$n;}for($r=(bc.[mul,add,0,sub][ord($o)-42])(d($a),d($b));$r;$r-=2**$l)$t.=chr(97+$l=log($r,2)^0);echo$t;

Онлайн версия

расширенный

[$a,$o,$b]=explode(" ",$argn); # part the input into variables
function d($s){ # make decimal value
    for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);
    return$n;
}
for(
$r=(bc.[mul,add,0,sub][ord($o)-42])(d($a),d($b)) # result of the operation
;$r;
$r-=2**$l) # subtract the letter value 
$t.=chr(97+$l=log($r,2)^0); # find greatest letter
echo$t; # Output

4

Python 3 , 176 167 байт

i=lambda a:str(sum(1<<ord(i)-97for i in a))
def f(a):
 a,b,c=a.split();m=eval(i(a)+b+i(c));r=''
 while m:
  t=0
  while m>=2**t*2:t+=1
  r+=chr(97+t);m-=2**t
 return r

Попробуйте онлайн!

  • сэкономлено 9 байт: благодаря tutleman

1
Если я не ошибаюсь, вы можете сбрить два байта, заменив m>=2**(t+1)на m>=2**t*2, и пять байтов, заменив a=a.split();m=eval(i(a[0])+a[1]+i(a[2]))что-то вроде b,c,d=a.split();m=eval(i(b)+c+i(d)).
Тутлеман

1
Да, и еще два байта, заменив 2**(ord(i)-97)на 1<<ord(i)-97.
Тутлеман

1
Я поражен, насколько читаемо это решение по сравнению с другими решениями.
Оле Танге

Спасибо :). Но я думаю, что это также из-за того, что язык Python используется. Отступы увеличивают количество байтов, однако читаемые. ;)
officialaimm

2

PHP, 130

for($d=a;$e=$argn[$i++];)$e!=' '?$d!=b?$$d+=1<<ord($e)-97:$b=$e:++$d;eval("for(;\$j++<27;)echo($a$b$c>>\$j-1)&1?chr(96+\$j):'';");

расширенная версия:

for($d=a;$e=$argn[$i++];)       // for each char in the input
  $e!=' '?                      //   if space
    $d!=b?                      //     if not the operation
      $$d+=1<<ord($e)-97:       //       add 2^(char - 'a')
      $b=$e:                    //     else save operation
    ++$d;                       //   else increase "pointer"
eval("for(;\$j++<27;)           // for each bit in the output
        echo($a$b$c>>\$j-1)&1?  //   calulate the result and check the bit
          chr(96+\$j):          //     output corrosponding char
          '';                   //     output nothing
     ");

беги с php -R <code>.


1

AWK, 201 байт

BEGIN{RS="(.)"}n=index(V="abcdefghijklmnopqrstuvwxyz",RT){s+=2^--n}index("+-*",RT){a=s RT
s=0}END{RS="\n"
"(awk '$0="a s"'<<<1)"|getline v
for(j=26;j--;)if((s=v-2^j)>=0){v=s;c=substr(V,j+1,1)c}print c}

"(awk '$0="a s"'<<<1)"|getline vэто лучший способ, который я мог придумать, чтобы сделать evaluateв AWK. Возможно, я немного «обманываю», чтобы назвать это просто AWK, так как я выполняю команду, но, по крайней мере, команда тоже AWK:)

Я уверен, что упускаю какой-то способ уменьшить количество байтов, но я точно не вижу этого.

Использование довольно стандартно, например, введите код FILEи сделайте:

awk -f FILE <<< "bc + ab"

Обратите внимание, что пробелы не требуются, и любой неоперационный / не [аз] символ будет игнорироваться. Может быть расширен для работы с числами больше, чем "abcdefghijklmnopqrstuvwxyz", изменив цикл. Для деления просто добавьте /символ в строку операции :). Кроме того, будет печатать пустую строку, если result <= 0.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.