Розділіть число на 3, не використовуючи операторів *, /, +, -,%


684

Як би ви розділити число на 3 без використання *, /, +, -, %, операторів?

Номер може бути підписаним або без підпису.


13
@AlexandreC. - хоча ці методи використовують додавання (+).
хетч - зроблено з SOverflow

19
Це був оракул, тому які частини оракула вам дозволяли використовувати?
Хоган

8
Ідентифікований дублікат не є копією. Зауважте, що кілька відповідей тут не використовують ні зміщення бітів, ні доповнення, оскільки це питання не обмежувало рішення цих операцій.
Майкл Берр

66
... і ось як народжується PL / SQL.
Седат Капаноглу

22
Це питання не відповідає темі. Належить до codegolf.stackexchange.com
Кромстер

Відповіді:


548

Це проста функція, яка виконує потрібну операцію. Але для цього потрібен +оператор, тому все, що вам залишилося зробити, - це додати значення за допомогою операторів біт:

// replaces the + operator
int add(int x, int y)
{
    while (x) {
        int t = (x & y) << 1;
        y ^= x;
        x = t;
    }
    return y;
}

int divideby3(int num)
{
    int sum = 0;
    while (num > 3) {
        sum = add(num >> 2, sum);
        num = add(num >> 2, num & 3);
    }
    if (num == 3)
        sum = add(sum, 1);
    return sum; 
}

Як коментував Джим, це працює, тому що:

  • n = 4 * a + b
  • n / 3 = a + (a + b) / 3
  • Таким чином sum += a, n = a + bі ітерація

  • Коли a == 0 (n < 4), sum += floor(n / 3);тобто 1,if n == 3, else 0


96
Це, мабуть, відповідь, яку шукає Oracle. Це показує, що ви знаєте, як оператори +, -, * та / реалізуються на процесорі: прості побітні операції.
craig65535

21
Це працює, тому що n = 4a + b, n / 3 = a + (a + b) / 3, тому сума + = a, n = a + b і ітерація. Коли a == 0 (n <4), сума + = пол (n / 3); тобто 1, якщо n == 3, інакше 0.
Джим Балтер

7
Ось трюк, який я знайшов, який отримав мені подібне рішення. У десятковій формі: 1 / 3 = 0.333333повторювані числа полегшують обчислення за допомогою a / 3 = a/10*3 + a/100*3 + a/1000*3 + (..). У бінарному це майже те саме:, 1 / 3 = 0.0101010101 (base 2)що призводить до a / 3 = a/4 + a/16 + a/64 + (..). Ділення на 4 - це звідки походить бітовий зсув. Остання перевірка на num == 3 потрібна, тому що у нас є лише цілі числа для роботи.
Йорк Сійслінг

4
У базі 4 вона стає ще краще: a / 3 = a * 0.111111 (base 4) = a * 4^-1 + a * 4^-2 + a * 4^-3 + (..) = a >> 2 + a >> 4 + a >> 6 + (..). Основа 4 також пояснює, чому лише 3 закріплені в кінці, тоді як 1 і 2 можуть бути округлені вниз.
Йорк Сійслінг

2
@ while1: це побіт І операція. Також загальновідомим фактом є те, що для n == 2^kнаступного вірно:, x % n == x & (n-1)тому тут num & 3використовується для виконання, num % 4поки %не дозволено.
аплавін

436

Ідіотичні умови вимагають ідіотичного рішення:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    FILE * fp=fopen("temp.dat","w+b");
    int number=12346;
    int divisor=3;
    char * buf = calloc(number,1);
    fwrite(buf,number,1,fp);
    rewind(fp);
    int result=fread(buf,divisor,number,fp);
    printf("%d / %d = %d", number, divisor, result);
    free(buf);
    fclose(fp);
    return 0;
}

Якщо також потрібна десяткова частина, просто оголосіть resultяк doubleі додайте до неї результат fmod(number,divisor).

Пояснення, як це працює

  1. В fwriteзаписує numberбайт (число є 123456 в прикладі вище).
  2. rewind скидає вказівник на передню частину файлу.
  3. freadзчитує максимум number"записів", що мають divisorдовжину з файлу, і повертає кількість прочитаних елементів.

Якщо ви запишете 30 байт, а потім прочитаєте файл назад у 3 одиниці, ви отримаєте 10 "одиниць". 30/3 = 10


