Konwerter binarny na dziesiętny


32

Konwerter binarny na dziesiętny

O ile widzę, nie mamy prostego wyzwania konwersji binarnej na dziesiętną.


Napisz program lub funkcję, która przyjmuje dodatnią liczbę całkowitą binarną i wypisuje swoją wartość dziesiętną.

Nie możesz używać żadnych wbudowanych podstawowych funkcji konwersji. Funkcje od liczb całkowitych do dziesiętnych (np. Funkcja, która zamienia się 101010w [1, 0, 1, 0, 1, 0]lub "101010") są wyłączone z tej reguły i dlatego są dozwolone.

Zasady:

  • Kod musi obsługiwać liczby binarne do najwyższej wartości liczbowej obsługiwanej przez język (domyślnie)
  • Możesz wybrać początkowe zera w reprezentacji binarnej
  • Dane dziesiętne mogą nie zawierać zer wiodących.
  • Formaty wejściowe i wyjściowe są opcjonalne, ale między cyframi nie może być żadnych separatorów. (1,0,1,0,1,0,1,0)nie jest poprawnym formatem wejściowym, ale oba są 10101010i (["10101010"])są.
    • Musisz przyjąć dane wejściowe w kierunku „normalnym”. nie 1110jest .147

Przypadki testowe:

1
1

10
2

101010
42

1101111111010101100101110111001110001000110100110011100000111
2016120520371234567

Wyzwanie to wiąże się z kilkoma innymi wyzwaniami, na przykład tym , tym i tym .



Czy wyjście musi być niepodpisane, czy może być podpisane? Ponadto, jeśli mój język automatycznie przełącza się między 32-bitowymi i 64-bitowymi liczbami całkowitymi w zależności od długości wartości, czy dane wyjściowe mogą być podpisywane w obu zakresach? Np. - Są dwie wartości binarne, które zostaną przekonwertowane na dziesiętne -1( 32 1'si 64 1's)
mleko

Czy dane wyjściowe mogą być zmienne, czy musi to być liczba całkowita?
Carcigenicate,

@Carcigenicate Musi to być liczba całkowita, ale może być dowolnego typu danych. O ile round(x)==xnic ci nie jest :) 2.000przyjmowane jest wyjście dla 10.
Stewie Griffin,

Och, słodko. Dzięki.
Carcigenicate

Odpowiedzi:


56

Galaretka , 5 bajtów

DḤ+¥/

Wypróbuj online!

Wyjaśnienie

enter image description here

Obsada

  • Dto monada (funkcja pojedynczego argumentu): cyfry zamieniają się 1234w [1, 2, 3, 4].

  • to monada, która podwaja swój pojedynczy argument.

  • + to diada (funkcja dwóch argumentów), która dodaje lewy i prawy argument.

Stamtąd robi się trochę trudniej.

Oto, co dzieje się w czasie analizy

  • D, i +są czytane. Łańcuch wygląda [D, Ḥ, +].

  • Kolejne dwa znaki to znaki szybkie , które działają jak operatory Postfix w czasie analizy na linkach (funkcjach), które czytaliśmy do tej pory.

  • Po ¥odczytaniu dwa ostatnie łącza są usuwane i zastępowane przez łącze, które działa jak diada utworzona przez ich skomponowanie. Więc teraz wygląda łańcuch [D, dyad(Ḥ+)].

  • Kiedy /jest czytany, ostatni link (który powinien być diadem) zostaje wysunięty i zastąpiony przez monadę, która składa się za pomocą tej diady (intuicyjnie: f/pobiera listę, zastępuje ją przecinkami fi ocenia wynik).

  • Ostatni łańcuch wygląda jak [D, fold(dyad(Ḥ+))]dwie monady.

Oto, co dzieje się w czasie wykonywania

  • Dane wejściowe (liczba) są domyślnie wczytywane do wartości roboczej (powiedzmy 101010).

  • Djest wykonywany, zastępując wartość roboczą cyframi ( [1,0,1,0,1,0]).

  • fold(dyad(Ḥ+))jest wykonywana, zastępując wartość roboczą 1∗0∗1∗0∗1∗0, gdzie jest diada Ḥ+.

