Dividi un numero per 3 senza usare gli operatori *, /, +, -,%


686

Come si dividere un numero per 3 senza utilizzare *, /, +, -, %, gli operatori?

Il numero può essere firmato o non firmato.


13
@AlexandreC. - quelle tecniche usano l'addizione (+) però.
ascia di guerra - fatto con SOverflow il

19
Questo era l'oracolo, quindi quali parti dell'oracolo ti è stato permesso di usare?
Hogan,

8
Il duplicato identificato non è un duplicato. Si noti che diverse risposte qui non utilizzano né spostamento di bit né aggiunta poiché questa domanda non ha limitato una soluzione a tali operazioni.
Michael Burr,

66
... ed ecco come nasce PL / SQL.
Sedat Kapanoglu,

23
Questa domanda è offtopica per SO. Appartiene a codegolf.stackexchange.com
Kromster il

Risposte:


548

Questa è una semplice funzione che esegue l'operazione desiderata. Ma richiede l' +operatore, quindi tutto ciò che resta da fare è aggiungere i valori con gli operatori bit:

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

Come ha commentato Jim, questo funziona perché:

  • n = 4 * a + b
  • n / 3 = a + (a + b) / 3
  • Quindi sum += a, n = a + be iterare

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


96
Questa è probabilmente la risposta che Oracle sta cercando. Ti mostra come gli operatori +, -, * e / sono effettivamente implementati sulla CPU: semplici operazioni bit a bit.
craig65535,

21
Questo funziona perché n = 4a + b, n / 3 = a + (a + b) / 3, quindi somma + = a, n = a + b e ripetizione. Quando a == 0 (n <4), somma + = piano (n / 3); cioè 1 se n == 3, altrimenti 0.
Jim Balter,

7
Ecco un trucco che ho trovato che mi ha procurato una soluzione simile. In decimale: 1 / 3 = 0.333333i numeri ripetuti lo rendono facile da calcolare usando a / 3 = a/10*3 + a/100*3 + a/1000*3 + (..). In binario è quasi lo stesso: 1 / 3 = 0.0101010101 (base 2)che porta a a / 3 = a/4 + a/16 + a/64 + (..). La divisione per 4 è la provenienza del bit shift. L'ultimo controllo su num == 3 è necessario perché abbiamo solo numeri interi con cui lavorare.
Yorick Sijsling,

4
In base 4 è ancora meglio: a / 3 = a * 0.111111 (base 4) = a * 4^-1 + a * 4^-2 + a * 4^-3 + (..) = a >> 2 + a >> 4 + a >> 6 + (..). La base 4 spiega anche perché solo 3 è arrotondato per eccesso alla fine, mentre 1 e 2 possono essere arrotondati per difetto.
Yorick Sijsling,

2
@ while1: è un'operazione AND bit a bit. Inoltre, un fatto ben noto è che per n == 2^kquanto segue è vero:, x % n == x & (n-1)quindi qui num & 3viene utilizzato per eseguire num % 4mentre %non è consentito.
aplavin,

436

Le condizioni idiote richiedono una soluzione idiota:

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

Se è necessaria anche la parte decimale, dichiarare resultas doublee aggiungere ad essa il risultato di fmod(number,divisor).

Spiegazione di come funziona

  1. Le fwritescrive numberbyte (numero essendo 123456 nell'esempio di cui sopra).
  2. rewind reimposta il puntatore del file all'inizio del file.
  3. freadlegge un massimo di number"record" che sono divisorin lunghezza dal file e restituisce il numero di elementi letti.

Se si scrivono 30 byte, quindi si rilegge il file in unità di 3, si ottengono 10 "unità". 30/3 = 10


13
@earlNameless: non sai cosa usano dentro, sono nella scatola nera di "implementazione definita". Nulla li impedisce di usare solo operatori bit a bit; comunque, sono al di fuori del dominio del mio codice, quindi non è un mio problema. :)
Matteo Italia,

