Mari kita lakukan aritmatika lokasi!


22

Dari artikel Wikipedia :

Aritmatika lokasi (Latin arithmeticæ localis) adalah sistem angka biner aditif (non-posisional), yang dieksplorasi John Napier sebagai teknik perhitungan dalam risalahnya Rabdology (1617), baik secara simbolis maupun pada kotak seperti papan catur.

Apa?

Angka lokasi adalah cara penulisan angka menggunakan huruf alfabet.

Notasi biner belum distandarisasi, sehingga Napier menggunakan apa yang disebutnya angka lokasi untuk mewakili angka biner. Sistem Napier menggunakan notasi nilai-tanda untuk mewakili angka; menggunakan huruf berturut-turut dari alfabet Inggris untuk mewakili kekuatan dua: berturut-turut: a = 2 ^ 0 = 1, b = 2 ^ 1 = 2, c = 2 ^ 2 = 4, d = 2 ^ 3 = 8, e = 2 ^ 4 = 16 dan seterusnya.

Sebuah contoh

ab = 1 + 2 = 3 pada basis 10

aabb = 1 + 1 + 2 + 2 = 6 di basis 10

Catatan yang aabbdapat disingkat menjadi bcdengan mengganti 2 contoh surat dengan yang lebih tinggi.

Tambahan

Anda baru saja menggabungkan dua angka dan menyederhanakan.

acd+ bde= acdbde= abcdde= acebe= abcf= 39pada basis 10

Pengurangan

Hapus saja semua digit yang tampak sama di kedua bagian pengurangan. Perluasan (konversi bke aa) mungkin diperlukan

abde- ad= be= 18 dalam basis 10

Perkalian

Ini agak sulit.

Katakanlah kita ingin mengalikan acd(13) dengan def(56). Pertama Anda mengatur acdsecara vertikal:

a
c
d

Kemudian Anda tambahkan defsetelah yang pertama a:

a def
c
d

Sekarang, c adalah 2 posisi kemudian dalam abjad dari, jadi kita tambahkan 2 posisi dalam alfabet untuk defuntuk membuat fgh. Itu ditambahkan ke baris kedua.

a def
c fgh
d

Terakhir, d adalah 1 posisi kemudian dalam alfabet dari c, jadi kami menambahkan 1 posisi dalam alfabet fghuntuk dibuat ghi. Itu ditambahkan ke baris ketiga.

a def
c fgh
d ghi

Kemudian Anda mengambil jumlah dari kanan: def+ fgh+ ghi= deffgghhi= deggghhi= deghhhi= deghii= deghj(728)

Contoh lain dari perkalian

Memasukkan:

bc * de

Pertama:

b
c

Kemudian

b ef
c 

Kemudian

b ef
c fg

Perhatikan bahwa kami menulis efdi baris pertama. Itu karena bcdimulai dengan b, dan bmerupakan huruf kedua dalam alfabet, jadi kita perlu beralih dedengan 1 huruf, jadi itu menjadi ef.

Kemudian

ef+fg

Keluaran:

eh

Divisi

Ini bukan bagian dari tantangan ini, karena ini bisa menjadi sangat kompleks.

Tantangan Anda yang sebenarnya

Program atau fungsi Anda harus mengambil input sebagai string yang terlihat seperti ini:

a + b

Dan Anda harus menampilkan:

ab

Tentu saja, program atau fungsi harus mendukung nomor panjang sewenang-wenang (sampai string atau masukan batas bahasa Anda) dengan salah satu operator +, -atau *. Beberapa contoh lagi:

Memasukkan:

ab + bd

Keluaran:

acd

Memasukkan:

d - ab

Keluaran:

ac

Memasukkan:

ab * cd

Keluaran:

cf

Catatan:

  • Urutan huruf dalam output tidak masalah, tetapi Anda selalu dapat mengasumsikan bahwa urutan huruf dalam angka dalam input akan naik (sebelum z).
  • Anda dapat mengambil input dengan trailing newline dan output dengan trailing newline.
  • Anda mungkin tidak mengambil input sebagai daftar ab, *dan bduntuk ab * bd.
  • Alfabet bahasa Inggris digunakan ( abcdefghijklmnopqrstuvwxyz)
  • Output Anda harus disederhanakan ( aatidak diizinkan, bdiperlukan)
  • Input akan disederhanakan ( b+ c, bukan aa+ bbatau aa+ aaaa)
  • Anda mungkin memerlukan ruang sebelum dan operator ( +, -, atau *), atau Anda mungkin memerlukan ada menjadi tidak ada.
  • Hanya akan ada satu operator per input.
  • Anda dapat berasumsi bahwa output dan input tidak akan pernah melebihi 2 ^ 27-1 ( abcdefghijklmnopqrstuvwxyz)
  • Ini , jadi jawaban tersingkat dalam byte menang!