13
@earlNameless: ви не знаєте, що вони використовують всередині, вони знаходяться в чорному полі "визначено реалізацією". Ніщо не заважає їм просто використовувати побітові оператори; у будь-якому випадку вони знаходяться поза доменом мого коду, тому це не моя проблема. :)
Маттео Італія

8
@ IvoFlipse від Я можу почистити, ти дістаєш щось велике і зашпурляєш його в щось утричі занадто мале, а потім побачиш, скільки вміщено. Це приблизно третина.
Pureferret

27
попросив найкращого програміста з C (і найбільш соціально незручного) в нашій компанії пояснити код. після цього я сказав, що це було досить геніально. Він сказав, що "ця криза не є рішенням" і попросив мене залишити його стіл
курвуш

6
@cvursache Я думаю, що справа в тому, що настільки мозок загинув, що відповідь на мертвий мозок дозволена. "Найкращий програміст C" у вашій компанії "так само легко міг би сказати," що криза не є (належним) питанням ".
JeremyP

17
@JeremyP: точно. Моя думка полягає в тому, що якби в реальному житті мені дали компілятор без підтримки арифметики, єдиним розумним було б попросити кращого компілятора , оскільки працювати в цих умовах не має сенсу. Якщо інтерв'юер хотів перевірити мої знання про те, як здійснити поділ за допомогою побітних операцій, він міг би бути простою і задати це як теоретичне запитання; такі "трюкові вправи" просто кричать за відповіді, як це.
Matteo Italia

306
log(pow(exp(number),0.33333333333333333333)) /* :-) */

2
Це насправді може спрацювати, якщо їх правильно округлити і якщо число не надто велике.
Містичний

252
Удосконалена версія: log (pow (exp (кількість), sin (atan2 (1, sqrt (8))))))
Alan Curry

@bitmask, математичні функції зазвичай реалізуються безпосередньо в ASM.
SingerOfTheFall

7
я просто набрав його на моїй консолі js, вона не працює з номером вище 709 (можливо, це лише моя система) Math.log(Math.pow(Math.exp(709),0.33333333333333333333))іMath.log(Math.pow(Math.exp(709),Math.sin(Math.atan2(1,Math.sqrt(8)))))
Shaheer

208
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{

    int num = 1234567;
    int den = 3;
    div_t r = div(num,den); // div() is a standard C function.
    printf("%d\n", r.quot);

    return 0;
}

113

Ви можете використовувати вбудовану вбудову (залежно від платформи), наприклад, для x86: (також працює для від'ємних чисел)

#include <stdio.h>

int main() {
  int dividend = -42, divisor = 5, quotient, remainder;

  __asm__ ( "cdq; idivl %%ebx;"
          : "=a" (quotient), "=d" (remainder)
          : "a"  (dividend), "b"  (divisor)
          : );

  printf("%i / %i = %i, remainder: %i\n", dividend, divisor, quotient, remainder);
  return 0;
}

2
@JeremyP ваш коментар не провалюється при припущенні, що відповідь не можна записати на С? Зрештою питання позначено "C".
Сет Карнегі

1
@SethCarnegie Відповідь не написана на мові C. x86 ассемблер не входить до стандарту.
JeremyP

1
@JeremyP це правда, але asmдиректива така. І я хотів би додати, що компілятори C - не єдині, у кого є вбудовані асемблери, Delphi - це також.
Сет Карнегі

7
@SethCarnegie asmДиректива згадується лише у стандарті C99 у Додатку J - загальні розширення.
JeremyP

2
Невдачі в arm-eabi-gcc.
Damian Yerrick

106

Використовуйте itoa для перетворення в базовий 3 рядок. Відкиньте останній трит і перетворіть назад на базу 10.

// Note: itoa is non-standard but actual implementations
// don't seem to handle negative when base != 10.
int div3(int i) {
    char str[42];
    sprintf(str, "%d", INT_MIN); // Put minus sign at str[0]
    if (i>0)                     // Remove sign if positive
        str[0] = ' ';
    itoa(abs(i), &str[1], 3);    // Put ternary absolute value starting at str[1]
    str[strlen(&str[1])] = '\0'; // Drop last digit
    return strtol(str, NULL, 3); // Read back result
}

4
@cshemby Я насправді не знав, що itoaможе використовувати довільну базу. Якщо ви виконаєте повну робочу реалізацію за допомогою, itoaя підкреслюю.
Містичний

2
Реалізація буде містити /і %... :-)
R .. GitHub СТОП ДОПОМОГА ВІД

