Teilen Sie eine Zahl durch 3, ohne die Operatoren *, /, +, -,% zu verwenden

684

Wie würden Sie eine Reihe von 3 teilen , ohne *, /, +, -, %, Betreiber?

Die Nummer kann signiert oder nicht signiert sein.

unbekannt
quelle
13
@AlexandreC. - Diese Techniken verwenden jedoch Addition (+).
Beil - fertig mit SOverflow
19
Dies war Orakel. Welche Teile des Orakels durften Sie verwenden?
Hogan
8
Das identifizierte Duplikat ist kein Duplikat. Beachten Sie, dass einige Antworten hier weder Bitverschiebung noch Addition verwenden, da diese Frage keine Lösung für diese Operationen einschränkte.
Michael Burr
66
... und so entsteht PL / SQL.
Sedat Kapanoglu
22
Diese Frage ist für SO offtopisch. Es gehört zu codegolf.stackexchange.com
Kromster

Antworten:

548

Dies ist eine einfache Funktion, die die gewünschte Operation ausführt. Da jedoch der +Operator erforderlich ist , müssen Sie nur noch die Werte mit Bitoperatoren hinzufügen:

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

Wie Jim kommentierte, funktioniert dies, weil:

  • n = 4 * a + b
  • n / 3 = a + (a + b) / 3
  • So sum += a, n = a + bund iterate

  • Wenn a == 0 (n < 4), sum += floor(n / 3);dh 1,if n == 3, else 0

qwertz
quelle
96
Dies ist wahrscheinlich die Antwort, nach der Oracle sucht. Es zeigt Ihnen, wie die Operatoren +, -, * und / tatsächlich auf der CPU implementiert sind: einfache bitweise Operationen.
craig65535
21
Dies funktioniert, weil n = 4a + b, n / 3 = a + (a + b) / 3, also Summe + = a, n = a + b und Iteration. Wenn a == 0 (n <4) ist, ist Summe + = Boden (n / 3); dh 1 wenn n == 3, sonst 0.
Jim Balter
7
Hier ist ein Trick, den ich gefunden habe und der mir eine ähnliche Lösung gebracht hat. In Dezimalzahlen: 1 / 3 = 0.333333Die sich wiederholenden Zahlen erleichtern die Berechnung mit a / 3 = a/10*3 + a/100*3 + a/1000*3 + (..). In der Binärdatei ist es fast dasselbe: 1 / 3 = 0.0101010101 (base 2)was dazu führt a / 3 = a/4 + a/16 + a/64 + (..). Durch Teilen durch 4 kommt die Bitverschiebung. Die letzte Überprüfung von num == 3 ist erforderlich, da wir nur Ganzzahlen haben, mit denen wir arbeiten können.
Yorick Sijsling
4
In Base 4 wird es noch besser : a / 3 = a * 0.111111 (base 4) = a * 4^-1 + a * 4^-2 + a * 4^-3 + (..) = a >> 2 + a >> 4 + a >> 6 + (..). Die Basis 4 erklärt auch, warum am Ende nur 3 aufgerundet wird, während 1 und 2 abgerundet werden können.
Yorick Sijsling
2
@ while1: Es ist bitweise UND-Operation. Eine bekannte Tatsache ist auch, dass für n == 2^kFolgendes gilt : x % n == x & (n-1), wird hier num & 3also verwendet, um auszuführen, num % 4solange dies %nicht erlaubt ist.
Aplavin
436

Idiotische Bedingungen erfordern eine idiotische Lösung:

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

Wenn auch der Dezimalteil benötigt wird, deklarieren Sie einfach resultals doubleund fügen Sie das Ergebnis von hinzu fmod(number,divisor).

Erklärung, wie es funktioniert

  1. Die fwriteSchreibvorgänge numberBytes (Zahl ist 123456 in dem obigen Beispiel).
  2. rewind Setzt den Dateizeiger auf die Vorderseite der Datei zurück.
  3. freadliest maximal number"Datensätze" divisormit einer Länge aus der Datei und gibt die Anzahl der gelesenen Elemente zurück.

