Сложные двоичные числа

36

Давайте создадим простое сюръективное отображение из положительных целых чисел в гауссовы целые числа , которые являются комплексными числами, где действительная и мнимая части являются целыми числами.

Например 4538, если задано положительное целое число, выразите его в двоичном формате без начальных 0символов:

4538 base 10 = 1000110111010 base 2

Удалить любые трейлинг 0-ы:

100011011101

Замените любые прогоны одного или нескольких 0с одним +:

1+11+111+1

Заменить все 1на is:

i+ii+iii+i

Оцените полученное комплексное выражение и выведите упрощенное гауссовское целое число:

i+ii+iii+i = i+i*i+i*i*i+i = 2i+i^2+i^3 = 2i+(-1)+(-i) = -1+i

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

-1+i
i-1
-1+1i
(-1, 1)
-1 1
-1\n1

Для входов , таких как 29, Mathy отформатированы выходы , такие как 0, 0iили 0+0iвсе хорошо.

Использование j(или что-то еще) вместо этого iхорошо, если это более естественно для вашего языка.

Самый короткий код в байтах побеждает.

Кальвин Хобби
источник
Из названия я подумал, что проблема будет в комплексных числах в двоичном виде, например 4+2j-> 100+10j...
Эрик Аутгольфер

Ответы:

22

MATL , 7 байт

BJ*Y'^s

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

Как это работает

Рассмотрим ввод, 4538например.

B     % Implicit input. Convert to binary
      % STACK: [1 0 0 0 1 1 0 1 1 1 0 1 0]
J*    % Multiply by 1i
      % STACK: [1i 0 0 0 1i 1i 0 1i 1i 1i 0 1i 0]
Y'    % Run-length encoding
      % STACK: [1i 0 1i 0 1i 0 1i 0], [1 3 2 1 3 1 1 1]
^     % Power, element-wise
      % STACK: [1i 0 -1 0 -1i 0 1i 0]
s     % Sum of array. Implicit display
      % STACK: -1+1i
Луис Мендо
источник
2
7 байтов в MATL, и лучшее, что я могу получить, это 58 в MATLAB ... Вы сделали хороший маленький язык там! =)
Стьюи Гриффин
1
@StewieGriffin легко лучший в шоу, когда речь заходит о графике или графике, возможно, также и о матричной арифметике из удивительных ответов, которые я видел в его посте.
Волшебная Урна Осьминога
13

Желе , 8 байт

BŒgaıP€S

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

Как это работает

BŒgaıP€S  Main link. Argument: n (integer)

B         Convert to binary.
          If n = 4538, this yields [1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0].
 Œg       Group equal elements.
          This yields [[1], [0, 0, 0], [1, 1], [0], [1, 1, 1], [0], [1], [0]].
   aı     Logical AND with the imaginary unit.
          This yields [[ı], [0, 0, 0], [ı, ı], [0], [ı, ı, ı], [0], [ı], [0]].
     P€   Product each.
          This yields [ı, 0, -1, 0, -ı, 0, ı, 0].
       S  Sum.
          This yields -1+ı.
Деннис
источник
10

Python 2, 53 байта

f=lambda n,k=0:(n and f(n/2,n%2*(k or 1)*1j))+~n%2*k

Я пытался сыграть в гольф, и это кажется играбельным, но у меня нет идей ...

Sp3000
источник
1
Это (k or 1)не кажется оптимальным, но единственное, о чем я могу думать, это (k+0**k)...
ETHproductions
@ETHproductions Мои мысли точно, но, к сожалению 0**k, не работает для сложных k...
Sp3000
6

Mathematica, 44 38 байт