Więc co x∗yocenia?

  • W diadycznej definicji, wartość pracy jest początkowo lewy argument x.

  • , podwójna monada, podwaja tę wartość. Wartość robocza jest teraz 2x.

  • +, plus diada, nie ma właściwego argumentu, więc jest to haczyk : specjalny składniowy wzór, w który wprowadza się odpowiedni argument tej diady +. Daje 2x + yto końcową wartość roboczą, która jest zwracana.

Całe wyrażenie ocenia więc:

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
Twoje wyjaśnienia stają się coraz lepsze :-)
Luis Mendo,

2
Hej, myślę, że robisz to teraz? To niesamowite, +1.
Erik the Outgolfer,

4
Myślę, że to pierwszy kawałek galaretki, jaki kiedykolwiek zrozumiałem. +1!
Blue

Brawo. Naprawdę rozumiem, co początkowo uważałem za bałagan pozornie przypadkowych postaci. Cudowne wyjaśnienie.
świnie

1
@Mark Jelly ma własną stronę kodową, dzięki której programy wyglądają na łatwe do odczytania, ale równie dobrze można by je pomijać.
Lynn

20

Python 2, 49 37 31 30 Bajtów

Teraz zajmie to liczbę binarną w postaci dziesiętnej, ponieważ Python może obsługiwać dowolnie duże liczby całkowite.

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

dzięki xnor za zapisanie bajtu :)

Najłatwiejszym sposobem sprawdzenia, jak to działa, jest zapoznanie się z podstawową formułą konwersji wartości binarnych na dziesiętne:

= 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

Jest to „standardowy” sposób konwersji. Możesz rozwinąć trzecią linię w następujący sposób:

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

I to jest właśnie to, co zrobiłem metodą rekurencyjną.

Alternatywne rozwiązania, które miałem:

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
Możesz zrobić n%5lub n%2zamiast n%10.
xnor

@ xnor Ah, nie jestem pewien, jak mi tego brakowało! Dzięki :)
Kade

12

05AB1E , 6 bajtów

Kod:

$¦v·y+

Dla wyjaśnienia weźmy przykład 101010 . Zaczynamy od cyfry 1 (reprezentowanej przez pierwszą cyfrę). Następnie mamy dwa przypadki:

  • Jeśli cyfra to 0 , pomnóż liczbę przez 2.
  • Jeśli cyfra to 1 , pomnóż liczbę przez 2 i dodaj 1.

Tak więc dla przypadku 101010 obliczane są:

  • 1 01010, zacznij od cyfry 1 .
  • 1 0 1010, pomnóż przez dwa, otrzymując 2 .
  • 10 1 010, pomnóż przez dwa i dodaj jeden, otrzymując 5 .
  • 101 0 10, pomnóż przez dwa, otrzymując 10 .
  • 1010 1 0, pomnóż przez dwa i dodaj jeden, otrzymując 21 .
  • 10101 0 , pomnóż przez dwa, otrzymując 42 , co jest pożądanym wynikiem.

Objaśnienie kodu:

$         # 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)

Wykorzystuje kodowanie CP-1252 . Wypróbuj online!


Niezłe! (nie działa dla 0, chociaż właśnie zauważyłem)
Emigna,

@Emigna Tak, na szczęście twój kod musi działać tylko dla dodatnich liczb binarnych.
Adnan,

Nawet nie widziałem tej części. Bardzo miło więc :)
Emigna,

9

Haskell, 16 111 + 57 = 168 bajtów

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

+57 bajty dla flagi kompilacji -XOverloadedStrings, -XOverlappingInstancesa -XFlexibleInstances.

Wyzwanie ma pewien uciążliwy format IO , ponieważ w dużej mierze zależy od sposobu wyrażenia typów danych w kodzie źródłowym. Moja pierwsza wersja (16 bajtów), a mianowicie

foldl1((+).(2*))

pobiera listę liczb całkowitych, np. [1,0,1,0,1,0]i została uznana za niepoprawną, ponieważ literalne listy Haskella zdarzają się mieć ,między elementami. Listy jako takie nie są zabronione. W mojej nowej wersji używam tej samej funkcji, teraz o nazwie f, ale przeciążam „Cytuj zamknięte sekwencje znaków”. Funkcja nadal pobiera listę liczb całkowitych, jak widać w adnotacji typu [Int] -> Int, ale listy z liczbami całkowitymi jednocyfrowymi można teraz zapisywać jak "1234"np.