Wenn Sie 30 Bytes schreiben und dann die Datei in Einheiten von 3 zurücklesen, erhalten Sie 10 "Einheiten". 30/3 = 10

Matteo Italia
quelle
13
@earlNameless: Sie wissen nicht, was sie im Inneren verwenden, sie befinden sich in der Blackbox "Implementierung definiert". Nichts hindert sie daran, nur bitweise Operatoren zu verwenden. Auf jeden Fall befinden sie sich außerhalb der Domäne meines Codes, das ist also nicht mein Problem. :)
Matteo Italia
8
@IvoFlipse von Ich kann putzen, du bekommst ein großes Etwas und schiebst es in etwas dreimal zu Kleines und siehst dann, wie viel hineinpasst. Das ist ungefähr ein Drittel.
Pureferret
27
bat den besten C-Programmierer (und den sozial umständlichsten) in unserem Unternehmen, den Code zu erklären. Nachdem er es getan hatte, sagte ich, es sei ziemlich genial. Er sagte, "dieser Dreck ist keine Lösung" und bat mich, seinen Schreibtisch zu verlassen
siehe Verletzung
6
@cvverletzung Ich denke der Punkt ist, dass die Frage so hirntot ist, dass eine hirntote Antwort erlaubt ist. Der "beste C-Programmierer" in Ihrem Unternehmen "hätte genauso gut sagen können," dass Dreck keine (richtige) Frage ist ".
JeremyP
17
@ JeremyP: genau. Mein Punkt ist, dass, wenn ich im wirklichen Leben einen Compiler ohne Unterstützung für Arithmetik bekommen würde, es nur sinnvoll wäre, nach einem besseren Compiler zu fragen , da das Arbeiten unter diesen Bedingungen keinen Sinn ergibt. Wenn der Interviewer mein Wissen über die Implementierung von Division mit bitweisen Operationen überprüfen wollte, konnte er einfach sein und es als theoretische Frage stellen. Diese Art von "Trickübungen" schreien nur nach Antworten wie diesen.
Matteo Italia
306
log(pow(exp(number),0.33333333333333333333)) /* :-) */
Alan Curry
quelle
2
Dies könnte tatsächlich funktionieren, wenn es richtig gerundet ist und die Zahl nicht zu groß ist.
Mysticial
252
Verbesserte Version: log (pow (exp (Zahl), sin (atan2 (1, sqrt (8))))
Alan Curry
@bitmask, mathematische Funktionen werden normalerweise direkt in asm implementiert.
SingerOfTheFall
7
Ich habe es gerade in meine JS-Konsole eingegeben, es funktioniert nicht mit einer Nummer höher als 709 (möglicherweise ist es nur mein System) Math.log(Math.pow(Math.exp(709),0.33333333333333333333))undMath.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;
}
nr
quelle
113

Sie können (plattformabhängige) Inline-Assembly verwenden, z. B. für x86: (funktioniert auch für negative Zahlen)

#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
quelle
2
@JeremyP scheitert Ihr Kommentar nicht unter der Annahme, dass die Antwort nicht in C geschrieben werden kann? Die Frage ist immerhin mit "C" markiert.
Seth Carnegie
1
@ SethCarnegie Die Antwort ist nicht in C geschrieben ist mein Punkt. Der x86-Assembler ist nicht Teil des Standards.
JeremyP
1
@JeremyP das stimmt, aber die asmDirektive ist. Und ich würde hinzufügen, dass C-Compiler nicht die einzigen sind, die Inline-Assembler haben, Delphi hat das auch.
Seth Carnegie
7
@SethCarnegie Die asmRichtlinie wird nur in der Norm C99 unter Anhang J - Allgemeine Erweiterungen erwähnt.
JeremyP
2
Schlägt in arm-eabi-gcc fehl.
Damian Yerrick
106

