Konverter biner ke desimal


32

Konverter biner ke desimal

Sejauh yang saya lihat, kami tidak memiliki tantangan konversi biner sederhana ke desimal.


Tulis program atau fungsi yang mengambil bilangan bulat biner positif dan mengeluarkan nilai desimalnya.

Anda tidak diperbolehkan menggunakan fungsi konversi basis bawaan apa pun. Fungsi integer-ke-desimal (mis., Fungsi yang berubah 101010menjadi [1, 0, 1, 0, 1, 0]atau "101010") dikecualikan dari aturan ini dan karenanya diizinkan.

Aturan:

  • Kode harus mendukung angka biner hingga nilai numerik tertinggi yang didukung bahasa Anda (secara default)
  • Anda dapat memilih untuk memiliki nol di depan dalam representasi biner
  • Output desimal mungkin tidak memiliki nol di depan.
  • Format input dan output adalah opsional, tetapi tidak ada pemisah antara digit. (1,0,1,0,1,0,1,0)bukan format input yang valid, tetapi keduanya 10101010dan (["10101010"])sedang.
    • Anda harus mengambil input ke arah "normal". 1110adalah 14tidak 7.

Kasus uji:

1
1

10
2

101010
42

1101111111010101100101110111001110001000110100110011100000111
2016120520371234567

Tantangan ini terkait dengan beberapa tantangan lain, misalnya ini , ini dan ini .



Apakah hasilnya harus ditandatangani atau dapatkah itu ditandatangani? Juga, jika bahasa saya secara otomatis beralih antara bilangan bulat 32-bit dan 64-bit tergantung pada panjang nilainya, dapatkah outputnya ditandatangani di kedua rentang? Misalnya- Ada dua nilai biner yang akan dikonversi menjadi desimal -1( 32 1'sdan 64 1's)
susu

Juga, dapatkah outputnya mengambang, apakah perlu integer?
Carcigenicate

@Carcigenicate Ini harus berupa bilangan bulat, tetapi bisa dari tipe data apa pun. Selama round(x)==xAnda baik-baik saja :) 2.000diterima untuk 10.
Stewie Griffin

Oh manisnya. Terima kasih.
Carcigenicate

Jawaban:


56

Jelly , 5 byte

DḤ+¥/

Cobalah online!

Penjelasan

masukkan deskripsi gambar di sini

Pemeran

  • Dadalah monad (fungsi argumen tunggal): digit, berubah 1234menjadi [1, 2, 3, 4].

  • adalah monad yang menggandakan argumen tunggal.

  • + adalah angka dua (fungsi dua argumen) yang menambahkan argumen kiri dan kanannya.

Dari sana, itu menjadi sedikit rumit.

Inilah yang terjadi pada waktu parse

  • D,, dan +dibaca. Rantai itu terlihat seperti [D, Ḥ, +].

  • Dua karakter berikutnya adalah quicks , yang bertindak seperti operator postfix parse-time pada tautan (fungsi) yang telah kita baca sejauh ini.

  • Ketika ¥dibaca, dua tautan terakhir akan muncul dan diganti oleh tautan yang bertindak seperti angka dua yang dibentuk dengan menyusunnya. Jadi sekarang rantai itu seperti [D, dyad(Ḥ+)].

  • Ketika /dibaca, tautan terakhir (yang seharusnya menjadi angka dua) akan muncul dan digantikan oleh monad yang melipat menggunakan angka dua ini (secara intuitif: f/mengambil daftar, mengganti koma di dalamnya dengan f, dan mengevaluasi hasilnya.)

  • Rantai terakhir terlihat seperti [D, fold(dyad(Ḥ+))], dua monad.

Inilah yang terjadi pada saat run time

  • Input (angka) secara implisit membaca ke dalam nilai kerja (katakanlah, 101010).

  • Ddieksekusi, mengganti nilai kerja dengan digitnya ( [1,0,1,0,1,0]).

  • fold(dyad(Ḥ+))dieksekusi, menggantikan nilai kerja dengan 1∗0∗1∗0∗1∗0, di mana angka dua itu Ḥ+.

Jadi apa yang x∗ydievaluasi?

  • Dalam definisi diadik, nilai kerja pada awalnya adalah argumen kirix ,.

  • , Yang ganda monad, ganda nilai ini. Nilai kerja sekarang 2x.

  • +, ditambah angka dua, tidak memiliki argumen yang benar, jadi ini adalah sebuah kait : pola sintaksis khusus di mana argumen yang tepat dari angka dua ini akan disuntikkan ke +. Ini menghasilkan 2x + ysebagai nilai kerja akhir, yang dikembalikan.

Jadi seluruh ekspresi dievaluasi menjadi:

1∗0∗1∗0∗1∗0 = 2×(2×(2×(2×(2×1+0)+1)+0)+1)+0
            = 32×1 + 16×0 + 8×1 + 4×0 + 2×1 + 1×0
            = 42

10
Penjelasan Anda menjadi lebih baik dan lebih baik :-)
Luis Mendo

2
Heh, saya kira Anda melakukannya mulai sekarang? Itu luar biasa, +1.
Erik the Outgolfer

4
Saya pikir ini adalah bagian pertama dari Jelly yang pernah saya mengerti. +1!
Biru