8
@IvoFlipse da Riesco a pulire, ottieni qualcosa di grosso e lo spingi in qualcosa di tre volte troppo piccolo, e poi vedi quanto si inserisce. Questo è circa un terzo.
Pureferret,

27
ha chiesto al miglior programmatore C (e più socialmente imbarazzante) della nostra azienda di spiegare il codice. dopo averlo fatto, ho detto che era abbastanza geniale. Ha detto 'questo dreck non è una soluzione' e mi ha chiesto di lasciare la sua scrivania
cvursache il

6
@cvursache Penso che il punto sia che la domanda è talmente cerebrale che è consentita una risposta cerebrale. Il "miglior programmatore C" nella tua azienda "avrebbe potuto altrettanto facilmente dire" che il dreck non è una (corretta) domanda ".
JeremyP

17
@JeremyP: esattamente. Il mio punto è che se nella vita reale mi venisse dato un compilatore senza supporto per l'aritmetica, l'unica cosa sensata sarebbe chiedere un compilatore migliore , perché lavorare in quelle condizioni non ha alcun senso. Se l'intervistatore volesse verificare le mie conoscenze su come implementare la divisione con operazioni bit per bit, potrebbe essere semplice e porlo come una domanda teorica; questo tipo di "esercizi di trucco" urla solo per risposte come questa.
Matteo Italia,

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

2
Questo potrebbe effettivamente funzionare se arrotondato correttamente e se il numero non è troppo grande.
Mistico il

252
Versione migliorata: log (pow (exp (numero), sin (atan2 (1, sqrt (8)))))
Alan Curry

@bitmask, le funzioni matematiche sono di solito implementate direttamente in asm.
SingerOfTheFall

7
l'ho appena digitato nella mia console js, non funziona con un numero superiore a 709 (potrebbe essere solo il mio sistema) Math.log(Math.pow(Math.exp(709),0.33333333333333333333))eMath.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

È possibile utilizzare l'assemblaggio inline (dipendente dalla piattaforma), ad es. Per x86: (funziona anche con numeri negativi)

#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 il tuo commento non fallisce nell'ipotesi che la risposta non possa essere scritta in C? Dopotutto, la domanda è taggata "C".
Seth Carnegie,

1
@SethCarnegie La risposta non è scritta in C è il mio punto. L'assemblatore x86 non fa parte dello standard.
JeremyP,

1
@JeremyP è vero, ma la asmdirettiva lo è. E aggiungerei che i compilatori C non sono i soli ad avere assemblatori in linea, ma anche Delphi.
Seth Carnegie,

7
@SethCarnegie La asmdirettiva è menzionata solo nello standard C99 nell'Appendice J - estensioni comuni.
JeremyP

2
Errore in arm-eabi-gcc.
Damian Yerrick,

106

Usa itoa per convertire in una stringa di base 3. Rilascia l'ultimo trit e riconvertilo in base 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 In realtà non sapevo che itoapotesse usare una base arbitraria. Se itoaesegui un'implementazione completa e funzionante usando Upvote.
Mistico il

2
L'implementazione conterrà /e %... :-)
R .. GitHub FERMA AIUTANDO ICE il

2
@R .. Anche l'implementazione di printfper visualizzare il risultato decimale.
Damian Yerrick,

57

(nota: vedi Modifica 2 di seguito per una versione migliore!)

Questo non è così complicato come sembra, perché hai detto "senza usare gli operatori [..] +[..] ". Vedi sotto, se vuoi proibire di usare il personaggio tutti insieme.+

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

quindi dì solo div_by(100,3)di dividere 100per 3.


Modifica : è possibile continuare e sostituire anche l' ++operatore:

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: leggermente più veloce versione senza l'utilizzo di qualsiasi operatore che contiene i +, -, *, /, % caratteri .

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