f "101010"

co ocenia na 42. Pech Haskell, ponieważ natywny format listy nie pasuje do reguł wyzwań. Btw, f [1,0,1,0,1,0]nadal działa.


2
Niestety lista nie jest prawidłowym wejściem.
Jonathan Allan,

@JonathanAllan: Dlaczego? A jeśli tak, to jak w ogóle powinien on brać udział? W Haskell ciąg znaków to tylko lista znaków.
nimi

Nie wiem dlaczego ... ale zapytałem o to wcześnie i dokonano edycji, aby dodać „ (1,0,1,0,1,0,1,0)nie jest prawidłowym formatem wejściowym, ale oba są 10101010i (["10101010"])są”. ponadto komentarz sugeruje, że tablica znaków jest dopuszczalna, jeśli w ten sposób interpretowany jest ciąg znaków.
Jonathan Allan,

1
@JonathanAllan: każda „liczba całkowita binarna” (dane wejściowe, które musimy podjąć) jest z natury oddzielona, ​​jest to ciąg potęg 2. Liczba ograniczeń dotyczy jawnych separatorów (między cyframi), a nie separacji. Jakoś muszę wziąć oddzielne cyfry.
nimi

2
Op tutaj: czy jest to możliwe do wprowadzenia 10101010, "10101010"lub coś podobnego i to działało następnie przedłożenie jest prawidłowy. Możesz nazwać to ciągiem, listą, liczbą całkowitą lub czymkolwiek. Wprowadzanie [1][0][1][0]lub [1,0,1,0]jest nieprawidłowe. Zasadniczo powinno być możliwe wybranie gdzieś jednego zera i zer. Czy to jasne?
Stewie Griffin,

7

Siatkówka, 15 bajtów

Konwertuje z binarnego na unarny, a następnie z unarnego na dziesiętny.

1
01
+`10
011
1

Wypróbuj online


Nie możesz używać żadnych wbudowanych podstawowych funkcji konwersji. ~ OP
Roman Gräf,

10
@ RomanGräf Nie ma żadnych. Po prostu opisywałem proces mojego rozwiązania.
mbomb007,

7

PHP, 44 bajty

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

Mógłbym przysiąc, że widziałem już to pytanie. Ale dobrze.

Odczytuje liczbę od lewej do prawej, przesuwa się w lewo i dodaje bieżący bit.


7

JavaScript (ES6), 33 31 bajtów

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

Edycja: Krótszy, ale mniej słodki: 2 bajty zapisane dzięki @ETHproductions.


Jak to często bywa, .mapjest krótszy:s=>[...s].map(c=>+c+r+r,r=0)|r
ETHproductions

@ETHproductions Jak twoja funkcja zwraca coś innego niż 0?
Neil,

Przepraszamy, powinno byćs=>[...s].map(c=>r+=+c+r,r=0)|r
ETHproductions

7

Labirynt , 17 15 bajtów

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

Wypróbuj online!

Image of the code

Labirynt to dwuwymiarowy język oparty na stosach. W labiryncie wykonywanie kodu odbywa się zgodnie ze ścieżką kodu, podobnie jak labirynt ze spacjami działającymi jak ściany i rozpoczynającymi się od lewego górnego znaku spacji. Przepływ kodu jest określony przez znak górnej części stosu. Ponieważ stos zawiera ukryte zera u dołu, pierwsze cztery instrukcje ( -+:+) nie działają.

Pętla zaczynająca się od ,

  • , Wciśnij wartość kodu ascii następnego znaku wejściowego do końca stosu lub wciśnij -1, jeśli EOF.
  • _48 przesuwa 48 na szczyt stosu
  • -Pop y, pop x, push x-y. Poprzednie instrukcje powodują odjęcie 48 od wartości wejściowej, dając 0 dla „0” i 1 dla „1”.
  • +Pop y, pop x, push x+y.
  • : Zduplikuj górę stosu
  • + Ta i poprzednia instrukcja powodują pomnożenie bieżącej wartości przez 2

Tak więc okrągła część kodu w efekcie zwielokrotnia bieżącą liczbę przez 2 i dodaje 1 lub 0 w zależności od tego, czy wprowadzono znak 1 czy 0.

Ogon

Jeśli górna część stosu jest ujemna (co oznacza, że ​​znaleziono EOF), kod skręci w lewo na skrzyżowaniu (w kierunku średnika).

  • `` Neguj górę stosu, aby uzyskać 1
  • ) Pokryj górę stosu, aby uzyskać 2
  • /Pop y, pop x, push x / y (dzielenie liczb całkowitych). Powoduje to cofnięcie ostatniego *2z pętli.
  • !Wyprowadza całkowitą reprezentację góry stosu. W tym momencie program się odwraca, ponieważ trafił w ślepy zaułek, a następnie wychodzi z błędem, ponieważ próbuje podzielić przez zero.

Dzięki @Martin Ender za uratowanie mi 2 bajtów (i nauczenie mnie, jak lepiej myśleć w Labiryncie).


Zamiast tego _48-możesz po prostu zrobić, #%ale niestety nie widzę, jak to może pomóc w liczeniu bajtów.
Martin Ender,

Państwo może zapisać bajt ze `)zamiast ;_2chociaż.
Martin Ender,