Bravo. Saya benar-benar mengerti apa yang saya pikir awalnya hanya kekacauan karakter yang tampaknya acak. Penjelasan yang luar biasa.
swinefish

1
@ Mark Jelly memiliki codepage sendiri untuk membuat program terlihat, ahem, dapat dibaca, tetapi program-program itu bisa juga hanya bytestrings.
Lynn

20

Python 2, 49 37 31 30 Bytes

Sekarang ini akan mengambil angka biner dalam representasi desimal, karena Python dapat menangani bilangan bulat besar yang sewenang-wenang.

b=lambda n:n and n%2+2*b(n/10)

terima kasih kepada xnor untuk menyimpan byte :)

Cara termudah untuk melihat bagaimana ini bekerja adalah dengan melihat rumus dasar untuk mengubah biner menjadi desimal:

= 101010 
= 1*(2^5) + 0*(2^4) + 1*(2^3) + 0*(2^2) + 1*(2^1) + 0*(2^0)
= 1*32 + 0*16 + 1*8 + 0*4 + 1*2 + 0*1
= 42

Ini adalah cara konversi yang 'standar'. Anda dapat memperluas baris ketiga seperti:

= ((((1*2 + 0)*2 + 1)*2 + 0)*2 + 1)*2 + 0

Dan pada dasarnya inilah yang dilakukan metode rekursif yang saya lakukan.

Solusi alternatif yang saya miliki:

b=lambda n:n and n%10+2*b(n/10)
b=lambda n:n%10+2*(n and b(n/10))
b=lambda n:0if n<1else n%10+2*b(n/10)
b=lambda n:0**(n/10)or n%10+2*b(n/10)
b=lambda n,o=0:o*(n<'0')or b(n[1:],2*o+int(n[0]))
lambda j:sum(int(b)*2**a for a,b in enumerate(j,1))

6
Anda dapat melakukan n%5atau n%2bukannya n%10.
xnor

@xnor Ah, tidak yakin bagaimana saya melewatkan itu! Terima kasih :)
Kade

12

05AB1E , 6 byte

Kode:

$¦v·y+

Untuk penjelasannya, mari kita ambil contoh 101010 . Kita mulai dengan angka 1 (yang diwakili oleh digit pertama). Setelah itu, kami memiliki dua kasus:

  • Jika digit adalah 0 , kalikan angkanya dengan 2.
  • Jika digit adalah 1 , kalikan angkanya dengan 2 dan tambahkan 1.

Jadi untuk kasus 101010 , berikut ini dihitung:

  • 1 01010, mulai dengan angka 1 .
  • 1 0 1010, kalikan dengan dua, menghasilkan 2 .
  • 10 1 010, kalikan dua dan tambahkan satu, menghasilkan 5 .
  • 101 0 10, kalikan dengan dua, menghasilkan 10 .
  • 1010 1 0, kalikan dengan dua dan tambahkan satu, menghasilkan 21 .
  • 10101 0 , kalikan dua, menghasilkan 42 , yang merupakan hasil yang diinginkan.

Penjelasan kode:

$         # Push 1 and input
 ¦        # Remove the first character
  v       # For each character (starting with the first)
   ·      #   Multiply the carry number by two
    y+    #   Add the current character (converted automatically to a number)

Menggunakan pengkodean CP-1252 . Cobalah online!


Yang bagus! (tidak bekerja untuk 0 meskipun saya baru saja memperhatikan)
Emigna

@Emigna Yap, untungnya kode Anda hanya perlu bekerja untuk angka biner positif.
Adnan

Bahkan tidak melihat bagian itu. Sangat bagus kalau begitu :)
Emigna

9

Haskell, 16 111 + 57 = 168 byte

import Data.String
instance IsString[Int]where fromString=map((-48+).fromEnum)
f::[Int]->Int
f=foldl1((+).(2*))

+57 byte untuk flag kompilasi -XOverloadedStrings, -XOverlappingInstancesdan -XFlexibleInstances.

Tantangannya memiliki beberapa format IO yang rumit , karena sangat tergantung pada bagaimana tipe data diekspresikan dalam kode sumber. Versi pertama saya (16 byte), yaitu

foldl1((+).(2*))

mengambil daftar bilangan bulat, misalnya [1,0,1,0,1,0]dan dinyatakan tidak valid karena daftar Haskell literal terjadi di ,antara elemen-elemen. Daftar per se tidak dilarang. Dalam versi baru saya, saya menggunakan fungsi yang sama, sekarang dinamai f, tetapi saya membebani "Kutipan urutan karakter terlampir". Fungsi masih mengambil daftar bilangan bulat seperti yang Anda lihat dalam anotasi jenis [Int] -> Int, tetapi daftar dengan bilangan bulat tunggal sekarang dapat ditulis seperti "1234", misalnya

f "101010"

yang dievaluasi menjadi 42. Sial, Haskell, karena format daftar asli tidak sesuai dengan aturan tantangan. Btw, f [1,0,1,0,1,0]masih berfungsi.


2
Sayangnya daftar bukanlah input yang valid.
Jonathan Allan

@ JonathanAllan: Kenapa? Dan jika demikian, bagaimana seharusnya mengambil input sama sekali? Dalam Haskell string hanya daftar karakter.
nimi

