Додавання в базі -1 + i


64

Цілі числа Гаусса - це складні числа форми, a+biде aі bє обидва цілі числа. У базі -1 + i всі цілі числа Гаусса можна однозначно представити за допомогою цифр 0і 1без необхідності символу для позначення знаку.

Наприклад, 1100у базі -1 + i є десяткове число 2, оскільки

1*(-1+i)^3 + 1*(-1+i)^2 + 0*(-1+i)^1 + 0*(-1+i)^0
= (2+2i) + (-2i) + 0 + 0
= 2

Вхідними даними будуть два цілі числа Гаусса в базі -1 + i, представлені за допомогою цифр 01. Це може мати одну з таких форм:

  • Дві окремі рядкові рядки,
  • Два десяткових цілих числа, що складаються з 01числа базових -1 + i чисел (наприклад, 1100для 2 у базовій -1 + i),
  • Два двійкові цілі числа, що представляють базові числа -1 + i (наприклад, десятковий 12або 0b1100для 2 у базовій -1 + i)
  • Один рядок, що розділяє двоцифрові рядки / двійкові цілі числа єдиним не буквено-цифровим роздільником (наприклад, 1100 1100або 12,12для 2 + 2)

Виведіть суму двох цілих чисел Гаусса, також у базі -1 + i та представлені за допомогою цифр 01(в одному з форматів, дозволених як введення, не обов'язково одного вибору). Вихід може містити кінцеву кількість провідних нулів.

Ваша функція або програма повинні припинитись протягом 2 секунд для введення не більше 30 цифр кожен.

Додаткові роз'яснення

  • Ви можете припустити, що вхід не містить сторонніх нульових нулів. Для особливого випадку 0 ви можете обрати будь-який 0або порожній рядок як представлення.

Тестові справи

0, 0 => 0                                      # 0 + 0 = 0
0, 1 => 1                                      # 0 + 1 = 1
1, 1 => 1100                                   # 1 + 1 = 2
1100, 1100 => 111010000                        # 2 + 2 = 4
1101, 1101 => 111011100                        # 3 + 3 = 6
110111001100, 1110011011100 => 0               # 42 + (-42) = 0
11, 111 => 0                                   # i + (-i) = 0
11, 110 => 11101                               # i + (-1-i) = -1
10101, 11011 => 10010                          # (-3-2i) + (-2+3i) = (-5+i)
1010100101, 111101 => 1110100000100            # (-19+2i) + (3-4i) = (-16-2i)

Більш тривалі випробування:

11011011010110101110010001001, 111100010100101001001010010101 => 0
111111111111111111111111111111, 111111111111111111111111111111 => 100100100100100100100100100100
101101110111011101110111011101, 101101110111011101110111011101 => 11101001010001000100010001000100011100
100100010101001101010110101010, 100010011101001011111110101000 => 110000110010101100001100111100010

Немає списків цифр?
CalculatorFeline

@CatsAreFluffy Немає знакових списків, вибачте.
Sp3000

96
Ви можете зберегти один байт шляхом зміни -1+iв i-1в назві.
mbomb007

1
Тепер нам потрібна конверсія навпаки. : P
Rɪᴋᴇʀ

3
У світі існує 1100 типів людей. Тих, хто розуміє бінарне, тих, хто цього не робить, тих, хто плутає його з потрійним, тих, хто плутає його з базовим 4, тих, хто плутає його з базовим 5, тих, хто плутає його з базовим -1 + i, тих, хто плутає його з база 6, ті, хто плутає її з базою 7, ті, хто плутає її з базою 8, ті, хто плутає її з базою 9 ...
wizzwizz4

Відповіді:


42

Python 2, 98 97 91 84 байт

s=input();L=1
for _ in`s`*8:s+=1098*int(str(s).translate('0011'*64));L*=10
print s%L

Це введення / виведення в десятковій частині. Цілі числа повинні бути розділені нелітерно-цифровим символом +.

Дякуємо @xnor за те, що ти граєш на 2 байти!

Спробуйте це на Ideone .

Як це працює

В « Арифметиці в складних базах» автор показує, як додавати і множити складні числа в базах виду -n + i .

Для базової -1 + i додавання виконується аналогічно звичайному, двійкове додавання з перенесенням, з двома різницями:

  • Замість того, щоб перенести 1 на наступну вищу позицію, ми переносимо 110 на наступну три.

  • Номери цифр можуть поширюватися нескінченно. Однак, не ведучи нулів, сума a + b має максимум на вісім цифр більше, ніж максимум a і b .

Ми поступаємо так.

  1. Спочатку додаємо a і b так, як ніби їх цифри були десятковими цифрами.

    Для a = 10101 і b = 11011 , це дає 21112 .

  2. Далі формуємо нове число, замінюючи цифри, більші за 1, на 1 , інші - на 0 . 1

    На суму 21112 це дає 10001 .

  3. Для кожної цифри, що перевищує 1 , ми повинні відняти 2 з цієї цифри і перенести 110 на наступні три вищі позиції. Оскільки 1098 = 10 * 110 - 2 , ми можемо досягти цього, помноживши результат з кроку 2 на 1098 , а потім додавши цей продукт до суми. 2

    На суму 21112 це дає 21112 + 1098 * 10001 = 21112 + 10981098 = 11002210 .

  4. Повторюємо кроки 2 і 3 загалом d * 8 разів, де d - кількість цифр a + b . 3

    За початковою сумою 21112 результати

                          11002210
                          12210010
                        1220010010
                      122000010010
                    12200000010010
                  1220000000010010
                122000000000010010
              12200000000000010010
            1220000000000000010010
          122000000000000000010010
        12200000000000000000010010
      1220000000000000000000010010
    122000000000000000000000010010
                                 .
                                 .
                                 .
    
  5. Ми беремо остаточну суму за модулем 10 d + 8 , відкидаючи всі, крім останніх d + 8 цифр.

    Для початкової суми 21112 кінцевий результат - 10010 .


1 Це досягається за допомогою перекладу . Повторення рядка 0011 64 рази робить одну лінію повторення послідовністю символів 0123 ASCII , досягаючи бажаної заміни.

2 Зауважте, що цифри цієї суми не можуть перевищувати 3 (початкове значення 1 плюс два 1 's від переносів).

3 Це трапляється для d = 1 , а d * 8> d + 8 інакше. Код може повторити кроки (d + 1) * 8 разів, оскільки s має кінцевий L, якщо s - довге ціле число.


7
Це глибока магія . Якого формату input()очікуєте? (Я отримую, 21112коли 10101, 11011
ввожу

1
Не звертай уваги; що працювала версія, перекладена (невдало, здається) на Python 3. Це добре працює під Python 2 .
Тім Педерік

9
... Як. Будь ласка. Поясніть.
Нік Хартлі

@QPaysTaxes Я відредагував свою відповідь.
Денніс

@Dennis Тепер ви могли б пояснити, чому це працює? Наприклад, чому d+8і ні, скажімо d+9,? Як ????
Нік Хартлі

16

Pyth, 34 байти

_shM.u,%J/eMeN\12-+PMeNm.B6/J2k,kQ

Спробуйте в Інтернеті: Демонстрація або Тестовий набір (займає досить багато часу). Він повинен задовольнити обмеження часу, хоча легко, оскільки онлайн-компілятор досить повільний порівняно з звичайним (офлайн) компілятором.

Пояснення:

Мій алгоритм - це в основному реалізація доповнення з перенесенням. Але замість того 1, щоб носити, я маю нести 110( 1100в базі -1+iте саме, що 2в базі -1+i). Це працює в основному добре, але ви можете застрягнути в нескінченному нулі друку. Наприклад , якщо ви додаєте 1з 11і в даний час мають керрі 110. Тому я в основному додаю, поки я не застрягну в циклі, а потім зупиняюся. Я думаю, що цикл, що цикл завжди буде друкувати нулі, і тому це повинно бути добре.

_shM.u,%J/eMeN\12-+PMeNm.B6/J2k,kQ   implicit: Q = input list of strings
                               ,kQ   create the pair ["", Q]
    .u                               modify the pair N (^) until loop:
      ,                                replace N with a new pair containing:
            eN                           N[1] (the remaining summand)
          eM                             take the last digits of each summand
         /    \1                         count the ones
        J                                store the count in J
       %J       2                        J % 2 (this is the first element of the new pair)
                   PMeN                  remove the last digit of each summand
                  +    m   /J2           and add J / 2 new summand:
                        .B6                 with the value "110" (binary of 6)
                 -            k          remove empty summand
    .u                               returns all intermediate results
  hM                                 extract the digits
 s                                   sum them up to a long string
_                                    reverse

13

Python 2, 69 67 байт

f=lambda a,b:a*a+b*b^58and 2*f(a*b%2*6,f(a/2,b/2))|a+b&1if a else b

Введення / виведення виконується за допомогою цілих чисел бази 2.

-2 спасибі @Dennis.


Я приймаю це a*a+b*b^58==0коли aі bє обертання? Як це працює?
xnor

@xnor Ні, a*a+b*b==58коли одному з них 3, а другому 7.
feersum

1
Мені не очевидно, що (3,7)це єдина пара, яка дає цикл і потребує спеціального корпусу. Якщо це правда, то вам потрібно лише перевірити (a,b)==(3,7)в такому порядку, оскільки це (7,3)повторюється (3,7), і, можливо, є коротший вираз для цього.
xnor

1
Тепер це гарантовано збиває з пантелику тих, хто не знає (або забуває), що (а) ^є XOR, а не експоненціація, або (b) XOR має нижчий пріоритет ніж +.
Тім Педерік

12

Сітківка , 100 байт

r+`(.*)(\d|(?!\4))( .*)(.?)
$2$4:$1$3
T` 0
+`1:11(1*:1*)11
:$1
^:*
:::
}`:(1*:1*:)11
1:1$1
(1)*:
$#1

Це займає вхід, розділений комою. Вихід завжди починається з трьох провідних нулів.

Спробуйте в Інтернеті!

Мені дуже цікаво, чи є коротше рішення для першого етапу ...


2
Ні, ні, оцінка ідеальна, як і є;)
Conor O'Brien

2
Хороший бал -2i!
Нік Хартлі

Ого. Я не бачив цього рішення, коли розміщував своє ... Набагато перевершує моє рішення.
Лина монашка

@KennyLau Я просто дивився на це і думав: "Хм, я думаю, я повинен був би додати пояснення в якийсь момент ..."
Мартін Ендер,

...- 2i? Це десятковий, але програма використовує базу, яка ні.
користувач75200

12

Желе, 29 28 26 24 21 20 байт

DBḅ1100ḌµDL+8µ¡Dṣ2ṪḌ

Це введення / виведення в десятковій частині. Цілі числа повинні бути розділені нелітерно-цифровим символом +.

Спробуйте в Інтернеті! або перевірити всі тестові випадки .

Фон

В « Арифметиці в складних базах» автор показує, як додавати і множити складні числа в базах виду -n + i .

Для базової -1 + i додавання виконується аналогічно звичайному, двійкове додавання з перенесенням, з двома різницями:

  • Замість того, щоб перенести 1 на наступну вищу позицію, ми переносимо 110 на наступну три.

  • Номери цифр можуть поширюватися нескінченно. Однак, не ведучи нулів, сума a + b має максимум на вісім цифр більше, ніж максимум a і b .

Ми поступаємо так.

  1. Спочатку додаємо a і b так, як ніби їх цифри були десятковими цифрами.

    Для a = 10101 і b = 11011 , це дає 21112 .

  2. Для кожної цифри, що перевищує 1 , ми повинні відняти 2 з цієї цифри і перенести 110 на наступні три вищі позиції. Ми можемо досягти цього, перетворивши кожну десяткову цифру у двійкові, отримані двійкові масиви з бази 1100 до цілих чисел та інтерпретуючи отриманий список 0 's, 1 ' s, 1100 's та 1101 ' як неканонічну базу 10 число. 1

    На суму 21112 це дає 21112 + 1098 * 10001 = 21112 + 10981098 = 11002210 .

  3. Повторюємо кроки 2 загалом d + 8 разів, де d - кількість цифр a + b .

    За початковою сумою 21112 результати

                          11002210
                          12210010
                        1220010010
                      122000010010
                    12200000010010
                  1220000000010010
                122000000000010010
              12200000000000010010
            1220000000000000010010
          122000000000000000010010
        12200000000000000000010010
      1220000000000000000000010010
    122000000000000000000000010010
    
  4. Ми відкидаємо всі, крім останніх цифр d + 8, від остаточного результату. Це досягається шляхом відкидання все після останніх 2 . 2

    Для початкової суми 21112 кінцевий результат - 10010 .

Як це працює

DBḅ1100ḌµDL+8µ¡Dṣ2ṪḌ  Main link. Argument: a + b (implicit sum)

        µ    µ¡       Execute the chain before the first µ n times, where n is
                      the result of executing the chain before the second µ.
         D            Convert a + b to base 10.
          L           Length; count the decimal digits.
           +8         Add 8 to the number of digits.
D                     Convert the initial/previous sum to base 10.
 B                    Convert each digit (0 - 3) to binary.
  ḅ1100               Convert each binary array from base 1100 to integer.
       Ḍ              Interpret the resulting list as a base 10 number.
               D      Convert the final sum to base 10.
                ṣ2    Split at occurrences of 2.
                  Ṫ   Select the last chunk.
                   Ḍ  Convert from base 10 to integer.

1 Зауважте, що цифри цієї суми не можуть перевищувати 3 (початкове значення 1 плюс два 1 's від переносів).

2 Це працює, тому що остання цифра, яка буде скасована, не може бути 3 .


6

Python 3, 289 байт

Це виконує додавання в цифровій формі від найменш до найбільш значущої цифри (іншими словами, точно такий же алгоритм, який ви навчали в початковій школі). Відмінності полягають у тому, що (а) це у двійковій, а не в десятковій формі, тому ви переносите щоразу, коли цифра дорівнює 2 і більше, і (b) 1 + 1 = 1100, ні 10.

Власне, потрібно також зазначити, що 11 + 111 = 0інакше суми, які мають стати нульовими, ніколи не припиняться.

from collections import*
def a(*s,p=0):
 r=defaultdict(int,{0:0})
 for S in s:
  n=0
  for d in S[::-1]:r[n]+=d=='1';n+=1
 while p<=max(r):
  while r[p]>1:
   r[p]-=2
   if r[p+1]>1<=r[p+2]:r[p+1]-=2;r[p+2]-=1
   else:r[p+2]+=1;r[p+3]+=1
  p+=1
 return str([*map(r.get,sorted(r))])[-2::-3]

Напевно можливо більше гольфу.


Наскільки ви впевнені, що ваш «нульовий детектор» достатній?
Якк

4
@Yakk: За шкалою від одного до рецензованого журналу, можливо, дайте йому не відповідні приклади - поки?
Тім Педерік

2

Сітчаста, 157 151 134 133 124 123 байт

1 байт, завдяки Мартіну Бюттнеру.

(.+),(.+)
$.1$*0$2,$.2$*0$1,
1
0x
+`(0x*)(,.*)0(x*),
$2,$1$3
{`,

(^|0x0xx0xx)
000
(0x*)(0x*)(0x*0)xx
$1x$2x$3
)`^0+
0
0x
1

Спробуйте в Інтернеті!

Перетворюється на одинарний, а потім повторюйте наступні заміни (показані тут у десятковій кількості):

122 -> 000
0002 -> 1100 (this can also be 0012 -> 1110 and 1112 -> 2210 or even 2222 -> 3320 or even 3333 -> 4431)

В основному, коли більше двох: забрати два, не додати нічого до попередньої цифри, додати до попередньої цифри, а потім додати до попередньої цифри.

У псевдокоді:

if(a[n]>2):
    a[n] -= 2;
    a[n-2] += 1;
    a[n-3] += 1;

Унітарна реалізація:

Кожна цифра (наприклад 3) відображається як число xs (наприклад xxx), а потім префіксом 0.

Наприклад, 1234виражатиметься як 0x0xx0xxx0xxxx.

Це залишається 0незмінним, як 101би було виражено 0x00x.

Оскільки спочатку і, нарешті, є тільки 0і 1, перетворення може бути легко здійснено за допомогою 1->0xі 0x->1.

Натисніть тут, щоб побачити кожен крок .


1

JavaScript (ES6), 146 126 байт

r=n=>n&&n%2-r(n>>=1)-i(n)
i=n=>n&&r(n>>=1)-i(n)
g=(x,y,b=(x^y)&1)=>x|y&&b+2*g(b-x+y>>1,b-x-y>>1)
(x,y)=>g(r(x)+r(y),i(x)+i(y))

g перетворює ціле число Гаусса (реальна і уявна частини) в базу i-1 , в той час , rі iперетворює базове i-1число в гауссовское ціле (дійсні та уявні частини , відповідно). Після того, як перетворення відбудуться, я просто повинен виконати арифметику.

Редагувати: Збережено 20 байт шляхом обчислення реальних та уявних частин окремо.


1

C ++ 416 байт плюс #include <vector>\n#include <algorithm>\n(ще 40)

using I=int;using v=std::vector<I>;void r(v&x){v r{rbegin(x),rend(x)};x=r;}v a(v L,v R){r(L);r(R);L.resize(std::max(L.size(),R.size()));for(int&r:R)L[&r-R.data()]+=r;while(1){L.resize(L.size()+3);auto it=find(rbegin(L),rend(L),2);if(it==rend(L))break;I i=-1+it.base()-begin(L);i&&L[i+1]&&L[i-1]/2?L[i+1]=L[i]=L[i-1]=0:(++L[i+2],++L[i+3],L[i]=0);}L.erase( std::find(rbegin(L),rend(L),1).base(),end(L));r(L);return L;}

або, з більшою кількістю пробілів:

using I=int;
using v=std::vector<I>;

void r(v&x){v r{rbegin(x),rend(x)};x=r;}
v a(v L,v R) {
  r(L);r(R);
  L.resize(std::max(L.size(),R.size()));
  for(int&r:R)
    L[&r-R.data()]+=r;
  while(1) {
    L.resize(L.size()+3);
    auto it=find(rbegin(L), rend(L), 2);
    if(it==rend(L)) break;
    I i=-1+it.base()-begin(L);
    i&&L[i+1]&&L[i-1]/2?
      L[i+1]=L[i]=L[i-1]=0
    :
      (++L[i+2],++L[i+3],L[i]=0);
  }
  L.erase( std::find(rbegin(L),rend(L),1).base(), end(L));
  r(L);
  return L;
}

Ледь гольф. Він приймає введення як вектор ints і повертає вектор ints.

Живий приклад .

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