@MartinEnder, nie rozumiem twojego komentarza na temat #%. Czy możesz wyjaśnić, jak to działa jako zamiennik _48-do konwersji z ascii na int. Dzięki za )wskazówkę. Dokonam tej zmiany.
Robert Hickman,

W tym momencie twojego programu zawsze są dwie wartości na stosie, więc #jest to po prostu skrót _2. Chociaż _2%nie jest to ogólna metoda konwersji ASCII na liczbę całkowitą, działa tutaj, ponieważ interesują Cię tylko pierwsze dwie cyfry jako możliwe dane wejściowe. Alternatywą byłoby _1&(ponieważ modulo 2 po prostu wyodrębnia najmniej znaczący bit).
Martin Ender,

O. To wspaniale. Ale tak, nie jestem pewien, jak użyć tej substytucji ( #%) do ogólnego skrócenia kodu.
Robert Hickman,

6

Brain-Flak , 46 , 28 bajtów

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

Wypróbuj online!

Wiele wielu bajtów zapisanych dzięki @Riley!

Ponieważ atak mózgu nie może przyjmować danych binarnych, dane wejściowe to lista „0” i „1”.

Wyjaśnienie:

#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.
<>

Uwielbiam wyjaśnienie! Tak trudno odczytać bez niego
wyrzuty mózgów

2
^. Nie mogę nawet czytać własnych programów, jeśli nie zostawię sobie kilku komentarzy.
Riley,

Możesz sprowadzić go do 32 bajtów, pozbywając się całej części if, a dla kroku „dodaj numer do innego stosu” po prostu dodaj go do (innego stosu) * 2. ([]){({}[()]<({}<>({}){})><>)}<>
Riley,

Możesz uratować kolejne 4, po prostu strzelając na początku i ponownie podnosząc wysokość na końcu. ([]){{}({}<>({}){})<>([])}<>
Riley,

@ Riley O rany, to genialne. Dziękuję Ci bardzo!
DJMcMayhem

6

Java, 84 79 46 48 bajtów

  • Wersja 3.1

Zmieniono na long/ 48 bajtów:

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

Czy trochę golfa / 46 bajtów:

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

Dzięki @Geobits! / 79 bajtów:

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

84 bajtów:

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
Chyba powinienem był zrobić iteracyjne rozwiązanie. Lulz. dobra robota
Poke

Czy Twój typ wejściowy to List <Character> lub String? Jeśli to drugie, nie wiedziałem, że Java8 może to zrobić! Jeśli to pierwsze jest dozwolone przez wyzwanie?
Poke

spowinno być char[]. Mam nadzieję, że jest to dozwolone ...
Roman Gräf,

Jaki jest tutaj typ zwrotu? Myślę, że powinien on być długi, ponieważ „Kod musi obsługiwać liczby binarne do najwyższej wartości liczbowej obsługiwanej przez Twój język” według OP, ale w przypadku mniejszych wartości uważam, że zwraca int
Poke

1
Prawdopodobnie dobrze na typ wejścia dla tego . Być może zechcesz wziąć 2 bajtowe uderzenie dla wyjścia imo
Poke

4

Befunge-98, 12 bajtów

2j@.~2%\2*+

Wypróbuj online!

Odczytuje jeden znak na raz z wejścia, konwertuje go na 0 lub 1, przyjmując jego wartość modulo 2 (0 to char (48), 1 to char (49)), a następnie używa zwykłego algorytmu podwajania bieżącej wartości i dodawania nowa cyfra za każdym razem.

Premia: Działa to z dowolnym rodzajem ciągu wejściowego, od jakiegoś czasu próbuję znaleźć jakąś zabawną kombinację wejścia -> wyjścia, ale nie byłem w stanie nic wytworzyć (niestety „odpowiedź” = 46). Czy możesz?


LOL. Grałem w tę samą grę z moją odpowiedzią. Najciekawszą liczbą, jaką udało mi się wygenerować, było 666 .
James Holderness

Niezłe! Nie udało mi się znaleźć niczego, co pasowałoby do 666: D Byłoby o wiele łatwiej, gdyby wielkie litery miały wpływ na wartości ...
Leo

@James Holderness - robiłem to samo i znalazłem „theleapyear”, aby przywrócić 366, twój jest naprawdę dobry.
Teal pelikan

4

JavaScript (ES7) 41 40 36 bajtów

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

pobiera ciąg jako dane wejściowe

Ogolono bajt dzięki produktom 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
Asocjatywność od prawej do lewej **jest dziwna, ale przydaje się tutaj dobra robota. 1<<b.lengthzrobiłby to samo, ale wymagałoby to, aby nawiasy nie były analizowane jako (c*1)<<(b.length+...). Myślę, że możesz zapisać bajt, zastępując b[0]go b+b( patrz tutaj ).
ETHproductions

4

C # 6, 85 37 36 bajtów

long b(long n)=>n>0?n%2+2*b(n/10):0;
  • Dzięki Kade za oszczędność 41 bajtów!
  • Zmiana na C # 6 pozwoliła zaoszczędzić kolejne 7 bajtów.

Może to może dostarczyć inspiracji? ;)
Kade