Verwenden Sie itoa , um eine Basis-3-Zeichenfolge zu konvertieren. Lass den letzten Trit fallen und konvertiere zurück zu Basis 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
quelle
4
@cshemby Ich wusste eigentlich nicht, dass itoadas eine beliebige Basis verwenden könnte. Wenn Sie eine vollständige funktionierende Implementierung mit durchführen, itoawerde ich abstimmen.
Mysticial
2
Die Implementierung wird enthalten /und %... :-)
R .. GitHub STOP HELPING ICE
2
@R .. Ebenso die Implementierung von printfzur Anzeige Ihres Dezimalergebnisses.
Damian Yerrick
57

(Hinweis: Eine bessere Version finden Sie unter Bearbeiten 2 unten!)

Dies ist nicht so schwierig, wie es sich anhört, weil Sie "ohne Verwendung der Operatoren [..] +[..] " gesagt haben . Siehe unten, wenn Sie die Verwendung des Charakters insgesamt verbieten möchten .+

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

dann nur sagen , div_by(100,3)zu dividieren 100durch 3.


Bearbeiten : Sie können den ++Operator auch ersetzen :

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: Etwas schnellere Version ohne jeden Operator, der die enthält +, -, *, /, % Zeichen .

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

Wir verwenden das erste Argument der addFunktion, da wir den Zeigertyp ohne Verwendung des *Zeichens nicht bezeichnen können , außer in Funktionsparameterlisten, in denen die Syntax type[]identisch ist mit type* const.

FWIW, Sie können eine Multiplikationsfunktion einfach mit einem ähnlichen Trick implementieren, um den 0x55555556von AndreyT vorgeschlagenen Trick zu verwenden :

int mul(int const x, int const y) {
  return sizeof(struct {
    char const ignore[y];
  }[x]);
}
Bitmaske
quelle
5
Die Frage ist mit c und nicht mit SQL gekennzeichnet, obwohl Oracle erwähnt wird.
Bitmaske
3
Dies sieht in der Tat nicht nach SQL aus!
Moooeeeep
64
Wenn Sie verwenden können ++: Warum verwenden Sie nicht einfach /=?
QWERTZ
5
@bitmask: ++ist auch eine Abkürzung: Für num = num + 1.
QWERTZ
4
@bitmask Ja, aber +=ist endlich eine Abkürzung für num = num + 1.
QWERTZ
44

Auf dem Setun-Computer ist dies problemlos möglich .

Um eine ganze Zahl durch 3 zu teilen, verschieben Sie sie um 1 Stelle nach rechts .

Ich bin mir nicht sicher, ob es durchaus möglich ist, einen konformen C-Compiler auf einer solchen Plattform zu implementieren. Möglicherweise müssen wir die Regeln etwas erweitern, z. B. "mindestens 8 Bits" als "in der Lage, mindestens ganze Zahlen von -128 bis +127 zu halten" interpretieren.

Mechanische Schnecke
quelle
8
Das Problem ist, dass Sie in C keinen Operator "Verschiebung um 1 Stelle nach rechts" haben. Der >>Operator ist der Operator "Division durch 2 ^ n", dh er wird in Bezug auf die Arithmetik und nicht in Bezug auf die Maschinendarstellung angegeben.
R .. GitHub STOP HELPING ICE
Der Setun-Computer ist in keiner Weise binär, daher muss der Befehlssatz definitiv anders sein. Ich bin jedoch überhaupt nicht mit der Bedienung dieses Computers vertraut, daher kann ich nicht bestätigen, ob die Antwort wirklich korrekt ist - aber zumindest sinnvoll - und sehr originell ist. +1
Virolino
32

Wie wäre es mit einer Nachschlagetabelle mit vorberechneten Antworten, da es von Oracle stammt? :-D

Jeff Martin
quelle
32

Hier ist meine Lösung:

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

Beachten Sie zunächst, dass

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

Jetzt ist der Rest einfach!

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