Saya tidak tahu mengapa ... tapi saya menanyakan hal ini sejak awal dan sebuah suntingan dibuat untuk menambahkan " (1,0,1,0,1,0,1,0)bukan format input yang valid, tetapi keduanya 10101010dan (["10101010"])sedang." lebih jauh lagi sebuah komentar menunjukkan array karakter dapat diterima jika itu adalah bagaimana input string ditafsirkan.
Jonathan Allan

1
@ JonathanAllan: "biner integer" (input yang harus kita ambil) terpisah secara inheren, ini adalah urutan kekuatan 2. Pembatasannya adalah tentang pemisah eksplisit (antara digit) dan bukan tentang pemisahan. Entah bagaimana saya harus mengambil angka yang terpisah.
nimi

2
Op di sini: jika memungkinkan untuk memasukkan 10101010, "10101010"atau sesuatu yang serupa dan membuatnya berfungsi maka pengajuan tersebut valid. Anda dapat menyebutnya string, daftar, integer atau apa pun. Memasukkan [1][0][1][0]atau [1,0,1,0]tidak ok. Pada dasarnya, itu mungkin untuk hanya menekan sekelompok yang dan nol berturut-turut di suatu tempat. Apakah ini jelas?
Stewie Griffin

7

Retina, 15 byte

Mengubah dari biner ke unary, lalu unary ke desimal.

1
01
+`10
011
1

Cobalah online


Anda tidak diperbolehkan menggunakan fungsi konversi basis bawaan apa pun. ~ OP
Roman Gräf

10
@ RomanGräf Tidak ada. Saya hanya menggambarkan proses solusi saya.
mbomb007

7

PHP, 44 byte

for(;""<$c=$argv[1][$i++];)$n+=$n+$c;echo$n;

Saya bersumpah bahwa saya pernah melihat pertanyaan itu sebelumnya. Tapi baiklah.

Membaca angka dari kiri ke kanan, bergeser ke kiri dan menambahkan bit saat ini.


7

JavaScript (ES6), 33 31 byte

s=>[...s].map(c=>r+=+c+r,r=0)|r

Sunting: Lebih pendek tapi kurang manis: 2 byte disimpan berkat @ETHproduksi.


Seperti yang sering terjadi, .maplebih pendek:s=>[...s].map(c=>+c+r+r,r=0)|r
ETHproduksi

@ ETHproductions Bagaimana fungsi Anda mengembalikan apa pun selain 0?
Neil

Maaf, seharusnyas=>[...s].map(c=>r+=+c+r,r=0)|r
ETHproductions

7

Labirin , 17 15 byte

-+:
8 +
4_,`)/!

Cobalah online!

Gambar kode

Labyrinth adalah bahasa dua dimensi, berbasis stack. Di labirin, eksekusi kode mengikuti jalur kode seperti labirin dengan spasi yang bertindak sebagai dinding dan dimulai dengan karakter non-spasi paling kiri. Alur kode ditentukan oleh tanda bagian atas tumpukan. Karena tumpukan memiliki nol tersirat di bagian bawah, empat instruksi pertama ( -+:+) tidak berpengaruh.

Loop dimulai pada ,

  • , Dorong nilai kode ascii dari karakter input berikutnya ke stop stack, atau tekan -1 jika EOF.
  • _48 mendorong 48 ke atas tumpukan
  • -Pop y, pop x, push x-y. Instruksi sebelumnya memiliki efek mengurangi 48 dari input yang menghasilkan 0 untuk "0" dan 1 untuk "1".
  • +Pop y, pop x, push x+y.
  • : Gandakan bagian atas tumpukan
  • + Instruksi ini dan sebelumnya memiliki efek mengalikan nilai saat ini dengan 2

Jadi bagian melingkar dari kode, pada dasarnya, mengalikan angka saat ini dengan 2 dan menambahkan angka 1 atau 0 tergantung pada apakah karakter 1 atau 0 dimasukkan.

Ekor

Jika bagian atas tumpukan negatif (artinya EOF ditemukan), kode akan belok kiri di persimpangan (menuju tanda titik koma).

  • `` `Negasikan bagian atas tumpukan untuk mendapatkan 1
  • ) Tambahkan bagian atas tumpukan untuk mendapatkan 2
  • /Pop y, pop x, push x / y (pembagian integer). Ini memiliki efek membatalkan yang terakhir *2dari loop.
  • !Keluarkan representasi integer dari bagian atas tumpukan. Pada titik ini program berbalik karena menemui jalan buntu dan kemudian keluar dengan kesalahan karena mencoba untuk membaginya dengan nol.

Terima kasih kepada @Martin Ender karena telah menyelamatkan saya 2 byte (dan mengajari saya cara berpikir yang lebih baik di Labyrinth).


Alih-alih _48-Anda bisa melakukannya #%tetapi sayangnya saya tidak melihat bagaimana hal itu dapat membantu dengan jumlah byte.
Martin Ender

Anda dapat menyimpan byte dengan `)sebagai gantinya ;_2.
Martin Ender

@ MartinEnder, saya tidak mengerti komentar Anda tentang #%. Bisakah Anda menjelaskan cara kerjanya sebagai pengganti untuk _48-mengonversi dari ascii ke int. Terima kasih atas )tipnya. Saya akan melakukan perubahan itu.
Robert Hickman