2
d is 2 positions later in the alphabet than capakah ini wright? bukankah seharusnya begitu 1? That is added to the second row.pada kalimat yang sama, bukankah begitu third?
Felipe Nardi Batista

1
@FelipeNardiBatista alfabet bahasa Inggris digunakan di sini, diedit.
programmer5000

@ programmer5000 masih, bc*de==efghtapi efghini 240tidak144
Felipe Nardi Batista

1
bc*deseharusnyaeh
Felipe Nardi Batista

@Dada hanya akan ada satu operator per input.
programmer5000

Jawaban:


3

Jelly , 26 25 byte

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

Menggunakan operator Jelly ( ×bukan *dan _bukan -) dalam string input sebagaimana diizinkan oleh OP .

(Membutuhkan ruang di sekitar operator)

Cobalah online! atau lihat test suite

Bagaimana?

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 byte

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

Solusi awal saya (sebelum posting diedit untuk mengklarifikasi bahwa output harus disederhanakan) adalah 64byte lebih pendek:

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

Ini hanya mengubah solusi itu agar berfungsi. Mungkin lebih pendek untuk benar-benar menggunakan metode yang dijelaskan dalam tantangan, tetapi saya tetap ingin menerapkannya.

Penjelasan:

Mengganti setiap urutan huruf dengan integer yang sesuai dengan kode karakter aritmatika, kemudian mengubah string yang dihasilkan menjadi ekspresi (yang secara otomatis akan menyederhanakan menjadi integer), kemudian menghasilkan string akarakter dengan panjang sama dengan integer itu, dan akhirnya menggantikan identik yang berdekatan karakter dengan kode karakter berikutnya hingga titik tetap tercapai.


2
Oh, tidak ada built-in 1-char? Mengejutkan!
programmer5000

7

JavaScript (ES6), 136 134 133 byte

Disimpan 1 byte berkat Luke

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

Uji kasus


Bagus sekali! Anda mengalahkan saya untuk itu ...
programmer5000

Apakah ini dikonversi menjadi desimal dan kembali? Tampaknya begitu.
programmer5000

1
@ programmer5000 Ya memang. Saya menduga banyak jawaban akan. (Kecuali tentu saja Mathematica, yang mungkin memiliki bawaan untuk itu. ^^)
Arnauld

Sepertinya komentar Anda tidak memiliki tautan. Apa yang sudah ada di dalamnya?
programmer5000

@ programmer5000 (Bahkan, itu tidak ada kata.)
Arnauld

5

Perl 5 , 95 byte

94 byte kode + -pbendera.

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

Cobalah online!

Tiga langkah di sini:
- s/\w/a x 2**(-97+ord$&)/ge;Mengkonversi input menjadi string asaja.
- s/(.*)-\1|+//;/*/&&($_=$`x length$')akan mengeksekusi operator (yang sangat sederhana pada string a): +adalah rangkuman, -berarti melepaskan dari bagian pertama sebanyak yang aada di bagian kedua, dan *berarti menduplikasi bagian pertama sebanyak yang ada adi bagian kedua bagian.
- 1while s/(.)\1/chr 1+ord$1/emelipat huruf yang sama berturut-turut menjadi huruf berikutnya dalam alfabet.


Satu-satunya jawaban yang tidak dikonversi menjadi desimal! Pekerjaan yang baik!
programmer5000

1
@ programmer5000 Dari 2 jawaban, saya tidak akan menyebut itu mengesankan!
Dada

5

05AB1E , 29 byte

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

Cobalah online! atau sebagai Test suite

Penjelasan

ð¡                             # 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 Bytes

Kompilasi dengan -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);}}

Penjelasan

Karena C tidak punya eval() , saya menggunakan tabel instruksi x86 sebagai gantinya. Saya harus memilih instruksi yang panjangnya sama (atau diisi dengan nops), dan yang diharapkan src dan tujuan dari jenis yang sama. Yang sangat mengganggu adalah bahwa MUL hanya dapat menulis ke register, dan opcode MUL 1-byte hanya dapat menulis ke EAX. Selain itu, sepertinya tidak ada instruksi SUB register-writing yang dikurangi dari memori, bukan sebaliknya, maka XCHG.

sunting

Karena ditanya dalam komentar, penilaian yang lebih tradisional akan terlihat seperti ini:

#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);}}

Ini sebenarnya sedikit lebih pendek, pada 301 karakter, karena beberapa alasan: 1. Karena harus ada banyak fungsi, overhead masing-masing dapat dipotong dengan beberapa aturan preprosesor. 2. Linux modern melindungi dari eksekusi pada stack, sehingga panggilan mprotect () untuk menonaktifkan 34 byte ini dikorbankan. 3. Panggilan XCHG sangat sub-optimal, dengan biaya 30 byte lagi. Jika bukan karena hal-hal itu, kombo x86 akan menang sekitar 10-20 byte.

Juga cincang 2 byte dari keduanya dengan meningkatkan panggilan islower () di g.


