Podziel liczbę przez 3 bez użycia operatorów *, /, +, -,%

684

W jaki sposób można podzielić liczbę przez 3 bez używania *, /, +, -, %, operatorów?

Numer może być podpisany lub niepodpisany.

nieznanych
źródło
13
@AlexandreC. - te techniki wykorzystują jednak dodawanie (+).
topór - wykonane SOverflow
19
To była wyrocznia, więc z jakich części wyroczni wolno ci korzystać?
Hogan
8
Zidentyfikowany duplikat nie jest duplikatem. Zauważ, że kilka odpowiedzi tutaj nie używa przesunięcia ani dodawania bitów, ponieważ to pytanie nie ograniczyło rozwiązania do tych operacji.
Michael Burr,
66
... a oto jak powstaje PL / SQL.
Sedat Kapanoglu
22
To pytanie jest offtopiczne dla SO. Należy do codegolf.stackexchange.com
Kromster

Odpowiedzi:

548

Jest to prosta funkcja, która wykonuje żądaną operację. Wymaga to jednak +operatora, więc wystarczy, że dodasz wartości za pomocą operatorów bitowych:

// 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; 
}

Jak skomentował Jim, działa to, ponieważ:

  • n = 4 * a + b
  • n / 3 = a + (a + b) / 3
  • Tak sum += a, n = a + bi iterate

  • Kiedy a == 0 (n < 4), sum += floor(n / 3);tj. 1,if n == 3, else 0

qwertz
źródło
96
Jest to prawdopodobnie odpowiedź, której szuka Oracle. Pokazuje, że wiesz, jak operatory +, -, * i / są w rzeczywistości zaimplementowane w CPU: proste operacje bitowe.
craig65535
21
Działa to, ponieważ n = 4a + b, n / 3 = a + (a + b) / 3, więc sumuj + = a, n = a + b i iteruj. Gdy a == 0 (n <4), suma + = podłoga (n / 3); tj. 1, jeśli n == 3, w przeciwnym razie 0.
Jim Balter
7
Oto znaleziona sztuczka, która dała mi podobne rozwiązanie. W systemie dziesiętnym: 1 / 3 = 0.333333powtarzające się liczby ułatwiają obliczanie za pomocą a / 3 = a/10*3 + a/100*3 + a/1000*3 + (..). W systemie binarnym jest prawie tak samo 1 / 3 = 0.0101010101 (base 2):, co prowadzi do a / 3 = a/4 + a/16 + a/64 + (..). Dzielenie przez 4 jest źródłem przesunięcia bitów. Ostatnia kontrola na num == 3 jest potrzebna, ponieważ mamy tylko liczby całkowite do pracy.
Yorick Sijsling
4
W bazie 4 robi się jeszcze lepiej: a / 3 = a * 0.111111 (base 4) = a * 4^-1 + a * 4^-2 + a * 4^-3 + (..) = a >> 2 + a >> 4 + a >> 6 + (..). Baza 4 wyjaśnia również, dlaczego tylko 3 jest zaokrąglana w górę na końcu, podczas gdy 1 i 2 można zaokrąglać w dół.
Yorick Sijsling
2
@ while1: bitowa operacja AND. Dobrze znany jest również fakt, że w tym przypadku n == 2^kjest prawda: x % n == x & (n-1)więc tutaj num & 3jest używany do wykonywania, num % 4podczas gdy %nie jest dozwolone.
aplavin
436

Warunki idiotyczne wymagają idiotycznego rozwiązania:

#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;
}

Jeśli potrzebna jest również część dziesiętna, po prostu zadeklaruj resultjako doublei dodaj do niej wynik fmod(number,divisor).

Wyjaśnienie, jak to działa

  1. Do fwritepisze numberbajtów (liczba wynosi 123456 w powyższym przykładzie).
  2. rewind resetuje wskaźnik pliku na początek pliku.
  3. freadodczytuje maksymalnie number„rekordy” divisordługości z pliku i zwraca liczbę odczytanych elementów.