Pada titik itu dalam program Anda, selalu ada dua nilai pada stack sehingga #hanya kependekan _2. Meskipun _2%bukan metode konversi umum untuk ASCII untuk integer, ini berfungsi di sini karena Anda hanya tertarik pada dua digit pertama sebagai input yang mungkin. Alternatifnya adalah _1&(karena modulo 2 hanya mengekstrak bit yang paling tidak signifikan).
Martin Ender

Oh Itu brilian. Tapi ya saya tidak yakin bagaimana cara menggunakan subtitusi itu ( #%) untuk mempersingkat kode secara keseluruhan.
Robert Hickman

6

Brain-Flak , 46 , 28 byte

([]){{}({}<>({}){})<>([])}<>

Cobalah online!

Banyak byte yang disimpan berkat @Riley!

Karena brain-flak tidak dapat mengambil input biner, input adalah daftar '0 dan' 1.

Penjelasan:

#Push the height of the stack
([])

#While true:
{

 #Pop the height of the stack
 {}

 #Push this top number to (the other stack * 2)
 ({}<>({}){})

 #Toggle back on to the main stack
 <>

 #Push the new height of the stack
 ([])

#endwhile
}

#Toggle back to the other stack, implicitly display.
<>

Sukai penjelasannya! Jadi sulit untuk membaca kritik tanpa itu :)
Emigna

2
^. Saya bahkan tidak bisa membaca program saya sendiri jika saya tidak meninggalkan diri saya beberapa komentar.
Riley

Anda dapat menurunkannya menjadi 32 byte dengan menghilangkan keseluruhan jika bagian, dan untuk langkah "tambahkan nomor ke tumpukan lain" cukup tambahkan ke (tumpukan lain) * 2. ([]){({}[()]<({}<>({}){})><>)}<>
Riley

Dan Anda dapat menyimpan 4 lainnya hanya dengan muncul di awal sementara dan mendorong ketinggian lagi di akhir. ([]){{}({}<>({}){})<>([])}<>
Riley

@Riley Ya ampun, itu jenius. Terima kasih banyak!
DJMcMayhem

6

Java, 84 79 46 48 byte

  • Versi 3.1

Diubah menjadi long/ 48 byte:

s->{long x=0;for(char c:s)x=c-48l+x*2;return x;}
  • Versi 3.0

Melakukan beberapa golf / 46 byte:

s->{int x=0;for(char c:s)x=c-48+x*2;return x;}
  • Versi 2.0

Terima kasih kepada @Geobits! / 79 byte:

s->{int i=Math.pow(2,s.length-1),j=0;for(char c:s){j+=c>48?i:0;i/=2;}return j;}
  • Versi 1.0

84 byte:

s->{for(int i=-1,j=0;++i<s.length;)if(s[i]>48)j+=Math.pow(2,s.length-i+1);return j;}

1
kira saya harus melakukan solusi berulang. lulz. pekerjaan bagus
Poke

Apakah tipe input Anda List <Character> atau String? Jika itu yang terakhir, saya tidak tahu Java8 bisa melakukan itu! Jika yang pertama adalah apakah diizinkan oleh tantangan?
Poke

sseharusnya char[]. Saya harap itu diizinkan ...
Roman Gräf

Apa jenis pengembalian di sini? Saya pikir itu harus panjang karena "Kode harus mendukung angka biner hingga nilai numerik tertinggi yang didukung bahasa Anda" per OP tetapi untuk nilai yang lebih kecil saya akan berpikir itu mengembalikan int
Poke

1
Mungkin baik pada tipe input per ini . Mungkin ingin mengambil hit 2 byte untuk output imo
Poke

4

Befunge-98, 12 byte

2j@.~2%\2*+

Cobalah online!

Membaca satu karakter sekaligus dari input, mengubahnya menjadi 0 atau 1 dengan mengambil nilainya modulo 2 (0 adalah karakter (48), 1 adalah karakter (49)), kemudian menggunakan algoritma biasa menggandakan nilai saat ini dan menambahkan digit baru setiap kali.

Bonus: Ini berfungsi dengan segala jenis string input, saya sudah mencoba beberapa saat sekarang untuk menemukan kombinasi input-> output yang lucu, tetapi saya tidak dapat menghasilkan apa-apa (sayangnya, "jawaban" = 46). Bisakah kamu?


LOL. Saya memainkan permainan yang sama dengan jawaban saya. Angka paling menarik yang bisa saya hasilkan adalah 666 .
James Holderness

Yang bagus! Saya belum berhasil menemukan sesuatu yang cocok untuk 666: D Akan jauh lebih mudah jika kapitalisasi berpengaruh pada nilai-nilai ...
Leo

@ James Holderness - Saya telah melakukan hal yang sama dan saya hanya menemukan 'theapeapear' untuk mengembalikan 366, milik Anda benar-benar bagus.
Teal pelican

4

Javascript (ES7) 41 40 36 byte

f=([c,...b])=>c?c*2**b.length+f(b):0

mengambil string sebagai input

Mencukur satu byte berkat produk ETH

f=([c,...b])=>c?c*2**b.length+f(b):0
document.write([
    f('101010'),
    f('11010'),
    f('10111111110'),
    f('1011110010110'),
].join("<br>"))