Usiamo il primo argomento della addfunzione perché non possiamo indicare il tipo di puntatori senza usare il *carattere, tranne negli elenchi dei parametri delle funzioni, in cui la sintassi type[]è identica type* const.

FWIW, puoi facilmente implementare una funzione di moltiplicazione usando un trucco simile per usare il 0x55555556trucco proposto da AndreyT :

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

5
La domanda è taggata c , non SQL, anche se Oracle è menzionato.
maschera di bit

3
Questo in effetti non sembra SQL!
Moooeeeep,

64
Se puoi usare ++: Perché non lo usi semplicemente /=?
qwertz,

5
@bitmask: ++è anche una scorciatoia: per num = num + 1.
qwertz,

4
Sì, ma +=è finalmente una scorciatoia per num = num + 1.
qwertz,

44

È facilmente possibile sul computer Setun .

Per dividere un numero intero per 3, sposta a destra di 1 posizione .

Non sono sicuro però se sia strettamente possibile implementare un compilatore C conforme su tale piattaforma. Potremmo dover allungare un po 'le regole, come interpretare "almeno 8 bit" come "capace di contenere almeno numeri interi da -128 a +127".


8
Il problema è che non si ha un operatore "sposta a destra di 1 posto" in C. L' >>operatore è l'operatore "divisione per 2 ^ n", cioè è specificato in termini di aritmetica, non di rappresentazione della macchina.
R .. GitHub smette di aiutare ICE il

Il computer Setun non è binario in alcun senso della parola, quindi il set di istruzioni deve essere decisamente diverso. Tuttavia, non ho alcuna familiarità con il funzionamento di quel computer, quindi non posso confermare se la risposta è davvero corretta - ma almeno ha senso - ed è altamente originale. +1
virolino,

32

Dal momento che proviene da Oracle, che ne dici di una tabella di ricerca di risposte precalcolate. :-D


32

Ecco la mia soluzione:

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

Innanzitutto, nota che

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

Ora il resto è semplice!

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

Ora tutto ciò che dobbiamo fare è sommare questi valori di a! Oops! Non possiamo aggiungere però, quindi dovremo scrivere una funzione di aggiunta usando operatori bit-saggi! Se hai familiarità con gli operatori bit-saggi, la mia soluzione dovrebbe sembrare abbastanza semplice ... ma nel caso in cui non lo sei, vedrò un esempio alla fine.

Un'altra cosa da notare è che prima mi sposto a sinistra di 30! Questo per assicurarsi che le frazioni non vengano arrotondate.

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!

È semplicemente un'aggiunta che hai imparato da bambino!

111
 1011
+0110
-----
10001

Questa implementazione non è riuscita perché non possiamo aggiungere tutti i termini dell'equazione:

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

Supponiamo che il risultato sia div_by_3(a)= x, quindi x <= floor(f(a, i)) < a / 3. Quando a = 3kriceviamo una risposta sbagliata.


2
funziona per input di 3? 1/4, 1/16, ... restituiscono tutti 0 per 3, quindi si sommerebbe a 0, ma 3/3 = 1.
ascia di guerra - fatto con SOverflow il

1
La logica è buona ma l'implementazione è problematica. L'approssimazione in serie di n/3è sempre minore di n/3ciò significa che per qualsiasi n=3krisultato sarebbe k-1invece di k.
Xyand,

@Albert, Questo è stato il primo approccio che ho provato, con un paio di variazioni, ma hanno fallito su alcuni numeri equamente divisibili per 3 o uniformemente divisibili per 2 (a seconda della variazione). Quindi ho provato qualcosa di più semplice. Mi piacerebbe vedere un'implementazione di questo approccio che funziona, per vedere dove stavo rovinando.
ascia di guerra - fatto con SOverflow il

@hatchet, La domanda è chiusa, quindi non posso pubblicare una nuova risposta ma l'idea è quella di implementare div binari. Dovrei essere facile da cercare.
Xyand,


