Divisez un nombre par 3 sans utiliser les opérateurs *, /, +, -,%


686

Comment voulez - vous diviser un nombre par 3 sans utiliser *, /, +, -, %, opérateurs?

Le numéro peut être signé ou non signé.


13
@AlexandreC. - ces techniques utilisent cependant l'addition (+).
hache - fait avec SOverflow le

19
C'était de l'oracle, alors quelles parties de l'oracle étiez-vous autorisé à utiliser?
Hogan

8
Le doublon identifié n'est pas un doublon. Notez que plusieurs réponses ici n'utilisent ni décalage de bit ni addition puisque cette question n'a pas limité une solution à ces opérations.
Michael Burr

66
... et voici comment PL / SQL est né.
Sedat Kapanoglu

23
Cette question est hors sujet pour SO. Il appartient à codegolf.stackexchange.com
Kromster

Réponses:


548

Il s'agit d'une fonction simple qui effectue l'opération souhaitée. Mais cela nécessite l' +opérateur, donc tout ce qu'il vous reste à faire est d'ajouter les valeurs avec des opérateurs de bits:

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

Comme Jim l'a commenté, cela fonctionne, car:

  • n = 4 * a + b
  • n / 3 = a + (a + b) / 3
  • Alors sum += a, n = a + bet itérer

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


96
C'est probablement la réponse qu'Oracle cherche. Il montre que vous savez comment les opérateurs +, -, * et / sont réellement implémentés sur le CPU: opérations simples au niveau du bit.
craig65535

21
Cela fonctionne parce que n = 4a + b, n / 3 = a + (a + b) / 3, donc additionnez + = a, n = a + b et itérez. Quand a == 0 (n <4), somme + = étage (n / 3); c'est-à-dire, 1 si n == 3, sinon 0.
Jim Balter

7
Voici une astuce que j'ai trouvée qui m'a donné une solution similaire. En décimal 1 / 3 = 0.333333:, les nombres répétitifs facilitent le calcul à l'aide de a / 3 = a/10*3 + a/100*3 + a/1000*3 + (..). En binaire, c'est presque la même chose: 1 / 3 = 0.0101010101 (base 2)ce qui mène à a / 3 = a/4 + a/16 + a/64 + (..). La division par 4 est l'origine du décalage de bits. La dernière vérification de num == 3 est nécessaire car nous n'avons que des entiers avec lesquels travailler.
Yorick Sijsling

4
En base 4 il y a encore mieux: 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 explique également pourquoi seulement 3 sont arrondis à la fin, tandis que 1 et 2 peuvent être arrondis vers le bas.
Yorick Sijsling

2
@ while1: c'est une opération ET au niveau du bit. En outre, un fait bien connu est que pour n == 2^kce qui suit est vrai:, x % n == x & (n-1)donc ici num & 3est utilisé pour effectuer num % 4alors que %n'est pas autorisé.
aplavin

436

Les conditions idiotes appellent une solution idiote:

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

Si la partie décimale est également nécessaire, déclarez simplement resultas doubleet ajoutez-y le résultat de fmod(number,divisor).

Explication de son fonctionnement

  1. Les octets d' fwriteécriture number(le nombre étant 123456 dans l'exemple ci-dessus).
  2. rewind réinitialise le pointeur de fichier à l'avant du fichier.
  3. freadlit un maximum d ' number"enregistrements" qui sont divisorlongs dans le fichier et renvoie le nombre d'éléments qu'il a lus.

Si vous écrivez 30 octets puis relisez le fichier par unités de 3, vous obtenez 10 "unités". 30/3 = 10


13
@earlNameless: vous ne savez pas ce qu'ils utilisent à l'intérieur, ils sont dans la boîte noire de "l'implémentation définie". Rien ne les empêche d'utiliser simplement des opérateurs au niveau du bit; de toute façon, ils sont en dehors du domaine de mon code, donc ce n'est pas mon problème. :)
Matteo Italia