2
@R .. Так само і реалізація printfдля відображення десяткового результату.
Даміян Єрік

57

(зверніть увагу: див. Редагування 2 нижче для кращої версії!)

Це не так складно, як це звучить, тому що ви сказали "без використання операторів [..] +[..] ". Дивіться нижче, якщо ви хочете заборонити використовувати символ разом.+

unsigned div_by(unsigned const x, unsigned const by) {
  unsigned floor = 0;
  for (unsigned cmp = 0, r = 0; cmp <= x;) {
    for (unsigned i = 0; i < by; i++)
      cmp++; // that's not the + operator!
    floor = r;
    r++; // neither is this.
  }
  return floor;
}

то просто скажіть div_by(100,3)ділити 100на 3.


Редагувати : Ви також можете продовжити та замінити ++оператора:

unsigned inc(unsigned x) {
  for (unsigned mask = 1; mask; mask <<= 1) {
    if (mask & x)
      x &= ~mask;
    else
      return x & mask;
  }
  return 0; // overflow (note that both x and mask are 0 here)
}

Редагування 2: Трохи швидше версія без використання будь-якого оператора , який містить +, -, *, /, % символи .

unsigned add(char const zero[], unsigned const x, unsigned const y) {
  // this exploits that &foo[bar] == foo+bar if foo is of type char*
  return (int)(uintptr_t)(&((&zero[x])[y]));
}

unsigned div_by(unsigned const x, unsigned const by) {
  unsigned floor = 0;
  for (unsigned cmp = 0, r = 0; cmp <= x;) {
    cmp = add(0,cmp,by);
    floor = r;
    r = add(0,r,1);
  }
  return floor;
}

Ми використовуємо перший аргумент addфункції, оскільки не можемо позначити тип покажчиків без використання *символу, за винятком списків параметрів функцій, де синтаксис type[]ідентичний type* const.

FWIW, ви можете легко реалізувати функцію множення, використовуючи аналогічний трюк, щоб використовувати 0x55555556трюк, запропонований AndreyT :

int mul(int const x, int const y) {
  return sizeof(struct {
    char const ignore[y];
  }[x]);
}

5
Питання позначено тегом c , а не SQL, навіть якщо згадується Oracle.
бітмаска

3
Це насправді не схоже на SQL!
moooeeeep

64
Якщо ви можете використовувати ++: Чому ви просто не використовуєте /=?
qwertz

5
@bitmask: ++також є ярликом: для num = num + 1.
qwertz

4
@bitmask Так, але +=, нарешті, це ярлик для num = num + 1.
qwertz

44

Це легко можливо на комп’ютері Setun .

Щоб розділити ціле число на 3, змістіть праворуч на 1 місце .

Я не впевнений, чи можливо на такій платформі реалізувати відповідний компілятор C. Можливо, нам доведеться трохи розтягнути правила, наприклад, інтерпретувати "принаймні 8 біт" як "здатні містити принаймні цілі числа від -128 до +127".


8
Проблема полягає в тому, що у вас немає оператора "зсув право на 1 місце" в C. >>Оператор - це оператор "ділення на 2 ^ n", тобто він задається з точки зору арифметичного, а не машинного подання.
R .. GitHub СТОП ДОПОМОГА ВІД

Комп'ютер Setun не є двійковим у будь-якому сенсі цього слова, тому набір інструкцій повинен бути безумовно іншим. Однак я зовсім не знайомий з роботою цього комп’ютера, тому не можу підтвердити, чи відповідь справді правильний - але, принаймні, має сенс - і дуже оригінальний. +1
virolino


32

Ось моє рішення:

public static int div_by_3(long a) {
    a <<= 30;
    for(int i = 2; i <= 32 ; i <<= 1) {
        a = add(a, a >> i);
    }
    return (int) (a >> 32);
}

public static long add(long a, long b) {
    long carry = (a & b) << 1;
    long sum = (a ^ b);
    return carry == 0 ? sum : add(carry, sum);
}

Спочатку зауважте, що

1/3 = 1/4 + 1/16 + 1/64 + ...

Тепер інше просто!

a/3 = a * 1/3  
a/3 = a * (1/4 + 1/16 + 1/64 + ...)
a/3 = a/4 + a/16 + 1/64 + ...
a/3 = a >> 2 + a >> 4 + a >> 6 + ...