25

Per dividere un numero a 32 bit per 3, è possibile moltiplicarlo per 0x55555556 e quindi prendere i 32 bit superiori del risultato a 64 bit.

Ora tutto ciò che resta da fare è implementare la moltiplicazione usando operazioni bit e turni ...


1
Questo è un trucco comune del compilatore per aggirare le divisioni lente. Ma probabilmente dovrai fare alcune correzioni, poiché 0x55555556 / 2 ** 32 non è esattamente 1/3.
CodesInChaos,

multiply it. Ciò non implicherebbe l'uso *dell'operatore proibito ?
luiscubal,

8
@luiscubal: No, non lo farà. Questo è il motivo per cui ho detto: "Ora tutto ciò che resta da fare è implementare la moltiplicazione usando operazioni con bit e turni "
AnT

18

Ancora un'altra soluzione. Questo dovrebbe gestire tutti gli ints (inclusi quelli negativi) ad eccezione del valore minimo di un int, che dovrebbe essere gestito come un'eccezione codificata. Questo fondamentalmente fa la divisione per sottrazione ma usando solo operatori bit (turni, xor e complemento). Per una maggiore velocità, sottrae 3 * (diminuendo i poteri di 2). In c #, esegue circa 444 di queste chiamate DivideBy3 per millisecondo (2,2 secondi per 1.000.000 di divisioni), quindi non orrendamente lento, ma non tanto vicino quanto un semplice x / 3. In confronto, la bella soluzione di Coodey è circa 5 volte più veloce di questa.

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

Questo è c # perché è quello che avevo a portata di mano, ma le differenze da c dovrebbero essere minori.


Devi solo provare a sottrarre sub una volta, perché se avessi potuto sottrarlo due volte, avresti potuto sottrarlo alla precedente iterazione quando era due volte più grande di adesso.
Neil,

Non (a >= sub)conta come una sottrazione?
Neil,

@Neil, penso che potresti avere ragione. Il mentre interno potrebbe essere sostituito con un semplice if, salvando un confronto non necessario dalla seconda iterazione del ciclo. Per quanto riguarda> = essere sottrazione ... spero di no, perché ciò renderebbe questo piuttosto difficile! Vedo il tuo punto, ma penso che mi appoggerei al lato che dice> = non conta come sottrazione.
ascia di guerra - fatto con SOverflow il

@Neil, ho apportato quella modifica, che ha dimezzato il tempo (salvato anche Negativi non necessari).
ascia di guerra - fatto con SOverflow il

16

È davvero abbastanza facile.

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;

(Ovviamente ho omesso parte del programma per brevità.) Se il programmatore si stanca di scrivere tutto questo, sono sicuro che lui o lei potrebbe scrivere un programma separato per generarlo per lui. Mi capita di essere a conoscenza di un certo operatore /, il che semplificherebbe immensamente il suo lavoro.


8
È possibile utilizzare dichiarazioni Dictionary<number, number>anziché ripetute in ifmodo da avere O(1)complessità temporale!
Peter Olson,

@EnesUnal No, il tempo aumenta in modo lineare all'aumentare del numero, perché deve attraversare sempre più istruzioni if.
Peter Olson,

Teoricamente non aumenta :)
ottenuto il

@PeterOlson, EresUnal se avessi usato un'istruzione switch, sarebbe O (1) :-)
thtayturns

Oppure potresti generare un array e utilizzare la programmazione dinamica. se x / 3 = y, quindi y << 2 + y = x - x% 3.
lsiebert

14

L'uso dei contatori è una soluzione di base:

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

È anche facile eseguire una funzione del modulo, controllare i commenti.


@Enes Unal: non per piccoli numeri :) Questo algoritmo è molto semplice.
GJ.

Ogni primitività include debolezze :)
ottenuta il

11

Questo è l'algoritmo di divisione classica nella base 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

