@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.
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 + operatorint 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
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:
@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.
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);return0;}
@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 digitreturn strtol(str, NULL,3);// Read back result}
@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(unsignedconst x,unsignedconst 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;elsereturn x & mask;}return0;// 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(charconst zero[],unsignedconst x,unsignedconst y){// this exploits that &foo[bar] == foo+bar if foo is of type char*return(int)(uintptr_t)(&((&zero[x])[y]));}unsigned div_by(unsignedconst x,unsignedconst 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(intconst x,intconst y){returnsizeof(struct{charconst ignore[y];}[x]);}
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".
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É
publicstaticint div_by_3(long a){
a <<=30;for(int i =2; i <=32; i <<=1){
a = add(a, a >> i);}return(int)(a >>32);}publicstaticlong 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+61011+0110
sum =1011^0110=1101
carry =(1011&0110)<<1=0010<<1=0100Now you recurse!1101+0100
sum =1101^0100=1001
carry =(1101&0100)<<1=0100<<1=1000Again!1001+1000
sum =1001^1000=0001
carry =(1001&1000)<<1=1000<<1=10000One last time!0001+10000
sum =0001^10000=10001=17
carry =(0001&10000)<<1=0Done!
C'est tout simplement un complément que vous avez appris enfant!
1111011+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.
ç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.
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.
publicstaticintDivideBy3(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;}publicstaticintNegate(int a){returnAdd(~a,1);}publicstaticintAdd(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).
(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.
@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 enduint32_t y =0;// resultint bit =31;// current bit
printf("X=%u X/3=%u\n",x,x/3);// the '/3' is for testingwhile(bit>0){
printf("BIT=%d X=%u Y=%u\n",bit,x,y);// decrement bitint h =1;while(1){ bit ^= h;if( bit&h ) h <<=1;elsebreak;}uint32_t r = x>>bit;// current remainder in 0..5
x ^= r<<bit;// remove R bits from Xif(r >=3) y |=1<<bit;// new output bit
x |= mod3[r]<<bit;// new remainder inserted in X}
printf("Y=%u\n",y);}
Écrivez le programme en Pascal et utilisez le DIV opérateur.
Puisque la question est balisée c, 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>externint 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));return0;}
Construire:
fpc divide_by_3.pas && gcc divide_by_3.o main.c -o main
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);return0;}
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)return0;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);}return0;}
Comment cela n'utilise-t-il -pas l' *opérateur ni ?
bitmask
4
Et cette approche (c #)?
privateint dividedBy3(int n){List<Object> a =newObject[n].ToList();List<Object> b =newList<object>();while(a.Count>2){
a.RemoveRange(0,3);
b.Add(newObject());}return b.Count;}
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? ")
#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);}
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:
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.
Réponses:
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:Comme Jim l'a commenté, cela fonctionne, car:
n = 4 * a + b
n / 3 = a + (a + b) / 3
Alors
sum += a
,n = a + b
et itérerQuand
a == 0 (n < 4)
,sum += floor(n / 3);
ie 1,if n == 3, else 0
la source
1 / 3 = 0.333333
:, les nombres répétitifs facilitent le calcul à l'aide dea / 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.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.n == 2^k
ce qui suit est vrai:,x % n == x & (n-1)
donc icinum & 3
est utilisé pour effectuernum % 4
alors que%
n'est pas autorisé.Les conditions idiotes appellent une solution idiote:
Si la partie décimale est également nécessaire, déclarez simplement
result
asdouble
et ajoutez-y le résultat defmod(number,divisor)
.Explication de son fonctionnement
fwrite
écriturenumber
(le nombre étant 123456 dans l'exemple ci-dessus).rewind
réinitialise le pointeur de fichier à l'avant du fichier.fread
lit un maximum d 'number
"enregistrements" qui sontdivisor
longs 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
la source
la source
Math.log(Math.pow(Math.exp(709),0.33333333333333333333))
etMath.log(Math.pow(Math.exp(709),Math.sin(Math.atan2(1,Math.sqrt(8)))))
la source
Vous pouvez utiliser un assemblage en ligne (dépendant de la plate-forme), par exemple, pour x86: (fonctionne également pour les nombres négatifs)
la source
asm
directive l'est. Et j'ajouterais que les compilateurs C ne sont pas les seuls à avoir des assembleurs en ligne, Delphi en a aussi.asm
directive n'est mentionnée que dans la norme C99 à l'annexe J - extensions courantes.Utilisez itoa pour convertir en une chaîne de base 3. Déposez le dernier trit et reconvertissez en base 10.
la source
itoa
pourrait utiliser une base arbitraire. Si vous effectuez une implémentation de travail complète en utilisantitoa
je vais voter./
et%
... :-)printf
pour afficher votre résultat décimal.(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.+
puis dites simplement
div_by(100,3)
de diviser100
par3
.Edit : Vous pouvez continuer et remplacer également l'
++
opérateur:Edit 2: Version légèrement plus rapide sans utiliser l' opérateur qui contient les
+
,-
,*
,/
,%
caractères .Nous utilisons le premier argument de la
add
fonction 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 syntaxetype[]
est identique àtype* const
.FWIW, vous pouvez facilement implémenter une fonction de multiplication en utilisant une astuce similaire pour utiliser l'
0x55555556
astuce proposée par AndreyT :la source
++
: Pourquoi n'utilisez -vous pas simplement/=
?++
est également un raccourci: pournum = num + 1
.+=
c'est finalement un raccourci pournum = num + 1
.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".
la source
>>
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.Comme il s'agit d'Oracle, que diriez-vous d'un tableau de recherche de réponses pré-calculées. :-RÉ
la source
Voici ma solution:
Tout d'abord, notez que
Maintenant, le reste est simple!
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.
C'est tout simplement un complément que vous avez appris enfant!
Cette implémentation a échoué car nous ne pouvons pas ajouter tous les termes de l'équation:
Supposons alors la retaille de
div_by_3(a)
= xx <= floor(f(a, i)) < a / 3
. Quanda = 3k
, nous obtenons une mauvaise réponse.la source
n/3
est toujours inférieure àn/3
ce qui signifie que pour toutn=3k
le résultat seraitk-1
au lieu dek
.Pour diviser un nombre 32 bits par 3, on peut le multiplier par
0x55555556
puis 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 ...
la source
multiply it
. Cela n'impliquerait-il pas l'utilisation de l'*
opérateur interdit ?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.
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.
la source
(a >= sub)
compte comme une soustraction?C'est vraiment assez simple.
(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.la source
Dictionary<number, number>
place desif
instructions répétées pour gagner enO(1)
complexité!L'utilisation de compteurs est une solution de base:
Il est également facile d'effectuer une fonction de module, vérifiez les commentaires.
la source
Celui-ci est l'algorithme de division classique en base 2:
la source
Écrivez le programme en Pascal et utilisez le
DIV
opérateur.Puisque la question est balisée c, 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-compiler
package 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
:main.c
:Construire:
Exemple d'exécution:
la source
la source
ADD
etINC
ils n'ont pas les mêmes opcodes.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.
la source
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.
la source
Serait-ce de la triche d'utiliser l'
/
opérateur "en coulisses" en utilisanteval
et la concaténation de chaînes?Par exemple, dans Javacript, vous pouvez faire
la source
Utilisation de BC Math en PHP :
MySQL (c'est une interview d'Oracle)
Pascal :
langage d'assemblage x86-64:
la source
D'abord que j'ai trouvé.
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 ...la source
Le script suivant génère un programme C qui résout le problème sans utiliser les opérateurs
* / + - %
:la source
Utilisation du calculateur de nombres Hacker's Delight Magic
Où fma est une fonction de bibliothèque standard définie dans l'en-
math.h
tête.la source
-
pas l'*
opérateur ni ?Et cette approche (c #)?
la source
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?
la source
Solution utilisant la fonction de bibliothèque fma () , fonctionne pour tout nombre positif:
Voir ma autre réponse .
la source
Utilisez cblas , inclus dans le cadre de l'accélération OS X.
la source
En règle générale, une solution à ce problème serait:
log(pow(exp(numerator),pow(denominator,-1)))
la source
Première:
Ensuite, découvrez comment résoudre x / (1 - y):
avec y = 1/4:
Bien qu'il utilise
+
, mais quelqu'un implémente déjà add by bitwise op.la source