Тепер все, що нам потрібно зробити, це скласти ці бітові зміщені значення a! На жаль! Ми не можемо додати, хоча, замість цього, нам доведеться написати функцію додавання за допомогою бітових операторів! Якщо ви знайомі з дотепними операторами, моє рішення повинно виглядати досить просто ... але на випадок, якщо ви цього не зробите, я перегляну приклад наприкінці.

Ще одне, що слід зазначити, що спочатку я зміщу ліворуч на 30! Це робиться для того, щоб дроби не округлилися.

11 + 6

1011 + 0110  
sum = 1011 ^ 0110 = 1101  
carry = (1011 & 0110) << 1 = 0010 << 1 = 0100  
Now you recurse!

1101 + 0100  
sum = 1101 ^ 0100 = 1001  
carry = (1101 & 0100) << 1 = 0100 << 1 = 1000  
Again!

1001 + 1000  
sum = 1001 ^ 1000 = 0001  
carry = (1001 & 1000) << 1 = 1000 << 1 = 10000  
One last time!

0001 + 10000
sum = 0001 ^ 10000 = 10001 = 17  
carry = (0001 & 10000) << 1 = 0

Done!

Це просто доповнення, яке ви навчилися ще в дитинстві!

111
 1011
+0110
-----
10001

Ця реалізація не вдалася, оскільки ми не можемо додати всі умови рівняння:

a / 3 = a/4 + a/4^2 + a/4^3 + ... + a/4^i + ... = f(a, i) + a * 1/3 * 1/4^i
f(a, i) = a/4 + a/4^2 + ... + a/4^i

Припустімо, тоді знаходження div_by_3(a)= x x <= floor(f(a, i)) < a / 3. Коли a = 3kми отримуємо неправильну відповідь.


2
це працює для введення 3? 1/4, 1/16, ... всі повертають 0 за 3, тож дорівнюватиме 0, але 3/3 = 1.
хетч - зроблено з SOverflow

1
Логіка хороша, але реалізація є проблематичною. Наближення ряду n/3завжди менше, ніж n/3це означає, що для будь-якого n=3kрезультату було б k-1замість k.
Xyand

@Albert, Це був перший підхід, який я спробував, з декількома варіаціями, але всі вони зазнали невдачі на певних числах, рівномірно поділених на 3, або рівномірно поділених на 2 (залежно від варіації). Тож я спробував щось більш відверте. Я хотів би бачити реалізацію цього підходу, який працює, бачити, де я накручувався.
хетч - зроблено з SOverflow

@hatchet, Питання закрите, тому я не можу опублікувати нову відповідь, але ідея полягає у впровадженні двійкового діва. Мені повинно бути легко подивитися.
Xyand


25

Для поділу 32-бітного числа на 3 можна помножити його на, 0x55555556а потім взяти верхні 32 біти результату 64 біт.

Тепер все, що залишилося зробити, це реалізувати множення, використовуючи бітові операції та зрушення ...


1
Це звичайний трюк компілятора для подолання повільних поділів. Але вам, ймовірно, потрібно зробити деякі виправлення, оскільки 0x55555556 / 2 ** 32 не зовсім 1/3.
CodesInChaos

multiply it. Це не означатиме використання забороненого *оператора?
luiscubal

8
@luiscubal: Ні, не буде. Ось чому я сказав: «Тепер все, що залишилося зробити, - це реалізувати множення за допомогою бітових операцій та зрушень »
AnT

18

Ще одне рішення. Це має обробляти всі int (включаючи негативні int), за винятком мінімального значення int, яке потрібно обробляти як жорстко кодований виняток. В основному це ділення на віднімання, але тільки з використанням бітових операторів (shift, xor, & та доповнення). Для більшої швидкості він віднімає 3 * (зменшуючи потужність на 2). У c # він виконує близько 444 цих викликів DivideBy3 за мілісекунд (2,2 секунди за 1 000 000 ділення), так що не жахливо повільно, але ні там, де поруч так швидко, як простий х / 3. Для порівняння, приємне рішення Coodey приблизно в 5 разів швидше, ніж це.