Jeśli napiszesz 30 bajtów, a następnie ponownie odczytasz plik w jednostkach 3, otrzymasz 10 „jednostek”. 30/3 = 10

Matteo Italia
źródło
13
@ PearlNameless: nie wiesz, czego używają w środku, znajdują się w czarnej skrzynce „zdefiniowanej implementacji”. Nic nie powstrzymuje ich przed użyciem operatorów bitowych; w każdym razie są poza domeną mojego kodu, więc to nie mój problem. :)
Matteo Italia
8
@IvoFlipse od I mogę wyczyścić, dostajesz duże coś i wpychasz je w coś trzy razy za małe, a następnie sprawdzasz, jak bardzo się zmieści. To około jedna trzecia.
Pureferret
27
poprosił najlepszego programistę C (i najbardziej niezręcznego społecznie) w naszej firmie o wyjaśnienie kodu. kiedy to zrobił, powiedziałem, że to całkiem genialne. Powiedział „ten dreck nie jest rozwiązaniem” i poprosił mnie, abym opuścił biurko
cvursache
6
@cvursache Myślę, że chodzi o to, że pytanie jest tak martwe w mózgu, że dozwolona jest martwa odpowiedź mózgu. „Najlepszy programista C” w twojej firmie „równie łatwo mógłby powiedzieć„ że dreck nie jest (właściwym) pytaniem ”.
JeremyP
17
@JeremyP: dokładnie. Chodzi mi o to, że jeśli w prawdziwym życiu otrzymałbym kompilator bez obsługi arytmetyki, jedynym rozsądnym rozwiązaniem byłoby poproszenie o lepszy kompilator , ponieważ praca w takich warunkach nie ma sensu. Gdyby osoba przeprowadzająca wywiad chciała sprawdzić moją wiedzę o tym, jak wprowadzić podział za pomocą operacji bitowych, mógłby po prostu być prosty i zadać to pytanie teoretyczne; tego rodzaju „sztuczki” po prostu krzyczą na takie odpowiedzi.
Matteo Italia
306
log(pow(exp(number),0.33333333333333333333)) /* :-) */
Alan Curry
źródło
2
Może to faktycznie działać, jeśli zostanie poprawnie zaokrąglone, a liczba nie będzie zbyt duża.
Mysticial
252
Poprawiona wersja: log (pow (exp (liczba), sin (atan2 (1, sqrt (8)))))
Alan Curry
@bitmask, funkcje matematyczne są zwykle implementowane bezpośrednio w asm.
SingerOfTheFall,
7
właśnie wpisałem go w mojej konsoli js, nie działa z liczbą wyższą niż 709 (może to być tylko mój system) Math.log(Math.pow(Math.exp(709),0.33333333333333333333))iMath.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;
}
nos
źródło
113

Możesz użyć (zależnego od platformy) zestawu wbudowanego, np. Dla x86: (działa również dla liczb ujemnych)

#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;
}
moooeeeep
źródło
2
@JeremyP, czy Twój komentarz nie zawiedzie przy założeniu, że odpowiedzi nie można napisać w języku C? W końcu pytanie ma oznaczenie „C”.
Seth Carnegie
1
@SethCarnegie Odpowiedź nie jest napisana w C, o to mi chodzi. Asembler x86 nie jest częścią standardu.
JeremyP,
1
@JeremyP to prawda, ale asmdyrektywa jest. I dodałbym, że kompilatory C nie są jedynymi, które mają wbudowane asemblery, Delphi też to ma.
Seth Carnegie,
7
@SethCarnegie asmDyrektywa jest wymieniona tylko w standardzie C99 w Załączniku J - wspólne rozszerzenia.
JeremyP,
2
Nie działa w arm-eabi-gcc.
Damian Yerrick
106