8
@IvoFlipse de Je peux nettoyer, vous obtenez un gros quelque chose et vous le mettez dans quelque chose de trois fois trop petit, puis voyez combien il y en a. C'est environ un tiers.
Pureferret

27
a demandé au meilleur programmeur C (et le plus socialement maladroit) de notre entreprise d'expliquer le code. après cela, j'ai dit que c'était assez ingénieux. Il a dit 'ce dreck n'est pas une solution' et m'a demandé de quitter son bureau
cvursache

6
@cvursache Je pense que le fait est que la question est tellement morte au cerveau, qu'une réponse morte au cerveau est autorisée. Le "meilleur programmeur C" de votre entreprise "aurait tout aussi bien pu dire" que le dreck n'est pas une (bonne) question ".
JeremyP

17
@JeremyP: exactement. Mon point est que si dans la vie réelle on me donnait un compilateur sans support pour l'arithmétique, la seule chose sensée serait de demander un meilleur compilateur , parce que travailler dans ces conditions n'a aucun sens. Si l'intervieweur voulait vérifier mes connaissances sur la façon de mettre en œuvre la division avec des opérations au niveau du bit, il pouvait simplement être simple et le poser comme une question théorique; ce genre "d'exercices astucieux" ne fait que crier pour des réponses comme celle-ci.
Matteo Italia

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

2
Cela pourrait en fait fonctionner s'il est arrondi correctement et si le nombre n'est pas trop grand.
Mysticial

252
Version améliorée: log (pow (exp (nombre), sin (atan2 (1, sqrt (8)))))))
Alan Curry

@bitmask, les fonctions mathématiques sont généralement implémentées directement dans asm.
SingerOfTheFall