public static int DivideBy3(int a) {
    bool negative = a < 0;
    if (negative) a = Negate(a);
    int result;
    int sub = 3 << 29;
    int threes = 1 << 29;
    result = 0;
    while (threes > 0) {
        if (a >= sub) {
            a = Add(a, Negate(sub));
            result = Add(result, threes);
        }
        sub >>= 1;
        threes >>= 1;
    }
    if (negative) result = Negate(result);
    return result;
}
public static int Negate(int a) {
    return Add(~a, 1);
}
public static int Add(int a, int b) {
    int x = 0;
    x = a ^ b;
    while ((a & b) != 0) {
        b = (a & b) << 1;
        a = x;
        x = a ^ b;
    }
    return x;
}

Це c #, тому що це мені було в нагоді, але відмінності від c повинні бути незначними.


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

Чи (a >= sub)вважається відніманням?
Ніл

@Neil, я думаю, ти можеш мати рацію. Внутрішній час можна замінити простим, якщо зберегти непотрібне порівняння від другої ітерації циклу. Щодо> = віднімання ... я сподіваюся, що ні, тому що це зробило б це досить важко! Я бачу вашу думку, але я думаю, що я сперся на бік, який говорить> = не вважається відніманням.
хетч - зроблено з SOverflow

@Neil, я вніс цю зміну, яка скоротила час навпіл (також зберегла зайві Негати).
хетч - зроблено з SOverflow

16

Це дійсно досить просто.

if (number == 0) return 0;
if (number == 1) return 0;
if (number == 2) return 0;
if (number == 3) return 1;
if (number == 4) return 1;
if (number == 5) return 1;
if (number == 6) return 2;

(Я, звичайно, частину програми пропустив заради стислості.) Якщо програміст втомився вводити все це, я впевнений, що він або вона могли написати окрему програму, щоб створити його для нього. Я, мабуть, знаю певного оператора /, що б дуже спростило його роботу.


8
Ви можете використовувати Dictionary<number, number>замість повторних ifтверджень, щоб мати O(1)складність у часі!
Пітер Олсон

@EnesUnal Ні, час збільшується лінійно, оскільки число збільшується, тому що йому доведеться все більше переходити, якщо заяви.
Пітер Олсон

Теоретично вона не збільшується :)
Totten

@PeterOlson, EresUnal, якби я використав оператор переключення, це було б O (1) :-)
thedayturns

Або ви можете генерувати масив та використовувати динамічне програмування. якщо x / 3 = y, то y << 2 + y = x - x% 3.
lsiebert

14

Використання лічильників є основним рішенням:

int DivBy3(int num) {
    int result = 0;
    int counter = 0;
    while (1) {
        if (num == counter)       //Modulus 0
            return result;
        counter = abs(~counter);  //++counter

        if (num == counter)       //Modulus 1
            return result;
        counter = abs(~counter);  //++counter

        if (num == counter)       //Modulus 2
            return result;
        counter = abs(~counter);  //++counter

        result = abs(~result);    //++result
    }
}

Також легко виконувати функцію модуля, перевірити коментарі.


@Enes Unal: не для малих чисел :) Цей алгоритм дуже простий.
GJ.

Кожна примітивність включає слабкі місця :)
Totten

11

Цей алгоритм класичного поділу в базі 2:

#include <stdio.h>
#include <stdint.h>

int main()
{
  uint32_t mod3[6] = { 0,1,2,0,1,2 };
  uint32_t x = 1234567; // number to divide, and remainder at the end
  uint32_t y = 0; // result
  int bit = 31; // current bit
  printf("X=%u   X/3=%u\n",x,x/3); // the '/3' is for testing

  while (bit>0)
  {
    printf("BIT=%d  X=%u  Y=%u\n",bit,x,y);
    // decrement bit
    int h = 1; while (1) { bit ^= h; if ( bit&h ) h <<= 1; else break; }
    uint32_t r = x>>bit;  // current remainder in 0..5
    x ^= r<<bit;          // remove R bits from X
    if (r >= 3) y |= 1<<bit; // new output bit
    x |= mod3[r]<<bit;    // new remainder inserted in X
  }
  printf("Y=%u\n",y);
}

10

Напишіть програму на Паскалі та скористайтеся DIVоператором.

Оскільки питання позначено тегами ви, ймовірно, можете написати функцію в Pascal і викликати її зі своєї програми C; метод для цього є специфічним для системи.

Але ось приклад, який працює в моїй системі Ubuntu із fp-compilerвстановленим пакетом Free Pascal . (Я роблю це з чистої неправильної впертості; я не стверджую, що це корисно.)