Użyj itoa, aby przekonwertować na podstawowy ciąg 3. Upuść ostatni trit i przekonwertuj z powrotem na bazę 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
}
Alexandre Jasmin
źródło
4
@cshemby Właściwie to nie wiedziałem, że itoamożna użyć dowolnej bazy. Jeśli wykonasz pełną działającą implementację za pomocą itoa, będę głosować.
Mysticial
2
Realizacja będzie zawierać /i %... :-)
R .. GitHub ZATRZYMAJ POMOC ICE
2
@R .. Podobnie jak implementacja printfwyświetlania wyniku dziesiętnego.
Damian Yerrick
57

(uwaga: patrz Edycja 2 poniżej, aby uzyskać lepszą wersję!)

Nie jest to tak trudne, jak się wydaje, ponieważ powiedziałeś „bez użycia operatorów [..] +[..] ”. Zobacz poniżej, jeśli chcesz zabronić używania tej postaci razem.+

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

a potem po prostu powiedzieć, div_by(100,3)podzielić 100przez 3.


Edycja : Możesz także kontynuować i zastąpić ++operatora:

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

Edit 2: Nieco szybsza wersja bez użycia jakiegokolwiek operatora, który zawiera +, -, *, /, % znaki .

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

Używamy pierwszego argumentu addfunkcji, ponieważ nie możemy wskazać typu wskaźników bez użycia *znaku, z wyjątkiem list parametrów funkcji, w których składnia type[]jest identyczna type* const.

FWIW, możesz łatwo wdrożyć funkcję mnożenia za pomocą podobnej sztuczki, aby użyć 0x55555556sztuczki zaproponowanej przez AndreyT :

int mul(int const x, int const y) {
  return sizeof(struct {
    char const ignore[y];
  }[x]);
}
5 obrotów
źródło
5
Pytanie jest oznaczone jako c , a nie SQL, nawet jeśli wspomniano o Oracle.
maska ​​bitowa
3
To naprawdę nie wygląda jak SQL!
moooeeeep
64
Jeśli możesz użyć ++: Dlaczego nie używasz po prostu /=?
qwertz
5
@bitmask: ++to także skrót: For num = num + 1.
qwertz
4
@bitmask Tak, ale w +=końcu jest skrótem do num = num + 1.
qwertz
44

Jest to łatwo możliwe na komputerze Setun .

Aby podzielić liczbę całkowitą przez 3, przesuń w prawo o 1 miejsce .

Nie jestem jednak pewien, czy jest możliwe zaimplementowanie zgodnego kompilatora C na takiej platformie. Być może będziemy musieli nieco rozciągnąć reguły, na przykład interpretować „co najmniej 8 bitów” jako „zdolne do utrzymania co najmniej liczb całkowitych od -128 do +127”.

Ślimak mechaniczny
źródło
8
Problem polega na tym, że w C. nie >>ma operatora „przesunięcie o 1 miejsce”. Operator jest operatorem „dzielenia przez 2 ^ n”, tzn. Jest określony w kategoriach arytmetycznych, a nie reprezentacji maszyny.
R .. GitHub ZATRZYMAJ LÓD
Komputer Setun nie jest binarny w żadnym znaczeniu tego słowa, więc zestaw instrukcji musi być zdecydowanie inny. Jednak w ogóle nie znam działania tego komputera, więc nie mogę potwierdzić, czy odpowiedź jest naprawdę poprawna - ale przynajmniej ma sens - i jest bardzo oryginalna. +1
virolino,
32

Skoro pochodzi od Oracle, to co powiesz na tabelę wyszukiwania wstępnie obliczonych odpowiedzi. :-RE

Jeff Martin
źródło
32

Oto moje rozwiązanie:

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);
}

Po pierwsze, zwróć uwagę na to

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

Teraz reszta jest prosta!

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