Jetzt müssen wir nur noch diese bitverschobenen Werte von a addieren! Hoppla! Wir können jedoch nicht hinzufügen, daher müssen wir stattdessen eine Add-Funktion mit bitweisen Operatoren schreiben! Wenn Sie mit bitweisen Operatoren vertraut sind, sollte meine Lösung ziemlich einfach aussehen ... aber falls Sie dies nicht tun, werde ich am Ende ein Beispiel durchgehen.

Eine andere Sache zu beachten ist, dass ich zuerst um 30 nach links verschiebe! Dies soll sicherstellen, dass die Brüche nicht abgerundet werden.

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!

Es ist einfach eine Ergänzung, die Sie als Kind gelernt haben!

111
 1011
+0110
-----
10001

Diese Implementierung ist fehlgeschlagen, da nicht alle Begriffe der Gleichung hinzugefügt werden können:

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

Angenommen, die Auflösung von div_by_3(a)= x ist dann x <= floor(f(a, i)) < a / 3. Wann a = 3kbekommen wir eine falsche Antwort.

tschultz
quelle
2
funktioniert es für die Eingabe von 3? 1/4, 1/16, ... alle geben 0 für 3 zurück, würden also 0 ergeben, aber 3/3 = 1.
Beil - fertig mit SOverflow
1
Die Logik ist gut, aber die Implementierung ist problematisch. Die Seriennäherung von n/3ist immer kleiner als, n/3was bedeutet, dass für jedes n=3kErgebnis k-1stattdessen wäre k.
Xyand
@ Albert, Dies war der erste Ansatz, den ich versuchte, mit ein paar Variationen, aber alle scheiterten entweder an bestimmten Zahlen, die gleichmäßig durch 3 teilbar oder gleichmäßig durch 2 teilbar waren (abhängig von der Variation). Also habe ich etwas Unkomplizierteres versucht. Ich würde gerne eine Implementierung dieses Ansatzes sehen, die funktioniert, um zu sehen, wo ich es vermasselt habe.
Beil - fertig mit SOverflow
@hatchet, Die Frage ist geschlossen, daher kann ich keine neue Antwort posten, aber die Idee ist, binäres Div zu implementieren. Ich sollte es leicht nachschlagen können.
Xyand
25

Um eine 32-Bit-Zahl durch 3 zu teilen, kann man sie mit multiplizieren 0x55555556und dann die oberen 32 Bits des 64-Bit-Ergebnisses nehmen.

Jetzt müssen Sie nur noch die Multiplikation mit Bitoperationen und Verschiebungen implementieren ...

Ameise
quelle
1
Dies ist ein gängiger Compilertrick, um langsame Teilungen zu umgehen. Aber Sie müssen wahrscheinlich einige Korrekturen vornehmen, da 0x55555556 / 2 ** 32 nicht genau 1/3 ist.
CodesInChaos
multiply it. Würde das nicht bedeuten, den verbotenen *Operator zu verwenden?
luiscubal
8
@luiscubal: Nein, das wird es nicht. Deshalb sagte ich: "Jetzt müssen wir nur noch die Multiplikation mit Bitoperationen und Verschiebungen implementieren "
AnT
18

Noch eine andere Lösung. Dies sollte alle Ints (einschließlich negativer Ints) mit Ausnahme des Min-Werts eines Int behandeln, der als fest codierte Ausnahme behandelt werden müsste. Dies erfolgt grundsätzlich durch Subtraktion, jedoch nur unter Verwendung von Bitoperatoren (Verschiebungen, xor & und Komplement). Für eine schnellere Geschwindigkeit subtrahiert es 3 * (abnehmende Potenzen von 2). In c # werden ungefähr 444 dieser DivideBy3-Aufrufe pro Millisekunde ausgeführt (2,2 Sekunden für 1.000.000 Teilungen), also nicht schrecklich langsam, aber nicht annähernd so schnell wie ein einfaches x / 3. Im Vergleich dazu ist Coodeys nette Lösung ungefähr fünfmal schneller als diese.

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