1
Asosiatifitas kanan-ke-kiri **aneh, tapi pekerjaan yang bagus menggunakannya di sini. 1<<b.lengthakan melakukan hal yang sama, tetapi akan membutuhkan tanda kurung agar tidak diuraikan sebagai (c*1)<<(b.length+...). Saya pikir Anda dapat menyimpan byte dengan menggantinya b[0]dengan b+b( lihat di sini ).
ETHproductions

4

C # 6, 85 37 36 byte

long b(long n)=>n>0?n%2+2*b(n/10):0;
  • Terima kasih kepada Kade karena telah menghemat 41 byte!
  • Mengubah ke C # 6 menyimpan 7 byte lagi.

Mungkin ini bisa memberikan inspirasi? ;)
Kade

@ Kade Tidak, terima kasih! Saya melihat jawaban Python yang menggunakan teknik yang sama pada saat yang sama dengan tautan: DI bisa menjadi lebih pendek dengan C # 6.
Yytsi


3

C, 53

v(char*s){int v=0,c;while(c=*s++)v+=v+c-48;return v;}

Sama seperti jawaban javascript saya

Ide Tes


Anda dapat menyimpan 4 byte dengan mendeklarasikan vdan csebagai variabel global (meskipun Anda harus mengubah nama v, karena sudah menjadi nama fungsi) seperti ini:w=0;c;v(char*s){while(c=*s++)w+=w+c-48;return w;}
Steadybox

@Steadybox bisa jadi w,c;tapi saya tidak ingin menggunakan global ketika jawabannya adalah fungsi (bahkan dalam kode-golf)
edc65

@Steadybox Globals juga default ke 0, sehingga Anda dapat menghapus =0.
algmyr

3

Perl, 25 byte

-3 byte terima kasih kepada @Dom Hastings.

24 byte kode + 1 byte untuk -pflag.

$\|=$&<<$v++while s/.$//

Untuk menjalankannya:

perl -pe '$\|=$&<<$v++while s/.$//' <<< 101010

Penjelasan:

$\|=$&<<$v++  # Note that: we use $\ to store the result
              # at first $v=0, and each time it's incremented by one
              # $& contains the current bit (matched with the regex, see bellow)
              # So this operation sets a $v-th bit of $\ to the value of the $v-th bit of the input
while         # keep doing this while...
s/.$//        #  ... there is a character at the end of the string, which we remove.
         # $\ is implicitly printed thanks to -p flag

3

Pushy , 10 byte

Mengambil input sebagai daftar 0/1 pada baris perintah: $ pushy binary.pshy 1,0,1,0,1,0.

L:vK2*;OS#

Algoritma benar-benar menunjukkan keindahan memiliki tumpukan kedua:

            \ Implicit: Input on stack
L:    ;     \ len(input) times do:
  v         \   Push last number to auxiliary stack
   K2*      \   Double all items
       OS#  \ Output sum of auxiliary stack

Metode ini berfungsi karena tumpukan akan digandakan stack length - nkali sebelum mencapai angka n, yang kemudian dibuang ke tumpukan kedua untuk nanti. Beginilah prosesnya untuk input 101010:

1: [1,0,1,0,1,0]
2: []

1: [2,0,2,0,2]
2: [0]

1: [4,0,4,0]
2: [2]

1: [8,0,8]
2: [2,0]

1: [16,0]
2: [2,0,8]

1: [32]
2: [2,0,8,0]

1: []
2: [2,0,8,0,32]

2 + 8 + 32 -> 42

3

Matlab, 30 Bytes

@(x)sum(2.^find(flip(x)-48)/2)

Kasing uji terakhir memiliki kesalahan pembulatan (karena double), jadi jika Anda membutuhkan presisi penuh:

@(x)sum(2.^uint64(find(flip(x)-48))/2,'native')

dengan 47 Bytes.


Saya tidak dapat menguji ini, tetapi saya percaya @(x)sum(2.^(find(flip(x)-48)-1))akan memberikan hasil yang benar untuk semua kasus selama 32 byte. flipbekerja seperti fliplrjika xsatu dimensi.
Stewie Griffin

Solusi bagus! Saya juga mengalami kesalahan pembulatan, terima kasih atas perbaikannya. Apa format x? Memanggil flip atau fliplr pada nomor hanya mengembalikan nomor itu.
MattWH

x adalah string biner, jadi sebut saja dengan f=@(x)..; f('1111001010').
Jonas

3

Retina , 12 byte

Hitungan byte mengasumsikan penyandian ISO 8859-1.

+%`\B
¶$`:
1

Cobalah online!

Solusi alternatif:

+1`\B
:$`:
1

Penjelasan

Ini mungkin akan lebih mudah dijelaskan berdasarkan versi saya yang lama, kurang golf, dan kemudian menunjukkan bagaimana saya mempersingkatnya. Saya dulu mengonversi biner menjadi desimal seperti ini:

^
,
+`,(.)
$`$1,
1

Satu-satunya cara yang masuk akal untuk membangun angka desimal di Retina adalah dengan menghitung banyak hal (karena Retina memiliki beberapa fitur yang memungkinkannya mencetak angka desimal yang mewakili jumlah). Jadi sebenarnya satu-satunya pendekatan yang mungkin adalah mengubah biner menjadi unary, dan kemudian menghitung jumlah digit unary. Baris terakhir menghitung, jadi yang pertama mengkonversi biner ke unary.

