Разделите число на 3 без использования операторов *, /, +, -,%


686

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

Номер может быть подписан или не подписан.


13
@AlexandreC. - эти методы используют сложение (+), хотя.
топор - сделано с SOverflow

19
Это был оракул, так какие части оракула вам разрешали использовать?
Хоган

8
Идентифицированный дубликат не является дубликатом. Обратите внимание, что в некоторых ответах здесь не используется ни сдвиг битов, ни сложение, поскольку этот вопрос не ограничивал решение этих операций.
Майкл Барр

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

23
Этот вопрос является оффтопом для SO. Это принадлежит codegolf.stackexchange.com
Kromster

Ответы:


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. Он показывает, что вы знаете, как операторы +, -, * и / на самом деле реализованы на CPU: простые побитовые операции.
craig65535

21
Это работает, потому что n = 4a + b, n / 3 = a + (a + b) / 3, поэтому сумма + = a, n = a + b и итерация. Когда a == 0 (n <4), sum + = floor (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: вы не знаете, что они используют внутри, они находятся в черном ящике «определена реализация». Ничто не мешает им просто использовать побитовые операторы; во всяком случае, они находятся вне области моего кода, так что это не моя проблема. :)
Matteo Italia

8
@IvoFlipse от Я могу убрать, вы получаете что-то большое и толкаете это во что-то в три раза меньше, а затем смотрите, как много вписывается. Это примерно треть.
Pureferret

27
попросил лучшего программиста на Си (и самого неуклюжего) в нашей компании объяснить код. после того, как он это сделал, я сказал, что это было довольно изобретательно. Он сказал, что «эта штука не является решением проблемы» и попросил меня покинуть его стол
cvursache

6
@cvursache Я думаю, дело в том, что вопрос настолько умственно отсталый, что ответ отмертвым разрешен. «Лучший программист на Си» в вашей компании «с такой же легкостью мог бы сказать« что dreck - это не (правильный) вопрос ».
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.
Дамиан Йеррик

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 STOP HELPING ICE

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

57

(примечание: см. Edit 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 место» в Си. >>Оператор - это оператор «деление на 2 ^ n», т.е. он задается в терминах арифметики, а не машинного представления.
R .. GitHub ОСТАНОВИТЬ ЛЬДА

Компьютер Setun не является двоичным в любом смысле этого слова, поэтому набор команд должен быть совершенно другим. Тем не менее, я совсем не знаком с работой этого компьютера, поэтому не могу подтвердить, является ли ответ действительно правильным - но, по крайней мере, имеет смысл - и является ли он весьма оригинальным. +1
Виролино


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, вопрос закрыт, поэтому я не могу опубликовать новый ответ, но идея в том, чтобы реализовать бинарный div. Мне должно быть легко найти это.
Xyand


25

Чтобы разделить 32-битное число на 3, можно умножить его на 0x55555556 и затем взять старшие 32 бита 64-битного результата.

Теперь осталось только выполнить умножение с использованием битовых операций и сдвигов ...


1
Это распространенная хитрость компилятора для обхода медленных делений. Но вам, вероятно, нужно сделать некоторые исправления, так как 0x55555556 / 2 ** 32 не совсем 1/3.
CodesInChaos

multiply it, Разве это не означает использование запрещенного *оператора?
luiscubal

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

18

Еще одно решение. Это должно обрабатывать все целые (включая отрицательные), кроме минимального значения типа int, которое должно обрабатываться как жестко закодированное исключение. Это в основном делает деление на вычитание, но только с использованием битовых операторов (сдвиги, xor и & и дополнение). Для более быстрой скорости вычитает 3 * (уменьшая степень 2). В c # он выполняет около 444 этих вызовов DivideBy3 в миллисекунду (2,2 секунды для 1000000 делений), поэтому не ужасающе медленно, но далеко не так быстро, как простой х / 3. Для сравнения, хорошее решение Куди примерно в 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 должны быть незначительными.


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

Считается ли (a >= sub)вычитанием?
Нил

@ Нил, я думаю, ты прав. Внутреннее while можно заменить простым if, сохранив ненужное сравнение из второй итерации цикла. Что касается> = вычитания ... Я надеюсь, что нет, потому что это сделало бы это довольно сложно! Я понимаю вашу точку зрения, но думаю, что склонялся бы к той стороне, которая говорит, что> = не считается вычитанием.
топор - сделано с 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 Нет, время увеличивается линейно с увеличением числа, потому что оно должно проходить все больше и больше операторов if.
Питер Олсон

Theoritically не увеличивает :)
Тоттен

@PeterOlson, EresUnal, если бы я использовал оператор switch, это было бы O (1) :-)
thedayturns

Или вы можете сгенерировать массив и использовать динамическое программирование. если x / 3 = y, то y << 2 + y = x - x% 3.
Либерт

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: не для небольших чисел :) Этот алгоритм очень прост.
ГДж.

Каждый примитивность включает в себя слабые :)
Тоттен

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

РЕДАКТИРОВАТЬ: Извините, я не заметил тег 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 , входящий в состав OS X Accelerate Framework.

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