divide_by_3.pas :

unit Divide_By_3;
interface
    function div_by_3(n: integer): integer; cdecl; export;
implementation
    function div_by_3(n: integer): integer; cdecl;
    begin
        div_by_3 := n div 3;
    end;
end.

main.c :

#include <stdio.h>
#include <stdlib.h>

extern int div_by_3(int n);

int main(void) {
    int n;
    fputs("Enter a number: ", stdout);
    fflush(stdout);
    scanf("%d", &n);
    printf("%d / 3 = %d\n", n, div_by_3(n));
    return 0;
}

Будувати:

fpc divide_by_3.pas && gcc divide_by_3.o main.c -o main

Виконання зразка:

$ ./main
Enter a number: 100
100 / 3 = 33

8
int div3(int x)
{
  int reminder = abs(x);
  int result = 0;
  while(reminder >= 3)
  {
     result++;

     reminder--;
     reminder--;
     reminder--;
  }
  return result;
}

3
++ і - оператори відрізняються від + та - операторів! У мові складання є дві інструкції ADDі INCпро те, що вони не мають однакових опдодів.
Амір Саніян

7

Не здійснив перехресну перевірку, чи ця відповідь уже опублікована. Якщо програму потрібно розширити до плаваючих чисел, числа можна помножити на 10 * потрібну точність, а потім знову можна застосувати наступний код.

#include <stdio.h>

int main()
{
    int aNumber = 500;
    int gResult = 0;

    int aLoop = 0;

    int i = 0;
    for(i = 0; i < aNumber; i++)
    {
        if(aLoop == 3)
        {
           gResult++;
           aLoop = 0;
        }  
        aLoop++;
    }

    printf("Reulst of %d / 3 = %d", aNumber, gResult);

    return 0;
}

7

Це повинно працювати для будь-якого дільника, а не лише для трьох. Наразі лише для непідписаних, але продовження його до підписаного не повинно бути таким складним.

#include <stdio.h>

unsigned sub(unsigned two, unsigned one);
unsigned bitdiv(unsigned top, unsigned bot);
unsigned sub(unsigned two, unsigned one)
{
unsigned bor;
bor = one;
do      {
        one = ~two & bor;
        two ^= bor;
        bor = one<<1;
        } while (one);
return two;
}

unsigned bitdiv(unsigned top, unsigned bot)
{
unsigned result, shift;

if (!bot || top < bot) return 0;

for(shift=1;top >= (bot<<=1); shift++) {;}
bot >>= 1;

for (result=0; shift--; bot >>= 1 ) {
        result <<=1;
        if (top >= bot) {
                top = sub(top,bot);
                result |= 1;
                }
        }
return result;
}

int main(void)
{
unsigned arg,val;

for (arg=2; arg < 40; arg++) {
        val = bitdiv(arg,3);
        printf("Arg=%u Val=%u\n", arg, val);
        }
return 0;
}

7

Чи було б обманом використовувати /оператора "за кадром", використовуючи evalі строкову конкатенацію?

Наприклад, у Javacript ви можете це зробити

function div3 (n) {
    var div = String.fromCharCode(47);
    return eval([n, div, 3].join(""));
}

7

Використання BC Math в PHP :

<?php
    $a = 12345;
    $b = bcdiv($a, 3);   
?>