Scrivi il programma in Pascal e usa l' DIVoperatore.

Dal momento che la domanda è taggata , probabilmente puoi scrivere una funzione in Pascal e chiamarla dal tuo programma C; il metodo per farlo è specifico del sistema.

Ma ecco un esempio che funziona sul mio sistema Ubuntu con il fp-compilerpacchetto Free Pascal installato. (Lo sto facendo per pura testardaggine mal riposta; non pretendo che ciò sia utile.)

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

Costruire:

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

Esecuzione del campione:

$ ./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
Gli operatori ++ e - sono diversi dagli operatori + e -! Nel linguaggio assembly ci sono due istruzioni ADDe INCche non hanno gli stessi codici operativi.
Amir Saniyan,

7

Non è stato effettuato un controllo incrociato se questa risposta è già stata pubblicata. Se il programma deve essere esteso a numeri fluttuanti, i numeri possono essere moltiplicati per il numero di precisione 10 * necessario e quindi è possibile applicare nuovamente il codice seguente.

#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

Questo dovrebbe funzionare per qualsiasi divisore, non solo per tre. Attualmente solo per non firmati, ma estenderlo a firmato non dovrebbe essere così difficile.

#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

Sarebbe imbarazzante usare l' /operatore "dietro le quinte" usando evale la concatenazione delle stringhe?

Ad esempio, in Javacript, puoi farlo

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

7

Utilizzando BC Math in PHP :

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

MySQL (è un'intervista da Oracle)

> SELECT 12345 DIV 3;

Pascal :

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

linguaggio assembly x86-64:

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

1
Storia interessante, questo è etichettato C ed è stato così dal primo giorno. Inoltre, non riesci completamente a capire il punto della domanda.
Lundin,

6

Prima di tutto mi sono inventato.

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: Mi dispiace, non ho notato il tag C. Ma puoi usare l'idea della formattazione delle stringhe, immagino ...


5

Il seguente script genera un programma C che risolve il problema senza utilizzare gli operatori * / + - %:

#!/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

Che ne dici di questo approccio (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;
    }

Questo è etichettato C ed è stato così dal primo giorno.
Lundin,

4

Penso che la risposta giusta sia:

Perché non dovrei usare un operatore di base per eseguire un'operazione di base?


Perché quello che vogliono sapere è se sai come funziona il processore internamente ... l'uso di un operatore matematico alla fine eseguirà un'operazione molto simile alla risposta sopra.
RaptorX,

Oppure vogliono sapere se riesci a riconoscere un problema inutile.
Gregoire,

1
@Gregoire Sono d'accordo, non c'è assolutamente bisogno di fare una tale implementazione, Bit nella vita commerciale (Orcale) è necessario evitare di soddisfare requisiti inutili: la risposta corretta è: "Questo non ha alcun senso, perché perdere denaro per quello? ")
AlexWien il

4

Soluzione che utilizza la funzione di libreria fma () , funziona con qualsiasi numero positivo:

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

Vedi la mia altra risposta .


Bel uso della biblioteca. Perché non hai usato direttamente il risultato ++?
Folletto verde

allora la gente potrebbe dire che + è stato usato.
Otto

3

Usa cblas , incluso come parte del framework Accelerate di 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

Bene, quello era solo un dettaglio dell'implementazione, quindi potrei digitarlo come 3.0 / 1.0 anziché 0.333333, ma dovrei giocare secondo le regole. Fisso!
WJL

Inizialmente l'avevo come 3.0 / 1.0, come nel mio test. Usando un numero di precisione più elevato, dovrebbero ottenere un risultato ragionevolmente accurato. gist.github.com/3401496
wjl

3

In generale, una soluzione a questo sarebbe:

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


3

Primo:

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

Quindi scopri come risolvere 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))

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

Sebbene utilizzi +, ma qualcuno implementa già l'aggiunta bit per bit.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.