@Kade Tak, dziękuję! Patrzyłem na odpowiedź Pythona, która używa tej samej techniki w tym samym momencie, w którym połączyłeś: DI może być jeszcze krótszy z C # 6.
Yytsi


3

C, 53

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

Taki sam jak moja odpowiedź w języku JavaScript

Test Ideone


Możesz zapisać 4 bajty, deklarując vi cjako zmienne globalne (choć musisz zmienić nazwę v, ponieważ jest to już nazwa funkcji) w następujący sposób:w=0;c;v(char*s){while(c=*s++)w+=w+c-48;return w;}
Steadybox

@Steadybox może być, w,c;ale nie chcę używać globałów, gdy odpowiedź jest funkcją (nawet w golfie)
edc65

@Steadybox Globals również domyślnie ma wartość 0, więc możesz upuścić =0.
algmyr

3

Perl, 25 bajtów

-3 bajty dzięki @Dom Hastings.

24 bajty kodu + 1 bajt na -pflagę.

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

Aby uruchomić:

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

Objaśnienia:

$\|=$&<<$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

Natrętny , 10 bajtów

Zajmuje wejście jako lista 0/1 w linii poleceń: $ pushy binary.pshy 1,0,1,0,1,0.

L:vK2*;OS#

Algorytm naprawdę pokazuje piękno posiadania drugiego stosu:

            \ 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

Ta metoda działa, ponieważ stos zostanie podwojony stack length - nrazy, zanim osiągnie liczbę n, która jest następnie zrzucana do drugiego stosu na później. Oto jak wygląda proces wprowadzania danych 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 bajtów

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

Ostatni przypadek testowy zawiera błędy zaokrąglania (z powodu double), więc jeśli potrzebujesz pełnej precyzji:

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

z 47 bajtami.


Nie mogę tego przetestować, ale wierzę, @(x)sum(2.^(find(flip(x)-48)-1))że da poprawny wynik dla wszystkich przypadków dla 32 bajtów. flipdziała jak fliplrif xjest jednowymiarowy.
Stewie Griffin,

Fajne rozwiązanie! Wystąpił również błąd zaokrąglania, dzięki za poprawkę. Jaki jest format x? Wywołanie funkcji flip lub fliplr na numerze po prostu zwraca ten numer.
MattWH,

x jest łańcuchem binarnym, więc wywołaj go za pomocą f=@(x)..; f('1111001010').
Jonas,

3

Siatkówka , 12 bajtów