Dies ist c #, weil ich das zur Hand hatte, aber die Unterschiede zu c sollten gering sein.

Beil
quelle
Sie müssen nur einmal versuchen, Sub zu subtrahieren, denn wenn Sie es zweimal hätten subtrahieren können, hätten Sie es bei der vorherigen Iteration subtrahieren können, als es doppelt so groß war wie jetzt.
Neil
Zählt (a >= sub)als Subtraktion?
Neil
@Neil, ich denke du hast vielleicht recht. Das innere while könnte durch ein einfaches if ersetzt werden, wodurch ein nicht benötigter Vergleich aus der zweiten Iteration der Schleife gespeichert wird. In Bezug auf> = Subtraktion sein ... Ich hoffe nicht, denn das würde es ziemlich schwierig machen! Ich verstehe Ihren Standpunkt, aber ich denke, ich würde mich auf die Seite stützen, die sagt, dass> = nicht als Subtraktion zählt.
Beil - fertig mit SOverflow
@Neil, ich habe diese Änderung vorgenommen, die die Zeit halbiert (auch nicht benötigte Negate gespeichert).
Beil - fertig mit SOverflow
16

Es ist wirklich ganz einfach.

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;

(Ich habe der Kürze halber natürlich einen Teil des Programms weggelassen.) Wenn der Programmierer es satt hat, dies alles abzutippen, bin ich sicher, dass er oder sie ein separates Programm schreiben könnte, um es für ihn zu generieren. Mir ist zufällig ein bestimmter Bediener bekannt, der /seine Arbeit immens vereinfachen würde.

die Tagesumdrehungen
quelle
8
Sie könnten Dictionary<number, number>anstelle von wiederholten ifAnweisungen eine verwenden, um O(1)zeitliche Komplexität zu erzielen!
Peter Olson
@EnesUnal Nein, die Zeit nimmt mit zunehmender Anzahl linear zu, da sie immer mehr if-Anweisungen durchlaufen muss.
Peter Olson
Theoretisch nimmt es nicht zu :)
totten
@ PeterOlson, EresUnal, wenn ich eine switch-Anweisung verwenden würde, wäre es O (1) :-)
Tag dreht sich
Oder Sie können ein Array generieren und dynamische Programmierung verwenden. wenn x / 3 = y, dann ist y << 2 + y = x - x% 3.
lsiebert
14

Die Verwendung von Zählern ist eine grundlegende Lösung:

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

Es ist auch einfach, eine Modulfunktion auszuführen, überprüfen Sie die Kommentare.

GJ.
quelle
@Enes Unal: nicht für kleine Zahlen :) Dieser Algorithmus ist sehr einfach.
GJ.
Jede Primitivität beinhaltet Schwächen :)
Totten
11

Dies ist der klassische Divisionsalgorithmus in Basis 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
quelle
10

Schreiben Sie das Programm in Pascal und verwenden Sie den DIVOperator.

Da ist die Frage markiert können Sie wahrscheinlich eine Funktion in Pascal schreiben und von Ihrem C-Programm aus aufrufen; Die Methode hierfür ist systemspezifisch.

Aber hier ist ein Beispiel, das auf meinem Ubuntu-System mit dem fp-compilerinstallierten Free Pascal- Paket funktioniert . (Ich mache das aus purer Sturheit; ich behaupte nicht, dass dies nützlich ist.)

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

Bauen:

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

Beispielausführung:

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

     reminder--;
     reminder--;
     reminder--;
  }
  return result;
}
Amir Saniyan
quelle
3
++ und - Operatoren unterscheiden sich von + und - Operatoren! In Assembler - Sprache gibt es zwei Befehle ADDund INCdass sie nicht gleiche Opcodes haben.
Amir Saniyan
7

Es wurde nicht überprüft, ob diese Antwort bereits veröffentlicht wurde. Wenn das Programm auf Gleitkommazahlen erweitert werden muss, können die Zahlen mit der erforderlichen Genauigkeit von 10 * multipliziert werden, und dann kann der folgende Code erneut angewendet werden.