Bagaimana kita melakukannya? Secara umum, untuk mengkonversi dari daftar bit ke integer, kami menginisialisasi hasilnya 0dan kemudian pergi melalui bit dari yang paling signifikan, menggandakan nilai yang sudah kami miliki dan menambahkan bit saat ini. Misalnya, jika angka binernya adalah 1011, kami akan menghitung:

(((0 * 2 + 1) * 2 + 0) * 2 + 1) * 2 + 1 = 11
           ^        ^        ^        ^

Di mana saya telah menandai bit individu untuk kejelasan.

Trik untuk melakukan ini di unary adalah a) bahwa menggandakan berarti mengulangi angka dan b) karena kita menghitung 1s pada akhirnya, kita bahkan tidak perlu membedakan antara 0s dan 1s dalam proses. Ini akan menjadi lebih jelas dalam sedetik.

Apa yang dilakukan oleh program adalah bahwa ia pertama kali menambahkan koma ke awal sebagai penanda untuk berapa banyak input yang sudah kami proses:

^
,

Di sebelah kiri marker, kita akan memiliki nilai yang kita akumulasikan (yang diinisialisasi dengan benar ke representasi nol unary), dan kanan nilai akan menjadi bit berikutnya untuk diproses. Sekarang kami menerapkan substitusi berikut dalam satu lingkaran:

,(.)
$`$1,

Hanya dengan melihat ,(.)dan $1,, ini menggerakkan marker sedikit ke kanan setiap kali. Tapi kami juga menyisipkan $`, yang merupakan segalanya di depan marker, yaitu nilai saat ini, yang kami gandakan. Berikut adalah langkah-langkah individual saat memproses input 1011, di mana saya telah menandai hasil dari menyisipkan di $`atas setiap baris (kosong untuk langkah pertama):

,1011

1,011
 _
110,11
   ___
1101101,1
       _______
110110111011011,

Anda akan melihat bahwa kami telah mempertahankan dan menggandakan nol bersama dengan yang lainnya, tetapi karena kami mengabaikannya pada akhirnya, tidak masalah seberapa sering kami menggandakannya, selama jumlah 1s adalah benar. Jika Anda menghitungnya, ada beberapa 11, hanya yang kita butuhkan.

Sehingga menyisakan pertanyaan bagaimana cara memainkan golf ini hingga 12 byte. Bagian termahal dari versi 18-byte adalah harus menggunakan marker. Tujuannya adalah untuk menyingkirkan itu. Kami benar-benar ingin menggandakan awalan setiap bit, jadi ide pertama mungkin ini:

.
$`$&