Liczba bajtów zakłada kodowanie ISO 8859-1.

+%`\B
¶$`:
1

Wypróbuj online!

Alternatywne rozwiązanie:

+1`\B
:$`:
1

Wyjaśnienie

Prawdopodobnie łatwiej będzie to wyjaśnić na podstawie mojej starej, mniej golfowej wersji, a następnie pokazać, jak ją skróciłem. Kiedyś konwertowałem dane binarne na dziesiętne w następujący sposób:

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

Jedynym sensownym sposobem skonstruowania liczby dziesiętnej w Retinie jest zliczanie rzeczy (ponieważ Retina ma kilka funkcji, które pozwalają wydrukować liczbę dziesiętną reprezentującą ilość). Tak więc naprawdę jedynym możliwym podejściem jest konwersja binarnego na jednoargumentowy, a następnie policzenie liczby jednoznacznych cyfr. Liczy się ostatni wiersz, więc pierwsze cztery konwertują binarne na jednoargumentowe.

Jak to zrobimy? Ogólnie rzecz biorąc, aby przekonwertować z listy bitów na liczbę całkowitą, inicjalizujemy wynik, 0a następnie przechodzimy przez bity od najbardziej do najmniej znaczącej, podwajamy wartość, którą już mamy, i dodajemy bieżący bit. Np. Jeśli liczba binarna jest 1011, naprawdę obliczymy:

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

Gdzie zaznaczyłem poszczególne bity dla przejrzystości.

Sztuczka polegająca na robieniu tego pojedynczo polega na tym, że a) podwojenie oznacza po prostu powtórzenie liczby ib) ponieważ liczymy 1s na końcu, nie musimy nawet rozróżniać 0s i 1s w tym procesie. To stanie się wyraźniejsze za sekundę.

To, co robi program, polega na tym, że najpierw dodaje przecinek na początku jako znacznik ilości danych wejściowych, które już przetworzyliśmy:

^
,

Po lewej stronie znacznika będziemy mieć wartość, którą kumulujemy (która jest poprawnie zainicjalizowana do jednostkowej reprezentacji zera), a po prawej stronie wartości będzie następny bit do przetworzenia. Teraz stosujemy następujące podstawienie w pętli:

,(.)
$`$1,

Wystarczy spojrzeć na ,(.)i i $1,za każdym razem przesuwa znacznik nieco w prawo. Ale wstawiamy także $`, czyli wszystko przed znacznikiem, tj. Bieżącą wartość, którą podwajamy. Oto poszczególne kroki przetwarzania danych wejściowych 1011, w których zaznaczyłem wynik wstawiania$` powyżej każdej linii (dla pierwszego kroku jest pusty):

,1011

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

Zobaczysz, że zachowaliśmy i podwoiliśmy zero wraz ze wszystkim innym, ale ponieważ pomijamy je na końcu, nie ma znaczenia, jak często je podwajaliśmy, o ile liczba 1s poprawny. Jeśli je policzysz, jest 11ich tylko to, czego potrzebujemy.

Pozostawia to pytanie, jak zagrać w golfa do 12 bajtów. Najdroższa część 18-bajtowej wersji wymaga użycia znacznika. Celem jest pozbycie się tego. Naprawdę chcemy podwoić każdy prefiks, więc pierwszy pomysł może być następujący:

.
$`$&