Teraz wszystko, co musimy zrobić, to zsumować te nieco przesunięte wartości a! Ups! Nie możemy jednak dodawać, więc zamiast tego będziemy musieli napisać funkcję dodawania za pomocą bitowych operatorów! Jeśli znasz się na nieco bitowych operatorach, moje rozwiązanie powinno wyglądać dość prosto ... ale na wszelki wypadek, przejdę przez przykład na końcu.

Kolejną rzeczą do odnotowania jest to, że najpierw przesuwam w lewo o 30! Ma to na celu upewnienie się, że ułamki nie zostaną zaokrąglone.

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!

To po prostu dodatek, którego nauczyłeś się jako dziecko!

111
 1011
+0110
-----
10001

Ta implementacja nie powiodła się, ponieważ nie możemy dodać wszystkich warunków równania:

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

Załóżmy zatem, że reslut div_by_3(a)= x x <= floor(f(a, i)) < a / 3. Kiedy a = 3kotrzymujemy błędną odpowiedź.

tschultz
źródło
2
czy to działa dla wejścia 3? 1/4, 1/16, ... wszystkie zwracają 0 dla 3, więc sumują się do 0, ale 3/3 = 1.
topór - zrobione SOverflow
1
Logika jest dobra, ale wdrożenie jest problematyczne. Przybliżenie szeregu n/3jest zawsze mniejsze niż, n/3co oznacza, że ​​dla każdego n=3kwyniku byłby k-1zamiast k.
Xyand
@Albert, To było pierwsze podejście, które wypróbowałem, z kilkoma odmianami, ale wszystkie zawiodły w przypadku niektórych liczb podzielnych równomiernie przez 3 lub równomiernie podzielnych przez 2 (w zależności od odmiany). Więc spróbowałem czegoś prostszego. Chciałbym zobaczyć wdrożenie tego podejścia, które działa, aby zobaczyć, gdzie popieprzyłem.
topór - wykonane przy pomocy SOverflow
@hatchet, Pytanie jest zamknięte, więc nie mogę opublikować nowej odpowiedzi, ale pomysł polega na wdrożeniu binarnego div. Powinienem łatwo to sprawdzić.
Xyand
25

Aby podzielić liczbę 32-bitową przez 3, można ją pomnożyć, 0x55555556a następnie pobrać 32 górne bity wyniku 64-bitowego.

Teraz pozostaje tylko zaimplementować mnożenie za pomocą operacji bitowych i przesunięć ...

Mrówka
źródło
1
Jest to powszechna sztuczka kompilatora do obejścia powolnych podziałów. Ale prawdopodobnie musisz zrobić kilka poprawek, ponieważ 0x55555556 / 2 ** 32 nie jest dokładnie 1/3.
CodesInChaos
multiply it. Czy nie oznaczałoby to użycia zabronionego *operatora?
luiscubal
8
@luiscubal: Nie, nie będzie. Właśnie dlatego powiedziałem: „Pozostało już tylko wykonać mnożenie za pomocą operacji bitowych i przesunięć
AnT
18

Jeszcze inne rozwiązanie. Powinno to obsługiwać wszystkie liczby całkowite (w tym liczby całkowite ujemne) oprócz wartości minimalnej liczby całkowitej, która musiałaby być traktowana jako wyjątek zakodowany na stałe. Zasadniczo robi to dzielenie przez odejmowanie, ale tylko przy użyciu operatorów bitowych (shift, xor i & i dopełnianie). Dla większej prędkości odejmuje 3 * (malejące moce 2). W c # wykonuje około 444 z tych wywołań DivideBy3 na milisekundę (2,2 sekundy na 1 000 000 podziałów), więc nie jest strasznie powolny, ale nie jest tak szybki jak zwykłe x / 3. Dla porównania, dobre rozwiązanie Coodeya jest około 5 razy szybsze niż to.

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

To jest c #, ponieważ miałem to pod ręką, ale różnice w stosunku do c powinny być niewielkie.