7
je viens de le taper dans ma console js, cela ne fonctionne pas avec un nombre supérieur à 709 (c'est peut-être juste mon système) Math.log(Math.pow(Math.exp(709),0.33333333333333333333))etMath.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

Vous pouvez utiliser un assemblage en ligne (dépendant de la plate-forme), par exemple, pour x86: (fonctionne également pour les nombres négatifs)

#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 votre commentaire n'échoue-t-il pas en supposant que la réponse ne peut pas être écrite en C? La question est étiquetée "C" après tout.
Seth Carnegie

1
@SethCarnegie La réponse n'est pas écrite en C est mon point. L'assembleur x86 ne fait pas partie de la norme.
JeremyP

1
@JeremyP c'est vrai, mais la asmdirective l'est. Et j'ajouterais que les compilateurs C ne sont pas les seuls à avoir des assembleurs en ligne, Delphi en a aussi.
Seth Carnegie

7
@SethCarnegie La asmdirective n'est mentionnée que dans la norme C99 à l'annexe J - extensions courantes.
JeremyP

2
Échoue dans arm-eabi-gcc.
Damian Yerrick

106

Utilisez itoa pour convertir en une chaîne de base 3. Déposez le dernier trit et reconvertissez en 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 Je ne savais pas vraiment que cela itoapourrait utiliser une base arbitraire. Si vous effectuez une implémentation de travail complète en utilisant itoaje vais voter.
Mysticial

2
L'implémentation contiendra /et %... :-)
R .. GitHub STOP HELPING ICE

2
@R .. De même que l'implémentation de printfpour afficher votre résultat décimal.
Damian Yerrick

57

(note: voir Edit 2 ci-dessous pour une meilleure version!)

Ce n'est pas aussi compliqué que cela puisse paraître, car vous avez dit "sans utiliser les opérateurs [..] +[..] ". Voir ci-dessous, si vous souhaitez interdire d'utiliser le caractère tous ensemble.+

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

puis dites simplement div_by(100,3)de diviser 100par 3.


Edit : Vous pouvez continuer et remplacer également l' ++opérateur:

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: Version légèrement plus rapide sans utiliser l' opérateur qui contient les +, -, *, /, % caractères .

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

Nous utilisons le premier argument de la addfonction car nous ne pouvons pas désigner le type de pointeurs sans utiliser le *caractère, sauf dans les listes de paramètres de fonction, où la syntaxe type[]est identique à type* const.

FWIW, vous pouvez facilement implémenter une fonction de multiplication en utilisant une astuce similaire pour utiliser l' 0x55555556astuce proposée par AndreyT :

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

5
La question est balisée c , pas SQL, même si Oracle est mentionné.
bitmask

3
Cela ne ressemble en effet pas à SQL!
moooeeeep

64
Si vous pouvez utiliser ++: Pourquoi n'utilisez -vous pas simplement /=?
qwertz

5
@bitmask: ++est également un raccourci: pour num = num + 1.
qwertz

4
@bitmask Oui, mais +=c'est finalement un raccourci pour num = num + 1.
qwertz

44

C'est facilement possible sur l' ordinateur Setun .

Pour diviser un entier par 3, décaler vers la droite de 1 place .

Je ne sais pas s'il est strictement possible d'implémenter un compilateur C conforme sur une telle plate-forme. Nous devrons peut-être étirer un peu les règles, comme interpréter "au moins 8 bits" comme "capable de contenir au moins des entiers de -128 à +127".


8
Le problème est que vous n'avez pas d'opérateur "décalage à droite d'une place" en C. L' >>opérateur est l'opérateur "division par 2 ^ n", c'est-à-dire qu'il est spécifié en termes d'arithmétique, pas de représentation machine.
R .. GitHub STOP HELPING ICE

L'ordinateur Setun n'est pas binaire dans tous les sens du terme, donc le jeu d'instructions doit être définitivement différent. Cependant, je ne connais pas du tout le fonctionnement de cet ordinateur, donc je ne peux pas confirmer si la réponse est vraiment correcte - mais au moins elle a du sens - et est très originale. +1
virolino

32

Comme il s'agit d'Oracle, que diriez-vous d'un tableau de recherche de réponses pré-calculées. :-RÉ


32

Voici ma solution:

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

Tout d'abord, notez que

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

Maintenant, le reste est simple!

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

Il ne nous reste plus qu'à additionner ces valeurs décalées d'un bit! Oops! Nous ne pouvons pas ajouter cependant, alors à la place, nous devrons écrire une fonction d'ajout à l'aide d'opérateurs bit à bit! Si vous connaissez les opérateurs au niveau du bit, ma solution devrait être assez simple ... mais juste au cas où vous ne le seriez pas, je vais parcourir un exemple à la fin.

Une autre chose à noter est que je décale d'abord de 30 par gauche! Il s'agit de s'assurer que les fractions ne sont pas arrondies.

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!

C'est tout simplement un complément que vous avez appris enfant!

111
 1011
+0110
-----
10001

Cette implémentation a échoué car nous ne pouvons pas ajouter tous les termes de l'équation:

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

Supposons alors la retaille de div_by_3(a)= x x <= floor(f(a, i)) < a / 3. Quand a = 3k, nous obtenons une mauvaise réponse.


2
ça marche pour l'entrée de 3? 1/4, 1/16, ... renvoient tous 0 pour 3, donc résumeraient à 0, mais 3/3 = 1.
hache - fait avec SOverflow le

1
La logique est bonne mais la mise en œuvre est problématique. L'approximation en série de n/3est toujours inférieure à n/3ce qui signifie que pour tout n=3kle résultat serait k-1au lieu de k.
Xyand

@Albert, Ce fut la première approche que j'ai essayée, avec quelques variantes, mais elles ont toutes échoué sur certains nombres également divisibles par 3 ou divisibles par 2 (en fonction de la variation). J'ai donc essayé quelque chose de plus simple. Je voudrais voir une mise en œuvre de cette approche qui fonctionne, pour voir où je bousillais.
hache - fait avec SOverflow le

@hatchet, La question est fermée donc je ne peux pas poster une nouvelle réponse mais l'idée est d'implémenter une div binaire. Je devrais être facile à rechercher.
2012


25

Pour diviser un nombre 32 bits par 3, on peut le multiplier par 0x55555556puis prendre les 32 bits supérieurs du résultat 64 bits.

Il ne reste plus qu'à implémenter la multiplication à l'aide d'opérations binaires et de décalages ...


1
Il s'agit d'une astuce de compilation courante pour contourner les divisions lentes. Mais vous devez probablement faire quelques corrections, car 0x55555556 / 2 ** 32 n'est pas exactement 1/3.
CodesInChaos

multiply it. Cela n'impliquerait-il pas l'utilisation de l' *opérateur interdit ?
luiscubal

8
@luiscubal: Non, ce ne sera pas le cas. C'est pourquoi j'ai dit: "Maintenant, tout ce qui reste à faire est de mettre en œuvre la multiplication en utilisant des opérations et des décalages de bits "
AnT

18

Encore une autre solution. Cela devrait gérer tous les entiers (y compris les entiers négatifs) à l'exception de la valeur min d'un entier, qui devrait être traitée comme une exception codée en dur. Cela fait essentiellement la division par soustraction mais uniquement en utilisant des opérateurs de bits (décalages, xor et & et complément). Pour une vitesse plus rapide, il soustrait 3 * (puissance décroissante de 2). En c #, il exécute environ 444 de ces appels DivideBy3 par milliseconde (2,2 secondes pour 1000000 de divisions), donc pas terriblement lent, mais pas aussi rapide qu'un simple x / 3. En comparaison, la belle solution de Coodey est environ 5 fois plus rapide que celle-ci.

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'est c # parce que c'est ce que j'avais à portée de main, mais les différences par rapport à c devraient être mineures.


Vous devez seulement essayer de soustraire sub une fois, car si vous pouviez le soustraire deux fois, vous auriez pu le soustraire à l'itération précédente alors qu'il était deux fois plus gros qu'il ne l'est maintenant.
Neil

Est-ce que cela (a >= sub)compte comme une soustraction?
Neil

@Neil, je pense que vous avez peut-être raison. Le while interne pourrait être remplacé par un simple if, ce qui permet d'économiser une comparaison inutile de la deuxième itération de la boucle. En ce qui concerne> = être soustraction ... J'espère que non, car cela rendrait cela assez difficile! Je vois votre point, mais je pense que je me pencherais sur le côté qui dit> = ne compte pas comme soustraction.
hache - fait avec SOverflow le

@Neil, j'ai fait ce changement, ce qui a réduit le temps de moitié (a également sauvé les négatifs inutiles).
hache - fait avec SOverflow le

16

C'est vraiment assez simple.

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;

(J'ai bien sûr omis une partie du programme par souci de concision.) Si le programmeur se lasse de tout taper, je suis sûr qu'il ou elle pourrait écrire un programme distinct pour le générer pour lui. Il se trouve que je connais un certain opérateur /, qui simplifierait énormément son travail.


8
Vous pouvez utiliser une instruction à la Dictionary<number, number>place des ifinstructions répétées pour gagner en O(1)complexité!
Peter Olson

@EnesUnal Non, le temps augmente linéairement à mesure que le nombre augmente, car il doit parcourir de plus en plus d'instructions if.
Peter Olson

Théoriquement, cela n'augmente pas :)
totten

@PeterOlson, EresUnal si j'utilisais une instruction switch, ce serait O (1) :-)
thedayturns

Ou vous pouvez générer un tableau et utiliser la programmation dynamique. si x / 3 = y, alors y << 2 + y = x - x% 3.
lsiebert

14

L'utilisation de compteurs est une solution de 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
    }
}