MySQL (це інтерв'ю від Oracle)

> SELECT 12345 DIV 3;

Паскаль :

a:= 12345;
b:= a div 3;

x86-64 мова складання:

mov  r8, 3
xor  rdx, rdx   
mov  rax, 12345
idiv r8

1
Класна історія, це позначено мовою C і так було з першого дня. Крім того, ви повністю не розумієте суть питання.
Лундін

6

По-перше, що я придумав.

irb(main):101:0> div3 = -> n { s = '%0' + n.to_s + 's'; (s % '').gsub('   ', ' ').size }
=> #<Proc:0x0000000205ae90@(irb):101 (lambda)>
irb(main):102:0> div3[12]
=> 4
irb(main):103:0> div3[666]
=> 222

EDIT: Вибачте, я не помітив тег C. Але ви можете використовувати ідею про форматування рядків, я думаю ...


5

Наступний скрипт створює програму C, яка вирішує проблему без використання операторів * / + - %:

#!/usr/bin/env python3

print('''#include <stdint.h>
#include <stdio.h>
const int32_t div_by_3(const int32_t input)
{
''')

for i in range(-2**31, 2**31):
    print('    if(input == %d) return %d;' % (i, i / 3))


print(r'''
    return 42; // impossible
}
int main()
{
    const int32_t number = 8;
    printf("%d / 3 = %d\n", number, div_by_3(number));
}
''')


4

Як щодо цього підходу (c #)?

private int dividedBy3(int n) {
        List<Object> a = new Object[n].ToList();
        List<Object> b = new List<object>();
        while (a.Count > 2) {
            a.RemoveRange(0, 3);
            b.Add(new Object());
        }
        return b.Count;
    }

Це позначено тегом C і так було з першого дня.
Лундін

4

Я думаю, що правильна відповідь:

Чому я б не використовував базовий оператор для виконання базової операції?


Тому що те, що вони хочуть знати, це, якщо ви знаєте, як працює процесор внутрішньо ... використовуючи математичний оператор, врешті-решт виконаєте операцію, дуже схожу на вищезазначену відповідь.
RaptorX

Або хочуть дізнатися, чи зможете ви визнати марну проблему.
Грегуар

1
@Gregoire Я погоджуюсь, що абобоуллі не потребує такої реалізації, Біт у комерційному житті (Orcale) не потрібно виконувати марні вимоги: Правильна відповідь: "Це зовсім не має сенсу, навіщо втрачати гроші за це? »)
AlexWien

4

Рішення за допомогою функції бібліотеки fma () працює для будь-якого додатного числа:

#include <stdio.h>
#include <math.h>

int main()
{
    int number = 8;//Any +ve no.
    int temp = 3, result = 0;
    while(temp <= number){
        temp = fma(temp, 1, 3); //fma(a, b, c) is a library function and returns (a*b) + c.
        result = fma(result, 1, 1);
    } 
    printf("\n\n%d divided by 3 = %d\n", number, result);
}

Дивіться ще одну мою відповідь .


Приємне використання бібліотеки. Чому ви безпосередньо не використовували результат ++?
Зелений гоблін

тоді люди можуть сказати, що + було використано.
Вісім

3

Використовуйте cblas , що входить до складу Accelerate Framework OS X.

[02:31:59] [william@relativity ~]$ cat div3.c
#import <stdio.h>
#import <Accelerate/Accelerate.h>

int main() {
    float multiplicand = 123456.0;
    float multiplier = 0.333333;
    printf("%f * %f == ", multiplicand, multiplier);
    cblas_sscal(1, multiplier, &multiplicand, 1);
    printf("%f\n", multiplicand);
}

[02:32:07] [william@relativity ~]$ clang div3.c -framework Accelerate -o div3 && ./div3
123456.000000 * 0.333333 == 41151.957031

Ну, це була лише детальна інформація про реалізацію, щоб я міг її набрати як 3.0 / 1.0 замість 0.333333, але я повинен грати за правилами. Виправлено!
wjl

Спочатку у мене це було 3.0 / 1.0, що було в моєму тесті. Використовуючи більш високу точність, вони повинні отримати досить точний результат. gist.github.com/3401496
wjl

3

Як правило, рішенням цього рішення було б:

log(pow(exp(numerator),pow(denominator,-1)))


3

Спочатку:

x/3 = (x/4) / (1-1/4)

Тоді з’ясуйте, як розв’язати x / (1 - y):

x/(1-1/y)
  = x * (1+y) / (1-y^2)
  = x * (1+y) * (1+y^2) / (1-y^4)
  = ...
  = x * (1+y) * (1+y^2) * (1+y^4) * ... * (1+y^(2^i)) / (1-y^(2^(i+i))
  = x * (1+y) * (1+y^2) * (1+y^4) * ... * (1+y^(2^i))

з у = 1/4:

int div3(int x) {
    x <<= 6;    // need more precise
    x += x>>2;  // x = x * (1+(1/2)^2)
    x += x>>4;  // x = x * (1+(1/2)^4)
    x += x>>8;  // x = x * (1+(1/2)^8)
    x += x>>16; // x = x * (1+(1/2)^16)
    return (x+1)>>8; // as (1-(1/2)^32) very near 1,
                     // we plus 1 instead of div (1-(1/2)^32)
}

Хоча він використовує +, але хтось уже реалізує додавання по побітній оп.

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