siekiera
źródło
Musisz tylko odjąć odejmowanie jeden raz, ponieważ gdybyś mógł odjąć go dwa razy, mógłbyś odjąć go od poprzedniej iteracji, gdy była dwa razy większa niż obecnie.
Neil
Czy (a >= sub)liczy się jako odejmowanie?
Neil
@Neil, myślę, że masz rację. Wewnętrzna chwila mogłaby zostać zastąpiona prostą, jeśli, oszczędzając niepotrzebnego porównania z drugiej iteracji pętli. Odnośnie> = odejmowania ... Mam nadzieję, że nie, bo to uczyniłoby to dość trudnym! Rozumiem twój punkt widzenia, ale myślę, że oparłbym się na stronie, która mówi> = nie liczy się jako odejmowanie.
topór - wykonane SOverflow
@Neil, dokonałem tej zmiany, co skróciło czas o połowę (uratowałem również niepotrzebne Negaty).
topór - wykonane SOverflow
16

To naprawdę bardzo proste.

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;

(Oczywiście pominąłem część programu ze względu na zwięzłość). Jeśli programista zmęczy się pisaniem tego wszystkiego, jestem pewien, że mógłby napisać osobny program, aby go wygenerować. Zdarza mi się wiedzieć o pewnym operatorze /, co znacznie uprościłoby jego pracę.

zwroty dnia
źródło
8
Możesz użyć Dictionary<number, number>zamiast powtarzanych ifinstrukcji, aby mieć O(1)złożoność czasu!
Peter Olson,
@EnesUnal Nie, czas rośnie liniowo wraz ze wzrostem liczby, ponieważ musi on przechodzić coraz więcej instrukcji if.
Peter Olson,
Teoretycznie nie rośnie :)
totten
@PeterOlson, EresUnal, gdybym użył instrukcji switch, byłby to O (1) :-)
thedayturns
Lub możesz wygenerować tablicę i użyć programowania dynamicznego. jeśli x / 3 = y, to y << 2 + y = x - x% 3.
lsiebert
14

Korzystanie z liczników to podstawowe rozwiązanie:

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

Łatwo jest również wykonać funkcję modułu, sprawdź komentarze.

GJ.
źródło
@Enes Unal: nie dla małych liczb :) Ten algorytm jest bardzo prosty.
GJ.
Każda prymitywność obejmuje słabości :)
zabrała
11

Ten jest klasycznym algorytmem podziału w bazie 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);
}
Eric Bainville
źródło
10

Napisz program w Pascal i użyj DIVoperatora.

Ponieważ pytanie jest oznaczone , prawdopodobnie możesz napisać funkcję w Pascal i wywołać ją ze swojego programu w C; metoda ta jest specyficzna dla systemu.

Ale oto przykład, który działa na moim systemie Ubuntu z Free Pascal fp-compiler zainstalowanym pakietem . (Robię to z czysto upartego uporu; nie twierdzę, że jest to przydatne).

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

Budować:

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

Przykładowe wykonanie:

$ ./main
Enter a number: 100
100 / 3 = 33
Keith Thompson
źródło
8
int div3(int x)
{
  int reminder = abs(x);
  int result = 0;
  while(reminder >= 3)
  {
     result++;

     reminder--;
     reminder--;
     reminder--;
  }
  return result;
}
rev Amir Saniyan
źródło
3
++ i - operatorzy różnią się od + i - operatorzy! W języku asemblera są dwie instrukcje ADDi INCże nie mają tych samych kodów operacyjnych.
Amir Saniyan,
7

Nie sprawdziłem krzyżowo, czy ta odpowiedź jest już opublikowana. Jeśli program musi zostać rozszerzony na liczby zmiennoprzecinkowe, liczby można pomnożyć przez 10 * potrzebną liczbę dokładności, a następnie ponownie zastosować następujący kod.

#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;
}
PermanentGuest
źródło
7