Saya benar-benar tidak tahu bagaimana ini akan dibandingkan dengan pendekatan yang lebih klasik dalam hal ukuran kode, tapi saya sangat suka solusi Anda. +1
Arnauld

5

GNU sed + coreutils, 329 bytes

Ya, saya tidak tahu apa yang merasuki saya, tapi setidaknya saya tahu skrip sedikit lebih baik sekarang. Perhatikan bahwa solusi ini memerlukan eekstensi sed GNU , yang menjalankan perintah shell.

/\+/{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

Saya berasumsi bahwa tidak akan ada ruang di sekitar operator. Dari terminal saya:

$ 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

Dan, bagi mereka yang lebih waras daripada saya: versi komentar!

#!/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 untuk kode sed dan selamat datang di PPCG! Konvensi di sini ketika tidak menyelesaikan dalam sed GNU murni (atau dalam bahasa murni lainnya), adalah untuk menambah judul perintah sistem yang digunakan, seperti "GNU sed + coreutils" misalnya, bahkan jika Anda menyebutkan memanggil perintah shell dalam deskripsi . Hal ini dilakukan untuk membedakan, terutama dalam tantangan dengan dewan pimpinan, dari jawaban murni GNU.
seshoumara

Selain itu, kecuali untuk bendera 'f' yang diperlukan setiap saat, bendera lain harus dihitung sebagai 1 byte. Jadi skor Anda adalah 329. Anda mungkin ingin menyebutkannya dalam deskripsi. Dan untuk penyelesaiannya, Anda mungkin berpikir untuk menambahkan tautan ke juru bahasa online, seperti TIO .
seshoumara

Untuk tidak semua pembicaraan dan tidak ada tindakan, di sini adalah 43 byte lebih pendek! versi kode Anda (286 bytes termasuk -r), yang saya temukan dengan memasukkan perintah. Saya yakin itu bisa lebih pendek.
seshoumara

Ah, baiklah, senang tahu! Juga, bermain golf bagus! Versi sed apa yang Anda gunakan? Hormat saya bekerja di TIO, tetapi di GNU sed 4.4 saya baru saja mendapatkansed: file golf.sed line 24: ":" lacks a label
charliegreen

Label tanpa nama adalah bug yang terkenal di GNU sed, yang diperbaiki di versi 4.3. Tetapi pada PPCG, Anda dapat menulis program untuk segala varian dan versi, menggunakan bug sebagai fitur jika itu membantu dalam bermain golf. Perbedaan antara versi terlalu kecil untuk disebutkan (4.2 vs 4.4), tetapi varian (standar POSIX vs GNU sed diperluas) perlu ditentukan dalam judul, dengan menyebutkan program sistem yang disebut, jika ada.
seshoumara

4

PHP, 168

Output Naik dengan menggunakan 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 Bytes

Output Naik

[$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):"";

Versi Online

Diperluas

[$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 Bytes

Output Decending

[$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;

Versi Online

Diperluas

[$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 byte

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

Cobalah online!

  • disimpan 9 byte: Terima kasih kepada tutleman

1
Kecuali saya salah, Anda bisa mencukur habis dua byte dengan mengganti m>=2**(t+1)dengan m>=2**t*2, dan lima byte dengan mengganti a=a.split();m=eval(i(a[0])+a[1]+i(a[2]))dengan sesuatu seperti b,c,d=a.split();m=eval(i(b)+c+i(d)).
Tutleman

1
Oh, dan dua lagi byte dengan mengganti 2**(ord(i)-97)dengan 1<<ord(i)-97.
Tutleman

1
Saya kagum betapa mudahnya solusi ini dibandingkan dengan solusi lain.
Ole Tange

Terima kasih :). Tapi saya pikir itu juga karena python menjadi bahasa yang digunakan. Lekukan itu membuat jumlah byte bertambah, bagaimanapun terbaca. ;)
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):'';");

versi yang diperluas:

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

jalankan bersama php -R <code>.


1

AWK, 201 byte

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 vadalah cara terbaik yang bisa saya lakukan untuk melakukan evaluatein AWK. Saya mungkin "curang" sedikit untuk menyebut ini adil AWK, karena saya mengeksekusi perintah, tetapi setidaknya perintah juga AWK:)

Saya yakin saya kehilangan beberapa cara untuk mengurangi byte-count, tapi saya yakin tidak bisa melihatnya.

Penggunaan cukup standar, misalnya memasukkan kode FILEdan lakukan:

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

Perhatikan bahwa spasi tidak diperlukan dan karakter non-op / non [az] akan diabaikan secara diam-diam. Dapat diperluas untuk bekerja dengan angka yang lebih besar dari "abcdefghijklmnopqrstuvwxyz" dengan mengubah loop. Untuk melakukan pembagian, cukup tambahkan /karakter ke string operasi :). Juga, akan mencetak baris kosong jika result <= 0.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.