@AlexandreC. - Sin embargo, esas técnicas están usando la suma (+).
hacha - hecho con SOverflow
19
Este era el oráculo, entonces, ¿qué partes del oráculo se les permitió usar?
Hogan
8
El duplicado identificado no es un duplicado. Tenga en cuenta que varias respuestas aquí no utilizan ni desplazamiento ni adición de bits, ya que esta pregunta no restringió una solución a esas operaciones.
Esta es una función simple que realiza la operación deseada. Pero requiere el +operador, por lo que todo lo que queda por hacer es agregar los valores con operadores 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;}
Como Jim comentó, esto funciona porque:
n = 4 * a + b
n / 3 = a + (a + b) / 3
Por lo tanto sum += a, n = a + by iterate
Cuando a == 0 (n < 4), sum += floor(n / 3);es decir, 1,if n == 3, else 0
Esta es probablemente la respuesta que Oracle está buscando. Muestra que sabe cómo los operadores +, -, * y / se implementan realmente en la CPU: operaciones simples a nivel de bits.
craig65535
21
Esto funciona porque n = 4a + b, n / 3 = a + (a + b) / 3, entonces suma + = a, n = a + b e itera. Cuando a == 0 (n <4), suma + = piso (n / 3); es decir, 1 si n == 3, si no 0.
Jim Balter
77
Aquí hay un truco que encontré que me dio una solución similar. En decimal: 1 / 3 = 0.333333los números repetidos hacen que sea fácil de calcular usando a / 3 = a/10*3 + a/100*3 + a/1000*3 + (..). En binario es casi lo mismo: lo 1 / 3 = 0.0101010101 (base 2)que lleva a a / 3 = a/4 + a/16 + a/64 + (..). Dividiendo por 4 es de donde viene el cambio de bit. La última comprobación de num == 3 es necesaria porque solo tenemos enteros con los que trabajar.
Yorick Sijsling
44
En base 4 se pone aún mejor: 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 también explica por qué solo 3 se redondea al final, mientras que 1 y 2 se pueden redondear hacia abajo.
Yorick Sijsling
2
@ while1: es operación AND a nivel de bits. Además, un hecho bien conocido es que n == 2^klo siguiente es cierto: x % n == x & (n-1)así que aquí num & 3se usa para realizar num % 4mientras %no está permitido.
aplavin
436
Las condiciones idiotas requieren una solución idiota:
@earlNameless: no sabes lo que usan adentro, están en el cuadro negro de "implementación definida". Nada les impide usar operadores bit a bit; de todos modos, están fuera del dominio de mi código, así que ese no es mi problema. :)
Matteo Italia
8
@IvoFlipse de Puedo limpiar, obtienes algo grande y lo pones en algo tres veces demasiado pequeño, y luego ves cuánto encaja. Eso es un tercio.
Pureferret
27
le pedimos al mejor programador de C (y el más incómodo socialmente) de nuestra compañía que explicara el código. después de que lo hizo, dije que era bastante ingenioso. Dijo 'dreck esta no es una solución' y me pidió que deje su escritorio
cvursache
66
@cvursache Creo que el punto es que la pregunta es tan cerebral que se permite una respuesta con muerte cerebral. El "mejor programador de C" en su empresa "podría haber dicho con la misma facilidad" que dreck no es una pregunta (adecuada) ".
JeremyP
17
@ JeremyP: exactamente. Mi punto es que si en la vida real me dieron un compilador sin soporte para aritmética, lo único sensato sería pedir un mejor compilador , porque trabajar en esas condiciones no tiene ningún sentido. Si el entrevistador quisiera verificar mi conocimiento sobre cómo implementar la división con operaciones bit a bit, podría ser sencillo y formularlo como una pregunta teórica; este tipo de "ejercicios de truco" solo grita por respuestas como esta.
Esto podría funcionar si se redondea correctamente y si el número no es demasiado grande.
Mysticial
252
Versión mejorada: log (pow (exp (número), sin (atan2 (1, sqrt (8)))))
Alan Curry
@bitmask, las funciones matemáticas generalmente se implementan directamente en asm.
SingerOfTheFall
77
Acabo de escribirlo en mi consola js, no funciona con un número superior a 709 (puede ser solo mi sistema) Math.log(Math.pow(Math.exp(709),0.33333333333333333333))yMath.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, ¿su comentario no falla en el supuesto de que la respuesta no se puede escribir en C? La pregunta está etiquetada con "C" después de todo.
Seth Carnegie
1
@SethCarnegie La respuesta no está escrita en C es mi punto. El ensamblador x86 no es parte del estándar.
JeremyP
1
@JeremyP eso es cierto, pero la asmdirectiva sí. Y agregaría que los compiladores de C no son los únicos que tienen ensambladores en línea, Delphi también lo tiene.
Seth Carnegie
77
@SethCarnegie La asmdirectiva solo se menciona en el estándar C99 en el Apéndice J: extensiones comunes.
JeremyP
2
Falla en arm-eabi-gcc.
Damian Yerrick
106
Use itoa para convertir a una cadena de base 3. Suelta el último trit y vuelve a convertir a la 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 En realidad no sabía que itoapodría usar una base arbitraria. Si haces una implementación de trabajo completa usando itoa, votaré.
Mysticial
2
La implementación contendrá /y %... :-)
R .. GitHub DEJA DE AYUDAR AL HIELO
2
@R .. También lo hace la implementación de printfpara mostrar su resultado decimal.
Damian Yerrick
57
(nota: vea Edición 2 a continuación para una mejor versión)
Esto no es tan complicado como parece, porque dijiste "sin usar los operadores [..] +[..] ". Vea a continuación, si desea prohibir el uso del personaje todos juntos.+
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;}
entonces solo di div_by(100,3)dividir 100por 3.
Editar : también puede continuar y reemplazar el ++operador:
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)}
Edición 2: Ligeramente más rápido versión sin necesidad de utilizar cualquier operador que contiene las +, -, *, /, %caracteres .
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;}
Usamos el primer argumento de la addfunción porque no podemos denotar el tipo de punteros sin usar el *carácter, excepto en las listas de parámetros de funciones, donde la sintaxis type[]es idéntica type* const.
FWIW, puedes implementar fácilmente una función de multiplicación usando un truco similar para usar el 0x55555556truco propuesto por AndreyT :
int mul(intconst x,intconst y){returnsizeof(struct{charconst ignore[y];}[x]);}
Sin embargo, no estoy seguro de si es estrictamente posible implementar un compilador de C conforme en dicha plataforma. Es posible que tengamos que estirar un poco las reglas, como interpretar "al menos 8 bits" como "capaz de contener al menos enteros de -128 a +127".
El problema es que no tiene un operador de "desplazamiento a la derecha por 1 lugar" en C. El >>operador es el operador de "división por 2 ^ n", es decir, se especifica en términos de representación aritmética, no de máquina.
R .. GitHub DEJA DE AYUDAR AL HIELO
La computadora Setun no es binaria en ningún sentido de la palabra, por lo que el conjunto de instrucciones debe ser definitivamente diferente. Sin embargo, no estoy familiarizado con el funcionamiento de esa computadora, por lo que no puedo confirmar si la respuesta es realmente correcta, pero al menos tiene sentido, y es muy original. +1
virolino
32
Dado que es de Oracle, ¿qué tal una tabla de búsqueda de respuestas calculadas previamente. :-RE
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);}
Primero, tenga en cuenta que
1/3=1/4+1/16+1/64+...
¡Ahora, el resto es 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+...
Ahora todo lo que tenemos que hacer es sumar estos valores desplazados de bits de a! ¡Uy! Sin embargo, no podemos agregar, así que en su lugar, tendremos que escribir una función de agregar usando operadores de bits. Si está familiarizado con los operadores en cuanto a bits, mi solución debería parecer bastante simple ... pero en caso de que no lo esté, le explicaré un ejemplo al final.
¡Otra cosa a tener en cuenta es que primero cambio a la izquierda por 30! Esto es para asegurarse de que las fracciones no se redondeen.
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!
¡Es simplemente una adición que aprendiste de niño!
1111011+0110-----10001
Esta implementación falló porque no podemos agregar todos los términos de la ecuación:
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
Supongamos que el resultado de div_by_3(a)= x, entonces x <= floor(f(a, i)) < a / 3. Cuando a = 3k, recibimos una respuesta incorrecta.
¿funciona para la entrada de 3? 1/4, 1/16, ... todos devuelven 0 para 3, por lo que
sumaría
1
La lógica es buena pero la implementación es problemática. La aproximación en serie de n/3siempre es menor que lo n/3que significa que para cualquiera n=3kel resultado sería en k-1lugar de k.
Xyand
@ Albert, este fue el primer enfoque que probé, con un par de variaciones, pero todas fallaron en ciertos números divisibles por 3 o divisibles por 2 (dependiendo de la variación). Así que probé algo más directo. Me gustaría ver una implementación de este enfoque que funcione, para ver dónde estaba metiendo la pata.
hacha - hecho con SOverflow
@hatchet, la pregunta está cerrada, así que no puedo publicar una nueva respuesta, pero la idea es implementar div binario. Debería ser fácil buscarlo.
Este es un truco de compilación común para evitar divisiones lentas. Pero probablemente necesite hacer algunas reparaciones, ya que 0x55555556 / 2 ** 32 no es exactamente 1/3.
CodesInChaos
multiply it. ¿No implicaría eso usar el *operador prohibido ?
luiscubal
8
@luiscubal: No, no lo hará. Es por eso que dije: "Ahora todo lo que queda por hacer es implementar la multiplicación usando operaciones de bit y cambios "
AnT
18
Otra solución más. Esto debería manejar todas las entradas (incluidas las entradas negativas) excepto el valor mínimo de un int, que debería manejarse como una excepción codificada. Básicamente, esto hace la división por sustracción, pero solo usa operadores de bits (desplazamientos, xor y &). Para una velocidad más rápida, resta 3 * (potencias decrecientes de 2). En c #, ejecuta alrededor de 444 de estas llamadas DivideBy3 por milisegundo (2.2 segundos para 1,000,000 de divisiones), por lo que no es terriblemente lento, pero no tan rápido como un simple x / 3. En comparación, la buena solución de Coodey es aproximadamente 5 veces más rápida que esta.
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;}
Esto es c # porque eso es lo que tenía a mano, pero las diferencias con respecto a c deberían ser menores.
Solo necesita tratar de restar sub una vez, porque si hubiera podido restarlo dos veces, podría haber restado la iteración anterior cuando era dos veces más grande que ahora.
Neil
¿ (a >= sub)Cuenta como una resta?
Neil
@Neil, creo que tienes razón. El while interno podría reemplazarse por un simple if, guardando una comparación innecesaria de la segunda iteración del bucle. Con respecto a> = ser resta ... ¡espero que no, porque eso haría que hacer esto sea bastante difícil! Veo su punto, pero creo que me apoyaría en el lado que dice> = no cuenta como resta.
hacha - hecho con SOverflow
@Neil, hice ese cambio, que redujo el tiempo a la mitad (también ahorró Negates innecesarios).
(Por supuesto, he omitido parte del programa en aras de la brevedad). Si el programador se cansa de escribir todo esto, estoy seguro de que él o ella podría escribir un programa separado para generarlo para él. Estoy al tanto de un cierto operador /que simplificaría enormemente su trabajo.
@Enes Unal: no para números pequeños :) Este algoritmo es muy básico.
GJ.
Cada primitividad incluye debilidades :)
totten
11
Este es el algoritmo de división clásica en la 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);}
Escriba el programa en Pascal y use el DIVoperador.
Como la pregunta está etiquetada C, probablemente pueda escribir una función en Pascal y llamarla desde su programa C; El método para hacerlo es específico del sistema.
Pero aquí hay un ejemplo que funciona en mi sistema Ubuntu con el fp-compilerpaquete Free Pascal instalado. (Estoy haciendo esto por pura terquedad fuera de lugar; no pretendo que esto sea útil).
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;}
Para construir:
fpc divide_by_3.pas && gcc divide_by_3.o main.c -o main
Los operadores ++ y - son diferentes de los operadores + y -! En lenguaje ensamblador hay dos instrucciones ADDy INCque no tienen los mismos códigos de operación.
Amir Saniyan
7
No verifiqué si esta respuesta ya está publicada. Si el programa necesita extenderse a números flotantes, los números se pueden multiplicar por 10 * número de precisión necesaria y luego se puede aplicar nuevamente el siguiente código.
#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;}
Esto debería funcionar para cualquier divisor, no solo para tres. Actualmente solo para no firmados, pero extenderlo a firmado no debería ser tan difícil.
#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;}
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;}
Porque lo que quieren saber es si sabes cómo funciona internamente el procesador ... al usar un operador matemático, al final, realizarás una operación muy similar a la respuesta anterior.
RaptorX
O quieren saber si puedes reconocer un problema inútil.
Gregoire
1
@Gregoire Estoy de acuerdo, no hay necesidad de hacer tal implementación, Bit en la vida comercial (Orcale) es necesario para evitar cumplir requisitos inútiles: la respuesta correcta es: "Esto no tiene ningún sentido, por qué perder dinero para eso? ")
#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);}
Bueno, eso fue solo un detalle de implementación, así que podría escribirlo como 3.0 / 1.0 en lugar de 0.333333, pero debería seguir las reglas. ¡Fijo!
wjl
Originalmente lo tenía como 3.0 / 1.0, que hice en mi prueba. Al utilizar un número de mayor precisión, deberían obtener un resultado razonablemente preciso. gist.github.com/3401496
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)}
Aunque usa +, pero alguien ya implementa add by bitwise op.
Respuestas:
Esta es una función simple que realiza la operación deseada. Pero requiere el
+
operador, por lo que todo lo que queda por hacer es agregar los valores con operadores de bits:Como Jim comentó, esto funciona porque:
n = 4 * a + b
n / 3 = a + (a + b) / 3
Por lo tanto
sum += a
,n = a + b
y iterateCuando
a == 0 (n < 4)
,sum += floor(n / 3);
es decir, 1,if n == 3, else 0
fuente
1 / 3 = 0.333333
los números repetidos hacen que sea fácil de calcular usandoa / 3 = a/10*3 + a/100*3 + a/1000*3 + (..)
. En binario es casi lo mismo: lo1 / 3 = 0.0101010101 (base 2)
que lleva aa / 3 = a/4 + a/16 + a/64 + (..)
. Dividiendo por 4 es de donde viene el cambio de bit. La última comprobación de num == 3 es necesaria porque solo tenemos enteros con los que trabajar.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 también explica por qué solo 3 se redondea al final, mientras que 1 y 2 se pueden redondear hacia abajo.n == 2^k
lo siguiente es cierto:x % n == x & (n-1)
así que aquínum & 3
se usa para realizarnum % 4
mientras%
no está permitido.Las condiciones idiotas requieren una solución idiota:
Si también se necesita la parte decimal, simplemente declara
result
comodouble
y agrégale el resultado defmod(number,divisor)
.Explicación de cómo funciona.
fwrite
escrituranumber
(el número es 123456 en el ejemplo anterior).rewind
restablece el puntero del archivo al frente del archivo.fread
lee un máximo denumber
"registros" que tienen unadivisor
longitud del archivo y devuelve el número de elementos que lee.Si escribe 30 bytes y luego vuelve a leer el archivo en unidades de 3, obtendrá 10 "unidades". 30/3 = 10
fuente
fuente
Math.log(Math.pow(Math.exp(709),0.33333333333333333333))
yMath.log(Math.pow(Math.exp(709),Math.sin(Math.atan2(1,Math.sqrt(8)))))
fuente
Puede usar el ensamblaje en línea (dependiente de la plataforma), por ejemplo, para x86: (también funciona para números negativos)
fuente
asm
directiva sí. Y agregaría que los compiladores de C no son los únicos que tienen ensambladores en línea, Delphi también lo tiene.asm
directiva solo se menciona en el estándar C99 en el Apéndice J: extensiones comunes.Use itoa para convertir a una cadena de base 3. Suelta el último trit y vuelve a convertir a la base 10.
fuente
itoa
podría usar una base arbitraria. Si haces una implementación de trabajo completa usandoitoa
, votaré./
y%
... :-)printf
para mostrar su resultado decimal.(nota: vea Edición 2 a continuación para una mejor versión)
Esto no es tan complicado como parece, porque dijiste "sin usar los operadores [..]
+
[..] ". Vea a continuación, si desea prohibir el uso del personaje todos juntos.+
entonces solo di
div_by(100,3)
dividir100
por3
.Editar : también puede continuar y reemplazar el
++
operador:Edición 2: Ligeramente más rápido versión sin necesidad de utilizar cualquier operador que contiene las
+
,-
,*
,/
,%
caracteres .Usamos el primer argumento de la
add
función porque no podemos denotar el tipo de punteros sin usar el*
carácter, excepto en las listas de parámetros de funciones, donde la sintaxistype[]
es idénticatype* const
.FWIW, puedes implementar fácilmente una función de multiplicación usando un truco similar para usar el
0x55555556
truco propuesto por AndreyT :fuente
++
: ¿Por qué no lo usa simplemente/=
?++
también es un acceso directo: paranum = num + 1
.+=
finalmente es un atajo paranum = num + 1
.Es fácilmente posible en la computadora Setun .
Para dividir un número entero entre 3, cambie a la derecha por 1 lugar .
Sin embargo, no estoy seguro de si es estrictamente posible implementar un compilador de C conforme en dicha plataforma. Es posible que tengamos que estirar un poco las reglas, como interpretar "al menos 8 bits" como "capaz de contener al menos enteros de -128 a +127".
fuente
>>
operador es el operador de "división por 2 ^ n", es decir, se especifica en términos de representación aritmética, no de máquina.Dado que es de Oracle, ¿qué tal una tabla de búsqueda de respuestas calculadas previamente. :-RE
fuente
Aquí está mi solución:
Primero, tenga en cuenta que
¡Ahora, el resto es simple!
Ahora todo lo que tenemos que hacer es sumar estos valores desplazados de bits de a! ¡Uy! Sin embargo, no podemos agregar, así que en su lugar, tendremos que escribir una función de agregar usando operadores de bits. Si está familiarizado con los operadores en cuanto a bits, mi solución debería parecer bastante simple ... pero en caso de que no lo esté, le explicaré un ejemplo al final.
¡Otra cosa a tener en cuenta es que primero cambio a la izquierda por 30! Esto es para asegurarse de que las fracciones no se redondeen.
¡Es simplemente una adición que aprendiste de niño!
Esta implementación falló porque no podemos agregar todos los términos de la ecuación:
Supongamos que el resultado de
div_by_3(a)
= x, entoncesx <= floor(f(a, i)) < a / 3
. Cuandoa = 3k
, recibimos una respuesta incorrecta.fuente
n/3
siempre es menor que lon/3
que significa que para cualquieran=3k
el resultado sería enk-1
lugar dek
.Para dividir un número de 32 bits por 3, se puede multiplicar por
0x55555556
y luego tomar los 32 bits superiores del resultado de 64 bits.Ahora todo lo que queda por hacer es implementar la multiplicación usando operaciones de bit y cambios ...
fuente
multiply it
. ¿No implicaría eso usar el*
operador prohibido ?Otra solución más. Esto debería manejar todas las entradas (incluidas las entradas negativas) excepto el valor mínimo de un int, que debería manejarse como una excepción codificada. Básicamente, esto hace la división por sustracción, pero solo usa operadores de bits (desplazamientos, xor y &). Para una velocidad más rápida, resta 3 * (potencias decrecientes de 2). En c #, ejecuta alrededor de 444 de estas llamadas DivideBy3 por milisegundo (2.2 segundos para 1,000,000 de divisiones), por lo que no es terriblemente lento, pero no tan rápido como un simple x / 3. En comparación, la buena solución de Coodey es aproximadamente 5 veces más rápida que esta.
Esto es c # porque eso es lo que tenía a mano, pero las diferencias con respecto a c deberían ser menores.
fuente
(a >= sub)
Cuenta como una resta?Es realmente bastante fácil.
(Por supuesto, he omitido parte del programa en aras de la brevedad). Si el programador se cansa de escribir todo esto, estoy seguro de que él o ella podría escribir un programa separado para generarlo para él. Estoy al tanto de un cierto operador
/
que simplificaría enormemente su trabajo.fuente
Dictionary<number, number>
lugar deif
declaraciones repetidas para que puedas tenerO(1)
complejidad de tiempo!Usar contadores es una solución básica:
También es fácil realizar una función de módulo, verifique los comentarios.
fuente
Este es el algoritmo de división clásica en la base 2:
fuente
Escriba el programa en Pascal y use el
DIV
operador.Como la pregunta está etiquetada C, probablemente pueda escribir una función en Pascal y llamarla desde su programa C; El método para hacerlo es específico del sistema.
Pero aquí hay un ejemplo que funciona en mi sistema Ubuntu con el
fp-compiler
paquete Free Pascal instalado. (Estoy haciendo esto por pura terquedad fuera de lugar; no pretendo que esto sea útil).divide_by_3.pas
:main.c
:Para construir:
Ejecución de muestra:
fuente
fuente
ADD
yINC
que no tienen los mismos códigos de operación.No verifiqué si esta respuesta ya está publicada. Si el programa necesita extenderse a números flotantes, los números se pueden multiplicar por 10 * número de precisión necesaria y luego se puede aplicar nuevamente el siguiente código.
fuente
Esto debería funcionar para cualquier divisor, no solo para tres. Actualmente solo para no firmados, pero extenderlo a firmado no debería ser tan difícil.
fuente
¿Sería una trampa usar el
/
operador "detrás de escena" usandoeval
una concatenación de cadenas?Por ejemplo, en Javacript, puedes hacer
fuente
Usando BC Math en PHP :
MySQL (es una entrevista de Oracle)
Pascal :
Lenguaje ensamblador x86-64:
fuente
Primero lo que se me ocurrió.
EDITAR: Lo siento, no noté la etiqueta
C
. Pero puedes usar la idea sobre el formato de cadenas, supongo ...fuente
El siguiente script genera un programa en C que resuelve el problema sin usar los operadores
* / + - %
:fuente
Usando la calculadora de números de Hacker's Delight Magic
Donde fma es una función de biblioteca estándar definida en el
math.h
encabezado.fuente
-
ni el*
operador?¿Qué tal este enfoque (c #)?
fuente
Creo que la respuesta correcta es:
¿Por qué no usaría un operador básico para hacer una operación básica?
fuente
La solución que usa la función de biblioteca fma () funciona para cualquier número positivo:
Mira mi otra respuesta .
fuente
Use cblas , incluido como parte del marco Acelerar de OS X.
fuente
En general, una solución a esto sería:
log(pow(exp(numerator),pow(denominator,-1)))
fuente
Primero:
Luego descubra cómo resolver x / (1 - y):
con y = 1/4:
Aunque usa
+
, pero alguien ya implementa add by bitwise op.fuente