Складні двійкові числа


36

Створимо просте сюр'єктивне відображення від натуральних чисел до цілих чисел Гаусса , які є складними числами, де реальні та уявні частини - цілі числа.

Надавши додатне ціле число, наприклад 4538, виразити його у двійковій формі без провідних 0знаків:

4538 base 10 = 1000110111010 base 2

Видалити будь-які трейлінг 0:

100011011101

Замініть будь-які запуски однієї чи декількох 0на одиницю +:

1+11+111+1

Замініть все 1на i's:

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+2j100+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

Я намагався пограти в це в гольф, і, здається, пограбував, але я не маю ідеї в атм ...


1
Це (k or 1)не здається оптимальним, але єдине, про що я можу придумати - це (k+0**k)...
ETHproductions

@ETHproductions Мої думки точно, але, на жаль 0**k, не працюють для складних k...
Sp3000

6

Математика, 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 Min

так - набагато краще :)
март


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 i 4 (або 1 ) як [1 , 0] .

По-перше, ми кілька разів ділимо число на 2, збираючи кожен запуск одиниць у його двійкове подання. Кожному виконанню n n відповідає i n . Це відповідає додаванню 1 - (n & 2) до елемента в індексі n & 1 у двопозиційному масиві. Отже, це ми робимо.

Я, мабуть, слід додати більше пояснень, але я не можу придумати, що ще потрібно пояснити. Не соромтесь коментувати будь-які питання, які можуть виникнути.


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'вимкнено. Вбийте останні нулі. Розділити, використовуючи блок нуля (s) як роздільник. Мапа кожного блоку в 1j ** len. Потім візьміть суму всієї справи.

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


Я отримав щось досить схоже, тому не буду публікувати окрему відповідь, хоч трохи коротшеsum(1j**x.count('1')for x in bin(input()).split('0')if x)
Гриффін

@Griffin Nice. Я думаю, що це досить різне, що ви можете опублікувати окрему відповідь, оскільки він використовує інший метод підрахунку 1блоків, і він не використовує регулярний вираз, як у мене. Крім того, я не хочу красти код у вас, оскільки він набагато кращий, ніж моя версія. :)
HyperNeutrino

@Griffin Я знайшов інше рішення, яке має таку ж довжину, що і ваше рішення, за винятком того, що замість того, щоб рахувати 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). Крім того, +++не оцінюється лише +в Octave, оскільки це порушить ярлики збільшення / зменшення x++та x--.


1
Завжди +1 для використання eval:-P Не можна використовувати 1iзамість 1*i?
Луїс Мендо

1
О, ти використовуєш це по-іншому. Дуже розумний!
Луїс Мендо

Спасибі :-) Треба визнати, я був цілком задоволений i*1 частиною ...
Стюі Гріффін


2

Математика, 84 байти

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

Анонімна функція. Бере число як вхід і повертає складне число як вихід.


6
Нічого собі, я здивований, що математика для цього не має вбудованої!
HyperNeutrino

2

Математика, 75 байт

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

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


2

Матлаб, 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]]

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!)

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та використання ``░обрізки будь-яких порожніх рядків повинно економити чотири байти.
Шерлок9

1

Желе , 10 байт

Це не краще, ніж відповідь Дженніса на Jelly, але я хотів спробувати свої сили у відповіді на Jelly. Пропозиції з гольфу вітаються! Спробуйте в Інтернеті!

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.

У посиланні вище Вхід 1 повернення 1j вхід 2 повернення 1j .... Це правильно?
RosLuP

@RosLuP Так, саме так? Оскільки ми видаляємо останні 0, 1 => 1 => 1jце еквівалентно 2 => 10 => 1 => 1j.
Шерлок9

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.

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)

% i - уявний костант

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

0

Перл 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

Розширено:

*\             # 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


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


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, якщо він бачить нуль.



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вектор одного елемента.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.