Il est également facile d'effectuer une fonction de module, vérifiez les commentaires.


@Enes Unal: pas pour les petits nombres :) Cet algorithme est très basique.
GJ.

Chaque primitivité comprend des faiblesses :)
totten

11

Celui-ci est l'algorithme de division classique en 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

Écrivez le programme en Pascal et utilisez le DIV opérateur.

Puisque la question est balisée , vous pouvez probablement écrire une fonction en Pascal et l'appeler depuis votre programme C; la méthode pour ce faire est spécifique au système.

Mais voici un exemple qui fonctionne sur mon système Ubuntu avec le fp-compilerpackage Free Pascal installé. (Je le fais par entêtement purement déplacé; je ne prétends pas que cela soit 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;
}

Construire:

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

Exemple d'exécution:

$ ./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
Les opérateurs ++ et - sont différents des opérateurs + et -! En langage assembleur, il y a deux instructions ADDet INCils n'ont pas les mêmes opcodes.
Amir Saniyan

7

Je n'ai pas recoupé si cette réponse est déjà publiée. Si le programme doit être étendu à des nombres flottants, les nombres peuvent être multipliés par 10 * nombre de précision nécessaire, puis le code suivant peut être appliqué à nouveau.

#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

Cela devrait fonctionner pour n'importe quel diviseur, pas seulement pour trois. Actuellement uniquement pour les non signés, mais l'étendre à signé ne devrait pas être si 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