To powinno działać dla każdego dzielnika, nie tylko trzech. Obecnie tylko dla niepodpisanych, ale rozszerzenie go na podpisane nie powinno być takie trudne.

#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;
}
wildplasser
źródło
7

Czy oszustwo byłoby używać /operatora „za kulisami” za pomocą evali łączenia łańcuchów?

Na przykład w Javacript możesz to zrobić

function div3 (n) {
    var div = String.fromCharCode(47);
    return eval([n, div, 3].join(""));
}
Peter Olson
źródło
7

Korzystanie z BC Math w PHP :

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

MySQL (to wywiad z Oracle)

> SELECT 12345 DIV 3;

Pascal :

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

język asemblera x86-64:

mov  r8, 3
xor  rdx, rdx   
mov  rax, 12345
idiv r8
Pedro L.
źródło
1
Fajna historia, jest oznaczona jako C i taka jest od pierwszego dnia. Ponadto całkowicie nie rozumiesz sedna pytania.
Lundin
6

Najpierw wymyśliłem.

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

EDYCJA: Przepraszam, nie zauważyłem tagu C. Ale możesz użyć pomysłu na formatowanie ciągów, tak myślę ...

Artem Ice
źródło
5

Poniższy skrypt generuje program C, który rozwiązuje problem bez użycia operatorów * / + - %:

#!/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));
}
''')
Ślimak mechaniczny
źródło
5

Korzystanie z kalkulatora liczb Hacker's Delight Magic

int divideByThree(int num)
{
  return (fma(num, 1431655766, 0) >> 32);
}

Gdzie fma jest standardową funkcją biblioteki zdefiniowaną w math.hnagłówku.

Jaguar
źródło
Jak to nie używa operatora -ani *?
maska ​​bitowa
4

Co powiesz na to podejście (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;
    }
Mclafee
źródło
To jest oznaczone C i tak jest od pierwszego dnia.
Lundin
4

Myślę, że poprawna odpowiedź to:

Dlaczego nie miałbym używać operatora podstawowego do wykonania podstawowej operacji?

Gregoire
źródło
Ponieważ chcą wiedzieć, jeśli wiesz, jak procesor działa wewnętrznie ... użycie operatora matematycznego w końcu wykona operację bardzo podobną do powyższej odpowiedzi.
RaptorX,
Albo chcą wiedzieć, czy potrafisz rozpoznać bezużyteczny problem.
Gregoire,
1
@Gregoire Zgadzam się, że nie ma aboloultley takiej potrzeby, Bit w życiu komercyjnym (Orcale) konieczne jest unikanie spełniania niepotrzebnych wymagań: Prawidłowa odpowiedź to: „To nie ma żadnego sensu, po co tracić pieniądze za to? ”)
AlexWien
4

Rozwiązanie wykorzystujące funkcję biblioteki fma () , działa dla dowolnej liczby dodatniej:

#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);
}

Zobacz moją kolejną odpowiedź .

Osiem
źródło
Niezłe wykorzystanie biblioteki. Dlaczego nie użyłeś bezpośrednio wyniku ++?
Zielony goblin
wtedy ludzie mogą powiedzieć, że użyto +.
Osiem
3

Użyj cblas , zawartych w ramach Accelerate systemu 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
wjl
źródło
To był tylko szczegół implementacji, więc mogłem wpisać go jako 3.0 / 1.0 zamiast 0.333333, ale powinienem grać zgodnie z zasadami. Naprawiony!
wjl
Pierwotnie miałem go jako 3.0 / 1.0, co zrobiłem w moim teście. Używając liczby o wyższej precyzji, powinni uzyskać dość dokładny wynik. gist.github.com/3401496
wjl
3

Ogólnie rozwiązaniem tego byłoby:

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

NKN
źródło
3

Pierwszy:

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

Następnie wymyśl, jak rozwiązać 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))

zy = 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)
}

Chociaż używa +, ale ktoś już implementuje dodawanie bitowe op.

Zang MingJie
źródło