#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
quelle
7

Dies sollte für jeden Divisor funktionieren, nicht nur für drei. Derzeit nur für nicht signierte, aber die Erweiterung auf signierte sollte nicht so schwierig sein.

#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
quelle
7

Wäre es ein Betrug, den /Operator "hinter den Kulissen" mithilfe von evalString-Verkettung zu verwenden?

In Javacript können Sie dies beispielsweise tun

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

Verwenden von BC Math in PHP :

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

MySQL (es ist ein Interview von Oracle)

> SELECT 12345 DIV 3;

Pascal :

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

x86-64 Assemblersprache:

mov  r8, 3
xor  rdx, rdx   
mov  rax, 12345
idiv r8
Pedro L.
quelle
1
Coole Geschichte, dies ist mit C getaggt und ist es seit dem ersten Tag. Darüber hinaus verstehen Sie den Punkt der Frage überhaupt nicht.
Lundin
6

Zuerst habe ich mir etwas ausgedacht.

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: Sorry, ich habe das Tag nicht bemerkt C. Aber Sie können die Idee der String-Formatierung verwenden, denke ich ...

Artem Ice
quelle
5

Das folgende Skript generiert ein C-Programm, das das Problem ohne Verwendung der Operatoren löst * / + - %:

#!/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));
}
''')
Mechanische Schnecke
quelle
5

Verwenden des Hacker Delight Magic Zahlenrechners

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

Wobei fma eine im math.hHeader definierte Standardbibliotheksfunktion ist .

Jaguar
quelle
Wie benutzt das -weder den noch den *Operator?
Bitmaske
4

Wie wäre es mit diesem Ansatz (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
quelle
Dies ist mit C gekennzeichnet und ist dies seit dem ersten Tag.
Lundin
4

Ich denke die richtige Antwort ist:

Warum sollte ich keinen Basisoperator verwenden, um eine Basisoperation auszuführen?

Gregoire
quelle
Denn was sie wissen wollen, ist, wenn Sie wissen, wie der Prozessor intern funktioniert ... Wenn Sie einen mathematischen Operator verwenden, wird am Ende eine Operation ausgeführt, die der obigen Antwort sehr ähnlich ist.
RaptorX
Oder sie möchten wissen, ob Sie ein nutzloses Problem erkennen können.
Gregoire
1
@ Gregoire Ich stimme zu, es gibt absolut keine Notwendigkeit, eine solche Implementierung durchzuführen. Im kommerziellen Leben (Orcale) ist es notwendig, die Erfüllung nutzloser Anforderungen zu vermeiden: Die richtige Antwort lautet: "Das macht überhaupt keinen Sinn, warum Geld verlieren dafür? ")
AlexWien
4

Die Lösung mit der Bibliotheksfunktion fma () funktioniert für jede positive Zahl:

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

Siehe meine andere Antwort .

Acht
quelle
Gute Nutzung der Bibliothek. Warum haben Sie result ++ nicht direkt verwendet?
Grüner Kobold
dann können die Leute sagen, dass + verwendet wurde.
Acht
3

Verwenden Sie cblas , die Teil des Accelerate-Frameworks von OS X sind.

[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
quelle
Nun, das war nur ein Implementierungsdetail, also konnte ich es als 3.0 / 1.0 anstelle von 0.333333 eingeben, aber ich sollte mich an die Regeln halten. Fest!
wjl
Ich hatte es ursprünglich als 3.0 / 1.0, was in meinem Test tat. Durch die Verwendung einer Zahl mit höherer Genauigkeit sollten sie ein einigermaßen genaues Ergebnis erhalten. gist.github.com/3401496
wjl
3

Im Allgemeinen wäre eine Lösung hierfür:

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

NKN
quelle
3

Zuerst:

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

Dann finde heraus, wie man x / (1 - y) löst:

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

mit y = 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)
}

Es wird zwar verwendet +, aber jemand implementiert bereits add by bitwise op.

Zang MingJie
quelle