Serait-ce de la triche d'utiliser l' /opérateur "en coulisses" en utilisant evalet la concaténation de chaînes?

Par exemple, dans Javacript, vous pouvez faire

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

7

Utilisation de BC Math en PHP :

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

MySQL (c'est une interview d'Oracle)

> SELECT 12345 DIV 3;

Pascal :

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

langage d'assemblage x86-64:

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

1
Histoire cool, c'est le tag C et ce depuis le premier jour. De plus, vous ne parvenez pas à saisir le point de la question.
Lundin

6

D'abord que j'ai trouvé.

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: Désolé, je n'ai pas remarqué la balise C. Mais vous pouvez utiliser l'idée du formatage des chaînes, je suppose ...


5

Le script suivant génère un programme C qui résout le problème sans utiliser les opérateurs * / + - %:

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

Et cette approche (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;
    }

Il s'agit du tag C et cela depuis le premier jour.
Lundin

4

Je pense que la bonne réponse est:

Pourquoi ne devrais-je pas utiliser un opérateur de base pour effectuer une opération de base?


Parce que ce qu'ils veulent savoir, c'est si vous savez comment le processeur fonctionne en interne ... en utilisant un opérateur mathématique, vous finirez par effectuer une opération très similaire à la réponse ci-dessus.
RaptorX

Ou ils veulent savoir si vous pouvez reconnaître un problème inutile.
Gregoire

1
@Gregoire Je suis d'accord, il n'y a absolument pas besoin de faire une telle implémentation, Bit dans la vie commerciale (Orcale) il est nécessaire d'éviter de remplir des exigences inutiles: La bonne réponse est: "Cela n'a aucun sens, pourquoi perdre de l'argent pour ça? ")
AlexWien

4

Solution utilisant la fonction de bibliothèque fma () , fonctionne pour tout nombre positif:

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

Voir ma autre réponse .


Belle utilisation de la bibliothèque. Pourquoi n'avez-vous pas directement utilisé result ++?
Gobelin vert

alors les gens peuvent dire que + a été utilisé.
Huit

3

Utilisez cblas , inclus dans le cadre de l'accélération 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

Eh bien, c'était juste un détail d'implémentation pour que je puisse le taper 3.0 / 1.0 au lieu de 0.333333, mais je devrais respecter les règles. Fixé!
wjl

Je l'avais à l'origine comme 3.0 / 1.0, ce qui a été le cas lors de mon test. En utilisant un nombre de précision plus élevé, ils devraient obtenir un résultat raisonnablement précis. gist.github.com/3401496
wjl

3

En règle générale, une solution à ce problème serait:

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


3

Première:

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

Ensuite, découvrez comment résoudre 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))

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

Bien qu'il utilise +, mais quelqu'un implémente déjà add by bitwise op.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.