Tr[1##&@@@Split[I*#~IntegerDigits~2]]&

объяснение

#~IntegerDigits~2

Преобразовать вход в базу 2. ( 4538становится {1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0})

I*

Умножить на I( {1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0}становится {I, 0, 0, 0, I, I, 0, I, I, I, 0, I, 0})

Split

Разделить по пробегам ( {I, 0, 0, 0, I, I, 0, I, I, I, 0, I, 0}становится {{I}, {0, 0, 0}, {I, I}, {0}, {I, I, I}, {0}, {I}, {0}})

1##&@@@ ...

Найти товар на уровне 2. ( {{I}, {0, 0, 0}, {I, I}, {0}, {I, I, I}, {0}, {I}, {0}}становится {I, 0, -1, 0, -I, 0, I, 0})

Tr

Подведите итог. ( {I, 0, -1, 0, -I, 0, I, 0}становится -1 + I)

Юнг Хван Мин
источник
минус 1 байт:Tr[Times@@@(I*Split@RealDigits[#,2][[1]])]&
мартин
1
@martin Ну, сначала я использовал твою идею умножения I, но в IntegerDigitsитоге стал короче.
JungHwan Мин
да - намного лучше :)
мартин
5

JavaScript (ES6), 67 64 байта

f=(n,q=0,a=[0,0])=>q|n?f(n/2,n&1?q+1:q&&0*(a[q&1]+=1-(q&2)),a):a
<input oninput="O.innerHTML=f(this.value)" type="number" step=1 min=0 value="4538">
<pre id=O></pre>

Выходы в виде 2-элементного массива.

объяснение

Поскольку в JavaScript нет мнимых чисел, мы должны отслеживать действительные и мнимые части в отдельных переменных. Самый простой способ сделать это - в одном массиве, сначала с реальной частью. i представлен как [0,1] , i 2 (или -1 ) как [-1,0] , i 3 (или -i ) как [0, -1] и i 4 (или 1 ) как [1 , 0] .

Сначала мы многократно делим число на 2, собирая каждую серию единиц в двоичном представлении. Каждый прогон n соответствует i n . Это соответствует добавлению 1 - (n & 2) к элементу с индексом n & 1 в массиве из двух элементов. Так что мы делаем.

Возможно, мне следует добавить больше объяснений, но я не могу придумать, что еще нужно объяснить. Не стесняйтесь комментировать любые ваши вопросы.

ETHproductions
источник
5

Python, 199 129 124 116 94 90 71 63 61 байт

print sum(1j**len(s)for s in bin(input())[2:].split('0')if s)

Ввод - это просто само число.
Вывод в формате(a+bj) , где jнаходится мнимая единица. 0jбудет выводиться вместо(0+0j)

Сначала преобразуйте в двоичный файл. Усечь'0b' выкл. Убить конечные нули. Разделить, используя блок с нулями в качестве разделителя. Сопоставьте каждый блок с 1j ** len. Затем возьмите сумму всего.

-70 байт , не преобразуя в плюсы.
Регулярное выражение на 5 байт короче.
-8 байт , избавившись от двух ненужных переменных, которые вызывались только один раз.
-22 байта , используя комплексные числа вместо моей странной вещи. Спасибо ответу @Dennis за информацию о комплексных числах!
-4 байта , понимая, что mapэто всего лишь причудливый способ сделать списки, кроме более длинных.
-19 байт , переключившись на слегка загадочный способ избежать ошибок j ** 0и избежать регулярных выражений. Вдохновленный комментарием @ Griffin. Благодарность! :)
-8 байт , перемещая ifчасть до конца.
-2 байта Спасибо @Griffin за сохранение 2 байтов за счет удаления квадратных скобок, чтобы вместо этого сделать его генератором выражений!

HyperNeutrino
источник
Я получил нечто очень похожее, поэтому не буду публиковать отдельный ответ, хотя и немного корочеsum(1j**x.count('1')for x in bin(input()).split('0')if x)
Гриффин
@ Гриффин Ницца. Я думаю, что он достаточно отличается, чтобы вы могли опубликовать отдельный ответ, поскольку он использует другой метод подсчета 1блоков и не использует регулярные выражения, как мой. Кроме того, я не хочу украсть код у вас, так как он намного лучше моей версии. :)
HyperNeutrino
@ Гриффин Я нашел другое решение, которое имеет ту же длину, что и ваше решение, но вместо того, чтобы считать 1s, а не длину, 0xсначала часть снимается с передней части. Спасибо за идею продвинуться ifдо конца; Я никогда бы не узнал, что работает иначе!
HyperNeutrino
вам не нужно понимание списка. Снимите квадратные скобки, чтобы сделать его выражением генератора
Griffin
@ Гриффин Ох. Хорошо спасибо! Я буду помнить это для будущего игры в гольф
HyperNeutrino
4

MATLAB, 58 байт

@(x)eval([strrep(strrep(dec2bin(x),48,43),49,'i*1'),'.0'])

dec2bin(x) % converts the decimal value to a binary string of 1s and 0s.
strrep(dec2bin(x),48,43) % Substitutes ASCII character 48 with 43 (0s become +)
strrep(___,49,'i*1')     % Substitutes ASCII character 49 with 'i*1'
                         % 1s become 'i*1' (this is the gem)
eval([___,'.0']          % Appends .0 in the end and evaluates the expression.   

Давайте использовать 285для иллюстрации процесса:

temp1 = dec2bin(285)
      = 100011101

temp2 = strrep(temp1,48,43)
      = 1+++111+1

К счастью , 1+++1ведет себя так же , как 1+1в MATLAB, так что приведенные выше имеет значение: 1+111+1.

temp3 = strrep(temp2,49,'i*1')
      = i*1+++i*1i*1i*1+i*1

Теперь этот strrepзвонок - настоящая жемчужина! Вставив i*1для 1нас получить что - то действительно хорошее. Если есть только один 1, мы просто получаем, i*1что есть i. Если есть больше чем один , то i*1получает повторяется и объединено в последовательности: i*1i*1i*1i*1. Поскольку i==1iв среде MATLAB и 1i*1==iэто просто: i*i*i*i.

temp4 = [temp3,'.0']
      = i*1+++i*1i*1i*1+i*1.0

Добавление .0кажется здесь ненужным, но это необходимо, если последний символ temp3- +. Мы не можем добавить только ноль, так как это даст i*10в случае выше и, следовательно, неправильный результат.

И наконец:

eval(temp4)
0.0000 + 1.0000i

Это не работает в Октаве по нескольким причинам. strrepне может принимать ASCII-значения в качестве входных данных, ему нужны реальные символы ( '0'вместо 48). Кроме того, +++не оценивается только +в октаве, так как это сломает ярлыки увеличения / уменьшения x++и x--.

Стьюи Гриффин
источник
1
Всегда +1 за использование eval:-P Вы не можете использовать 1iвместо 1*i?
Луис Мендо
1
О, вы используете это по-другому. Очень умно!
Луис Мендо
Спасибо :-) Должен признаться, я был вполне доволен этой i*1частью ...
Стьюи Гриффин
2

Mathematica, 84 байта

ToExpression[#~IntegerString~2~StringTrim~"0"~StringReplace~{"0"..->"+","1"->"I "}]&

Анонимная функция. Принимает число в качестве ввода и возвращает комплексное число в качестве вывода.

LegionMammal978
источник
6
Вау, я удивлен, что Mathematica не имеет встроенного для этого!
HyperNeutrino
2

Mathematica, 75 байтов

ToExpression[#~IntegerString~2~StringReplace~{"1"->"I ","0"..->"+"}<>"-0"]&

Самостоятельно придумал почти то же решение, которое LegionMammal978 опубликовал 23 минуты назад! Замена 1на I (который является внутренним символом Mathematica для квадратного корня из -1) работает, потому что пробелы рассматриваются как умножение соседних выражений. Место, которое я сохранил в другом решении, а именно, избегая необходимости StringTrim, всегда добавляется -0: если двоичное число заканчивается 1, тогда заканчивается это выражение, ...I-0которое не влияет на его значение; тогда как если двоичное число оканчивается на «0», то это выражение заканчивается на том, ...+-0что анализируется как «добавить отрицательный 0» и, таким образом, избавляется от завершающего знака плюс.

Грег Мартин
источник
2

Matlab, 99 байт

function c=z(b)
c=0;b=strsplit(dec2bin(b),'0');for j=1:numel(b)-isempty(b{end});c=c+i^nnz(b{j});end

Тестовые случаи:

z(656) = 3i
z(172) = -1 + 2i
z(707) = -2 + i
z(32)  = i
z(277) = 4i
Оуэн Морган
источник
2

Haskell, 102 91 89 87 байт

0%a=a
n%c@[a,b]|odd n=div n 2%[-b,a]|d<-div n 2=zipWith(+)c$d%[mod d 2,0]
(%[0,0]).(*2)

Неоднократно делится на два и проверяет бит. Хранит аккумулятор, i^(number of odds)где a+b*iкодируется как [a,b]и *iесть [a,b]↦[-b,a](вращение на 90 градусов). Начальный(*2) - избежать поиска первого бита.

Использование (спасибо @OwenMorgan за примеры):

(%[0,0]).(*2)<$>[656,172,707,32,277]
[[0,3],[-1,2],[-2,1],[0,1],[0,4]]
Angs
источник
1

Java, 172 байта

l->{int i=0,j=i;for(String x:l.toString(2).split("0")){int a=x.length();j+=a&1>0?(a&3>2?(a-3)/-4+1:(a-3)/4+1):0;i+=a&1<1?(a&3>1?(a-3)/4+1:(a-3)/-4+1):0;}return i+"|"j+"i";}
Роман Греф
источник
1

Clojure, 183 байта

#(loop[x(clojure.string/split(Integer/toString % 2)#"0+")y[0 0]a 0](if(= a(count x))y(recur x(let[z([[1 0][0 1][-1 0][0 -1]](mod(count(x a))4))][(+(y 0)(z 0))(+(y 1)(z 1))])(inc a))))

Могу ли я сделать это?

Используйте функцию так:

(#(...) {num}) -> (Wrap the # function in brackets first!)
clismique
источник
1

На самом деле 35 байт

├'0' aÆô' @s"j+"j'jo`"1j*1"'1τ(Æ`Y≡

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

Объяснение:

├'0' aÆô' @s"j+"j'jo`"1j*1"'1τ(Æ`Y≡
├                                    binary representation of input
 '0' aÆ                              replace 0s with spaces
       ô                             trim leading and trailing spaces
        ' @s                         split on spaces
            "j+"j                    join with "j+"
                 'jo                 append "j"
                    `"1j*1"'1τ(Æ`Y   do until the string stops changing (fixed-point combinator):
                     "1j*1"'1τ(Æ       replace "11" with "1j*1"
                                  ≡  evaluate the resulting string to simplify it

Примерно эквивалентный код Python 3:

a='j+'.join(bin(eval(input()))[2:].replace('0',' ').strip().split())+'j'
b=0
while a!=b:b,a=a,a.replace("11","1j*1")
print(eval(a))

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

Мего
источник
Разделение на 0 с '0@sпомощью и использование ``░для обрезания любых завершающих пустых строк должно сэкономить вам четыре байта.
Sherlock9
1

Желе , 10 байт

Это не лучше, чем ответ Желе Денниса, но я все равно хотел попробовать свои силы в ответе Желе. Предложения по игре в гольф приветствуются! Попробуйте онлайн!

BŒrm2Ṫ€ı*S

Ungolfing

BŒrm2Ṫ€ı*S   Main link. Argument: n (integer)

B            Convert n to binary.
 Œr          Run-length encode the binary list.
   m2        Every 2nd element of the run_length encoding, getting only the runs of 1s.
     Ṫ€      Tail each, getting only the lengths of the runs.
       ı*    The imaginary unit raised to the power of each run (as * is vectorized).
         S   Sum it all into one complex number.
Sherlock9
источник
В приведенной выше ссылке вход 1 возвращает 1j, вход 2 возвращает 1j .... Это верно?
РосЛюП
@RosLuP Да, верно? Поскольку мы удаляем конечные 0, 1 => 1 => 1jэто эквивалентно 2 => 10 => 1 => 1j.
Sherlock9
1

На самом деле , 15 байтов

Предложения по игре в гольф приветствуются! Попробуйте онлайн!

├'0@s``░`lïⁿ`MΣ

Ungolfing:

         Implicit input n.
├        Convert n to binary.
'0@s     Split by '0's.
``░      Filter out non-truthy values.
`...`M   Map over the filtered result, a list of runs of '1's.
  l        Yield the length of the run of '1's.
  ïⁿ       Yield the imaginary unit to the power of that length.
Σ        Sum all of this into one complex number.
Sherlock9
источник
0

Аксиома, 140, 131, 118 108 байт

b(x)==(s:=0;repeat(x=0=>break;r:=x rem 2;repeat(x rem 2=1=>(r:=r*%i;x:=x quo 2);break);s:=s+r;x:=x quo 2);s)

% я - воображаемая стоимость.

sb(x:NNI):Complex INT==
  r:Complex INT;s:Complex INT:=0
  repeat
    x=0=>break
    r:=x rem 2
    repeat
       x rem 2=1=>(r:=r*%i;x:=x quo 2)
       break
    s:=s+r
    x:=x quo 2
  s

полученные результаты

(3) -> b 4538
   The type of the local variable r has changed in the computation.
   We will attempt to interpret the code.
   (3)  - 1 + %i
                                                    Type: Complex Integer
(4) -> b 29
   (4)  0
                                                    Type: Complex Integer
(5) -> sb 299898979798233333333333333339188888888888888888222
   Compiling function sb with type NonNegativeInteger -> Complex Integer
   (5)  - 7 + 12%i
                                                    Type: Complex Integer
(6) -> b 299898979798233333333333333339188888888888888888222
   (6)  - 7 + 12%i
                                                    Type: Complex Integer
RosLuP
источник
0

Perl 6 ,  40  46 байт

Я придумал это довольно быстро

*.base(2).comb(/1+/).map(i***.chars).sum

К сожалению, в настоящее время неточность в реализации Rakudo на MoarVM .
say i ** 3; # -1.83697019872103e-16-1i

Поэтому я должен был сделать следующую лучшую вещь:

*.base(2).comb(/1+/).map({[*] i xx.chars}).sum

Expanded:

*\             # Whatever lambda
.base(2)       # convert to a Str representation in base 2
.comb(/ 1+ /)  # get a list of substrings of one or more 「1」s
.map({         # for each of those

  [*]            # reduce using 「&infix:<**>」
    i xx .chars    # 「i」 list repeated by the count of the characters matched

}).sum          # sum it all up

Тест:

.say for (4538, 29).map:

    *.base(2).comb(/1+/).map({[*] i xx.chars}).sum

# -1+1i
# 0+0i
Брэд Гилберт b2gills
источник
Сообщение ошибки подало
Брэд Гилберт b2gills
0

PHP, 87 байт

for($n=$argv[1];$n|$i;$n>>=1)$n&1?$i++:($i?$i=0*${$i&1}+=1-($i&2):0);echo"(${0},${1})";

Почти так же, как решение ETHproductions; только итеративный, а не рекурсивный.
Принимает ввод из командной строки, устанавливает переменные ${0}и ${1}.

Titus
источник
0

TI-Basic (TI-84 Plus CE), 70 байт

Prompt X
0→S
0→N
While X
If remainder(X,2
Then
N+1→N
int(X/2→X
Else
S+i^Nnot(not(N→S
X/2→X
0→N
End
End
S+i^Nnot(not(N

Нет встроенной функции для преобразования в двоичную строку (и при этом нет необходимости анализировать строку), поэтому эта программа вручную делит на 2, увеличивая N каждый раз, когда видит 1, добавляя i ^ N к S (N> 0) и сбрасывая N, если он видит ноль.

pizzapants184
источник
0

R , 54 байта

function(n,x=rle(n%/%2^(0:log2(n))%%2))sum(1i^x$l*x$v)

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

n%/%2^(0:log2(n))%%2вычисляет вектор двоичных цифр. Используя кодирование длин серий, мы используем complexтип R для вычисления соответствующей суммы, умножая наx$values чтобы удалить нули.

Возвращает complexвектор одного элемента.

Giuseppe
источник