Problem polega na tym, że te zamiany odbywają się jednocześnie, więc pierwszy bit nie jest podwajany dla każdego bitu, ale jest po prostu kopiowany za każdym razem. Do wprowadzenia 1011otrzymamy (oznaczenie wstawionego $`):

 _ __ ___
1101011011

Nadal musimy rekurencyjnie przetwarzać dane wejściowe, aby podwojony pierwszy prefiks został ponownie podwojony przez drugi i tak dalej. Jednym z pomysłów jest wstawianie znaczników wszędzie i wielokrotne zastępowanie ich przedrostkiem:

\B
,
+%`,
¶$`

Po pierwszym zastąpieniu każdego znacznika prefiksem musimy pamiętać, gdzie był początek danych wejściowych, więc wstawiamy również linie i używamy %opcji, aby upewnić się, że następny $`odbierze tylko najbliższe źródło.

To działa, ale wciąż jest za długie (16 bajtów, licząc 1s na końcu). Co powiesz na to, żeby się odwrócić? Miejsca, w których chcemy wstawić znaczniki, są oznaczone \B(pozycja między dwiema cyframi). Dlaczego po prostu nie wstawiamy prefiksów w tych pozycjach? To prawie działa, ale różnica polega na tym, że w poprzednim rozwiązaniu faktycznie usuwaliśmy jeden marker w każdej zamianie, i to ważne, aby proces został zakończony. Jednak\B są to jednak postacie, tylko pozycje, więc nic nie zostanie usunięte. My może jednak zatrzymać\Bod dopasowania, zamiast tego wstawiając znak niecyfrowy w to miejsce. To zamienia granicę niebędącą słowem w granicę słowa, co jest równoważne wcześniejszemu usunięciu znaku znacznika. I tak działa 12-bajtowe rozwiązanie:

+%`\B
¶$`:

Dla kompletności, oto poszczególne etapy przetwarzania 1011, z pustym wierszem po każdym kroku:

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

Ponownie okaże się, że ostatni wynik zawiera dokładnie 11 1 sekund.

Czy jako ćwiczenie dla czytelnika możesz zobaczyć, jak dość łatwo generalizuje się to do innych baz (dla kilku dodatkowych bajtów na przyrost w bazie)?


2

T-SQL, 202 bajtów

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 bajty

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

Odwracamy naszą liczbę binarną, dzielimy ją na cyfry składowe i sumujemy na podstawie pozycji.


2

Narzędzia Bash + GNU, 29 bajtów

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

I / O poprzez stdin / stdout.

sedWyrażenie dzieli binarny góry do każdej cyfry i buduje wyrażenia RPN dla dcoceny.


2

PowerShell v2 +, 55 bajtów

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

Czuje się za długo ...Wydaje się Nie wydaje się, żeby grał w golfa - docenione wskazówki.

Wyjaśnienie

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 bajty

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

Rekursja znów oszczędza dzień! Chociaż parametryzacja wydaje się trochę długa ...


Skoro jest to pojedynczy „argument”, czy [...n]musi być otoczony nawiasami?
Cyoce,

@Cyoce Niestety tak lub JS zgłasza błąd SyntaxError.
ETHproductions

2

Mathematica, 27 13 11 bajtów

Fold[#+##&]

Akceptuje Listbitów jako wejście (na przykład {1, 0, 1, 1, 0}- Mathematica jest binarna reprezentacja liczby 22)


W następstwie komentarza do odpowiedzi Grega, w jaki sposób „dzielenie wszystkich cyfr na wejściu” nie jest podstawową funkcją konwersji?
Martin Ender,

@MartinEnder Używam go jak Charactersfunkcji.
JungHwan Min

@MartinEnder Właściwie, jak widać w odpowiedzi @ nich , mogłem po prostu zaakceptować listę cyfr 1 i 0, ponieważ jest to jedyny sposób reprezentowania liczby binarnej w Mathematica , co oznacza, że ​​nie potrzebuję IntegerDigits.
JungHwan Min

Zakłada się, że podstawa 10 jest „naturalną” reprezentacją liczby całkowitej. Rzeczywista wartość całkowita nie ma dołączonej do niej preferowanej podstawy (myślę, że można powiedzieć, że sposób jej przechowywania to prawdopodobnie podstawa 256, a może nawet podstawa 2, ale to szczegół implementacji). Tylko dlatego, że (zwykle) używamy podstawy 10 do pisania literałów całkowitoliczbowych, nie oznacza to, że wartości liczbowe są już w bazie 10.
Martin Ender

@MartinEnder @ Lynn używa kodu JellyD , który robi to samo, coIntegerDigits
JungHwan Min

2

Clojure, 114 105 63 41 bajtów

V4: 41 bajtów

-22 bajty dzięki @cliffroot. Ponieważ digitjest to znak, można go przekonwertować na kod za pomocą int, a następnie odjąć 48, aby uzyskać rzeczywistą liczbę. Mapa została również uwzględniona. Nie wiem, dlaczego wydawało się to konieczne.

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

V3: 63 bajty

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

-42 bajty (!), Zerkając na inne odpowiedzi. Moje „zipowanie” było ewidentnie bardzo naiwne. Zamiast podnieść 2 do potęgi aktualnego miejsca, a następnie pomnożyć go przez bieżącą cyfrę i dodać wynik do akumulatora, wystarczy pomnożyć akumulator przez 2, dodać bieżącą cyfrę, a następnie dodać do akumulatora. Również przekonwertowałem funkcję redukcji na makro, aby trochę się ogolić.

Dzięki @nimi i @Adnan!

Nie golfowany:

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

V2: 105 bajtów

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

-9 bajtów poprzez odwrócenie łańcucha, więc nie muszę tworzyć niewygodnego zakresu malejącego.

V1: 114 bajtów

Cóż, na pewno nie wygrywam! W mojej obronie jest to pierwszy program, jaki napisałem, który konwertuje między bazami, więc musiałem nauczyć się, jak to robić. Nie pomaga również, że Math/powzwraca wartość podwójną, która wymaga konwersji i Integer/parseIntnie przyjmuje znaku, więc cyfra musi zostać owinięta przed przekazaniem.

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

Zipuje łańcuch z indeksem malejącym reprezentującym numer miejsca. Zmniejsza w stosunku do wynikowej listy.

Nie golfowany:

(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 %)poprawiona wersja. Przeniesiono mapczęść kodu bezpośrednio do reduce, zmieniono metodę analizy liczb całkowitych, wprowadzono funkcję zewnętrzną ze skróconą składnią lambda.
Cliffroot,

@ cliffroot intmoże być użyty do parsowania !? To zrzuci jak 10 bajtów w każdym wyzwaniu, które tutaj zrobiłem lol.
Carcigenicate,

Och, widzę co robisz. Biorąc kod ascii, a następnie odejmując, aby uzyskać wartość. Myślę, że to działałoby tylko w wybranych okolicznościach. No cóż, dzięki za napiwek.
Carcigenicate,

2

Perl, 21 19 16 + 4 = 20 bajtów

-4 bajty dzięki @Dada

Uruchom z -F -p(w tym dodatkowe miejsce po F). Wartości rur do funkcji za pomocąecho -n

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

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

Wydaje mi się, że to wystarczająco różni się od odpowiedzi @ Dady, że zasługuje na swój własny wpis.

Wyjaśnienie:

-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 $\

Wykorzystuje mój osobisty algorytm do konwersji dwójkowej na dziesiętną. Biorąc pod uwagę liczbę binarną, uruchom akumulator od 0 i przeglądaj jego bity jeden po drugim. Podwój akumulator w każdym bicie, a następnie dodaj sam bit do akumulatora, a skończysz na wartości dziesiętnej. Działa, ponieważ każdy bit zostaje podwojony odpowiednią liczbę razy dla jego pozycji w oparciu o liczbę bitów pozostałych w oryginalnej liczbie binarnej.


Jeszcze krótszy:perl -F -pE '$\+=$_+$\for@F}{'
Dada

Szczerze się śmiałem z tego, jak krótkie jest to teraz. Dziękuję Ci.
Gabriel Benamy,

Tak, jest całkiem fajnie, dobrze zrobione!
Dada,

2

R (32-bit), 64 bajty

Dane wejściowe dla funkcji należy podać jako znak. Podstawowe funkcje R obsługują 32-bitowe liczby całkowite.

Wkład:

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

Wydajność:

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

R (64-bit), 74 bajty

Dane wejściowe dla funkcji należy podać jako znak. Paczkabit64 musi być używany dla 64-bitowych liczb całkowitych.

Wkład:

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

Wydajność:

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

2
Możesz zrobić: el(strsplit(x,""))zamiast strsplit(x,split="")[[1]]zaoszczędzić kilka bajtów.
Billywob,

Wielkie dzięki! Zwłaszcza dla elfunkcji - nie byłem tego świadomy.
djhurio

2

Dyalog APL , 12 bajtów

(++⊢)/⌽⍎¨⍞

uzyskać ciąg wejściowy

⍎¨ zamień każdy znak na liczbę

rewers

(... )/wstaw następujące funkcje między liczbami

++⊢ suma argumentów plus właściwy argument


ngn ogolił 2 bajty.


1

k, 8 bajtów

Ta sama metoda, co odpowiedź Haskella powyżej.

{y+2*x}/

Przykład:

{y+2*x}/1101111111010101100101110111001110001000110100110011100000111b
2016120520371234567
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.