Masalahnya adalah bahwa pergantian ini terjadi secara bersamaan, jadi bit pertama tidak menjadi dua kali lipat untuk setiap bit, tetapi hanya akan disalin sekali setiap kali. Untuk input yang 1011akan kami dapatkan (menandai yang dimasukkan $`):

 _ __ ___
1101011011

Kita masih perlu memproses input secara rekursif sehingga awalan pertama yang digandakan digandakan lagi oleh yang kedua dan seterusnya. Satu ide adalah menyisipkan spidol di mana-mana dan berulang kali menggantinya dengan awalan:

\B
,
+%`,
¶$`

Setelah mengganti setiap penanda dengan awalan untuk pertama kalinya, kita perlu mengingat di mana awal input itu, jadi kami juga memasukkan umpan baris dan menggunakan %opsi untuk memastikan bahwa berikutnya $`hanya mengambil hal-hal yang sesuai dengan umpan baris terdekat.

Ini berfungsi, tetapi masih terlalu lama (16 byte saat menghitung 1s di akhir). Bagaimana kalau kita membalikkan keadaan? Tempat-tempat di mana kita ingin menyisipkan marker diidentifikasi oleh \B(posisi di antara dua digit). Mengapa kita tidak memasukkan saja awalan ke posisi itu? Ini hampir berhasil, tetapi perbedaannya adalah bahwa dalam solusi sebelumnya, kami benar-benar menghapus satu penanda di setiap substitusi, dan itu penting untuk membuat proses berakhir. Namun, \Bbukan karakter tetapi hanya posisi, jadi tidak ada yang dihapus. Namun kita dapat menghentikannya\Bdari mencocokkan dengan memasukkan karakter non-digit ke tempat ini. Itu mengubah batas non-kata menjadi batas kata, yang setara dengan menghapus karakter penanda sebelumnya. Dan itulah yang dilakukan solusi 12-byte:

+%`\B
¶$`:

Hanya untuk kelengkapan, berikut adalah langkah-langkah pemrosesan 1011, dengan baris kosong setelah setiap langkah:

1
1:0
10:1
101:1

1
1:0
1
1:0:1
1
1:0
10:1:1

1
1:0
1
1:0:1
1
1:0
1
1:0:1:1

Sekali lagi, Anda akan menemukan bahwa hasil terakhir mengandung tepat 11 1detik.

Sebagai latihan untuk pembaca, dapatkah Anda melihat bagaimana ini secara umum dengan mudah ke pangkalan lain (untuk beberapa byte tambahan per kenaikan di pangkalan)?


2

T-SQL, 202 Bytes

DECLARE @b varchar(max)='1',@ int=1 declare @l int=LEN(@b)declare @o bigint=CAST(SUBSTRING(@b,@l,1)AS bigint)WHILE @<@l BEGIN SET @o=@o+POWER(CAST(SUBSTRING(@b,@l-@,1)*2AS bigint),@)SET @=@+1 END PRINT @o

2

PHP, 64 byte

foreach(str_split(strrev($argv[1]))as$k=>$v)$t+=$v*2**$k;echo$t;

Kami membalikkan angka biner kami, membaginya menjadi digit komponennya, dan menjumlahkannya berdasarkan posisi.


2

Utilitas Bash + GNU, 29 byte

sed 's/./2*&+/g;s/.*/K&p/'|dc

I / O via stdin / stdout.

The sedekspresi membagi up biner ke setiap digit dan membangun ekspresi RPN untuk dcmengevaluasi.


2

PowerShell v2 +, 55 byte

param($n)$j=1;$n[$n.length..0]|%{$i+=+"$_"*$j;$j*=2};$i

Terasa terlalu lama ... Sepertinya tidak bisa mengurangi golf - tips dihargai.

Penjelasan

param($n)$j=1;$n[$n.length..0]|%{$i+=+"$_"*$j;$j*=2};$i
param($n)$j=1;                                          # Take input $n as string, set $j=1
              $n[$n.length..0]                          # Reverses, also converts to char-array
                              |%{                  };   # Loop over that array
                                 $i+=+"$_"*$j;          # Increment by current value of $j times current digit
                                              $j*=2     # Increase $j for next loop iteration
                                                     $i # Leave $i on pipeline
                                                        # Implicit output

2

JavaScript (ES6), 32 byte

f=([...n])=>n+n&&+n.pop()+2*f(n)

Rekursi menghemat hari lagi! Meskipun parameterisasi tampaknya agak panjang ...


Karena ini adalah "argumen" tunggal, apakah [...n]perlu dikelilingi dalam tanda kurung?
Cyoce

@Cyoce Sayangnya, ya, atau JS melempar SyntaxError.
ETHproduksi

2

Mathematica, 27 13 11 byte

Fold[#+##&]

Menerima Listbit sebagai input (mis. {1, 0, 1, 1, 0}- Representasi biner dari angka dari Mathematica22 )


Menindaklanjuti dari komentar pada jawaban Greg, bagaimana "memisahkan semua digit pada input" bukan fungsi konversi basis?
Martin Ender

@ MartinEnder Saya menggunakannya seperti Charactersfungsi.
JungHwan Min

@ MartinEnder Sebenarnya, seperti yang terlihat pada jawaban @ nimi , saya hanya bisa menerima daftar 1s dan 0s karena itu adalah satu-satunya cara untuk mewakili angka biner di Mathematica , artinya saya tidak perlu IntegerDigitsdi tempat pertama.
JungHwan Min

Itu mengasumsikan bahwa basis 10 adalah representasi "alami" dari bilangan bulat. Nilai integer aktual tidak memiliki basis pilihan yang melekat padanya (saya kira Anda bisa mengatakan cara itu disimpan mungkin basis 256 atau bahkan mungkin basis 2 tapi itu detail implementasi). Hanya karena kita (biasanya) menggunakan basis 10 untuk menulis bilangan bulat integer tidak berarti nilai integer sudah ada di basis 10.
Martin Ender

@MartinEnder @ Lynn menggunakan kode JellyD , yang melakukan hal yang samaIntegerDigits
JungHwan Min

2

Clojure, 114 105 63 41 byte

V4: 41 byte

-22 byte berkat @cliffroot. Karena digitkarakter, dapat dikonversikan ke kode melalui int, kemudian memiliki 48 dikurangi dari itu untuk mendapatkan angka aktual. Peta juga diperhitungkan. Saya tidak tahu mengapa itu perlu.

#(reduce(fn[a d](+(* a 2)(-(int d)48)))%)

V3: 63 byte

(fn[s](reduce #(+(* %1 2)%2)(map #(Integer/parseInt(str %))s)))

-42 byte (!) Dengan mengintip jawaban lain. "Ritsleting" saya ternyata sangat naif. Alih-alih menaikkan 2 ke kekuatan tempat saat ini, lalu mengalikannya dengan digit saat ini dan menambahkan hasilnya ke akumulator, itu hanya mengalikan akumulator dengan 2, menambahkan pada digit saat ini, kemudian menambahkannya ke akumulator. Juga mengonversi fungsi pengurang menjadi makro untuk mengurangi sedikit.

Terima kasih kepada @nimi, dan @Adnan!

Tidak Disatukan:

(defn to-dec [binary-str]
  (reduce (fn [acc digit]
            (+ (* acc 2) digit))
          (map #(Integer/parseInt (str %)) binary-str)))

V2: 105 byte

#(reduce(fn[a[p d]](+ a(*(Integer/parseInt(str d))(long(Math/pow 2 p)))))0(map vector(range)(reverse %)))

-9 byte dengan membalikkan string jadi saya tidak perlu membuat rentang turun yang canggung.

V1: 114 byte

Yah, aku tentu saja tidak menang! Dalam pembelaan saya, ini adalah program pertama yang pernah saya tulis yang mengkonversi antara pangkalan, jadi saya harus belajar bagaimana melakukannya. Itu juga tidak membantu yang Math/powmengembalikan dua kali lipat yang memerlukan konversi dari, dan Integer/parseInttidak menerima karakter, sehingga digit harus dibungkus sebelum lewat.

#(reduce(fn[a[p d]](+ a(*(Integer/parseInt(str d))(long(Math/pow 2 p)))))0(map vector(range(dec(count %))-1 -1)%))

Ritsleting string dengan indeks turun yang mewakili nomor tempat. Mengurangi daftar yang dihasilkan.

Tidak Disatukan:

(defn to-dec [binary-str]
  (reduce (fn [acc [place digit]]
            (let [parsed-digit (Integer/parseInt (str digit))
                  place-value (long (Math/pow 2 place))]
              (+ acc (* parsed-digit place-value))))
          0
          (map vector (range (dec (count binary-str)) -1 -1) binary-str)))

#(reduce(fn[a b](+(* a 2)(-(int b)48)))0 %)versi yang ditingkatkan. Memindahkan mapbagian kode langsung ke reduce, mengubah metode parsing integer, membuat fungsi eksternal dengan sintaks steno lambda.
cliffroot

@cliffroot intbisa digunakan untuk mengurai !? Itu akan mengetuk seperti 10 byte dalam setiap tantangan yang saya lakukan di sini lol.
Carcigenicate

Oh, aku mengerti apa yang kamu lakukan. Mengambil kode ascii, lalu mengurangi untuk mendapatkan nilai. Saya kira ini hanya akan bekerja dalam keadaan tertentu saja. Oh well, terima kasih atas tipnya.
Carcigenicate

2

Perl, 21 19 16 + 4 = 20 byte

-4 byte terima kasih kepada @Dada

Jalankan dengan -F -p(termasuk ruang ekstra setelah F). Nilai pipa ke fungsi menggunakanecho -n

$\+=$_+$\for@F}{

Jalankan sebagai echo -n "101010" | perl -F -pE '$\+=$_+$\for@F}{'

Saya merasa ini cukup berbeda dari jawaban @ Dada yang pantas masuknya sendiri.

Penjelasan:

-F                              #Splits the input character by character into the @F array
-p                              #Wraps the entire program in while(<>){ ... print} turning it into
while(<>){$\+=$_+$\for@F}{print}
                   for@F        #Loops through the @F array in order ($_ as alias), and...
          $\+=$_+$\             #...doubles $\, and then adds $_ to it (0 or 1)...
while(<>){              }       #...as long as there is input.
                         {print}#Prints the contents of $_ (empty outside of its scope), followed by the output record separator $\

Ini menggunakan algoritme pilihan pribadi saya untuk konversi biner ke desimal. Diberi nomor biner, mulai akumulator Anda pada 0, dan lalui bitnya satu per satu. Gandakan akumulator setiap bit, lalu tambahkan bit itu sendiri ke akumulator Anda, dan Anda berakhir dengan nilai desimal. Ini bekerja karena setiap bit akhirnya menjadi dua kali lipat jumlah yang tepat untuk posisinya berdasarkan berapa banyak bit yang tersisa di angka biner asli.


Bahkan lebih pendek:perl -F -pE '$\+=$_+$\for@F}{'
Dada

Jujur saya tertawa betapa pendeknya ini sekarang. Terima kasih.
Gabriel Benamy

Ya, itu cukup rapi, bagus sekali!
Dada

2

R (32-bit), 64 Bytes

Input untuk fungsi harus diberikan sebagai karakter. Fungsi dasar R mendukung bilangan bulat 32-bit.

Memasukkan:

# 32-bit version (base)
f=function(x)sum(as.double(el(strsplit(x,"")))*2^(nchar(x):1-1))
f("1")
f("10")
f("101010")
f("1101111111010101100101110111001110001000110100110011100000111")

Keluaran:

> f("1")
[1] 1
> f("10")
[1] 2
> f("101010")
[1] 42
> f("1101111111010101100101110111001110001000110100110011100000111")
[1] 2.016121e+18

R (64-bit), 74 Bytes

Input untuk fungsi harus diberikan sebagai karakter. Paket bit64harus digunakan untuk integer 64-bit.

Memasukkan:

# 64-bit version (bit64)
g=function(x)sum(bit64::as.integer64(el(strsplit(x,"")))*2^(nchar(x):1-1))
g("1")
g("10")
g("101010")
g("1101111111010101100101110111001110001000110100110011100000111")

Keluaran:

> g("1")
integer64
[1] 1
> g("10")
integer64
[1] 2
> g("101010")
integer64
[1] 42
> g("1101111111010101100101110111001110001000110100110011100000111")
integer64
[1] 2016120520371234567

2
Anda dapat melakukan: el(strsplit(x,""))alih-alih strsplit(x,split="")[[1]]menyimpan beberapa byte.
Billywob

Terima kasih banyak! Khusus untuk elfungsi - saya tidak menyadarinya.
djhurio

2

Dyalog APL , 12 byte

(++⊢)/⌽⍎¨⍞

dapatkan input string

⍎¨ konversi setiap karakter ke angka

membalikkan

(... )/masukkan fungsi berikut di antara angka-angka

++⊢ jumlah argumen ditambah argumen yang benar


ngn mencukur 2 byte.


1

k, 8 byte

Metode yang sama dengan jawaban Haskell di atas.

{y+2*x}/

Contoh:

{y+2*x}/1101111111010101100101110111001110001000110100110011100000111b
2016120520371234567
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.