Come si dividere un numero per 3 senza utilizzare *
, /
, +
, -
, %
, gli operatori?
Il numero può essere firmato o non firmato.
Come si dividere un numero per 3 senza utilizzare *
, /
, +
, -
, %
, gli operatori?
Il numero può essere firmato o non firmato.
Risposte:
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 + b
e iterare
Quando a == 0 (n < 4)
, sum += floor(n / 3);
ovvero 1,if n == 3, else 0
1 / 3 = 0.333333
i 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.
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.
n == 2^k
quanto segue è vero:, x % n == x & (n-1)
quindi qui num & 3
viene utilizzato per eseguire num % 4
mentre %
non è consentito.
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 result
as double
e aggiungere ad essa il risultato di fmod(number,divisor)
.
Spiegazione di come funziona
fwrite
scrive number
byte (numero essendo 123456 nell'esempio di cui sopra).rewind
reimposta il puntatore del file all'inizio del file.fread
legge un massimo di number
"record" che sono divisor
in 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
log(pow(exp(number),0.33333333333333333333)) /* :-) */
Math.log(Math.pow(Math.exp(709),0.33333333333333333333))
eMath.log(Math.pow(Math.exp(709),Math.sin(Math.atan2(1,Math.sqrt(8)))))
È 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;
}
asm
direttiva lo è. E aggiungerei che i compilatori C non sono i soli ad avere assemblatori in linea, ma anche Delphi.
asm
direttiva è menzionata solo nello standard C99 nell'Appendice J - estensioni comuni.
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
}
itoa
potesse usare una base arbitraria. Se itoa
esegui un'implementazione completa e funzionante usando Upvote.
/
e %
... :-)
printf
per visualizzare il risultato decimale.
(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 100
per 3
.
++
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)
}
+
, -
, *
, /
, %
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 add
funzione 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 0x55555556
trucco proposto da AndreyT :
int mul(int const x, int const y) {
return sizeof(struct {
char const ignore[y];
}[x]);
}
++
: Perché non lo usi semplicemente /=
?
++
è anche una scorciatoia: per num = num + 1
.
+=
è finalmente una scorciatoia per num = num + 1
.
È 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".
>>
operatore è l'operatore "divisione per 2 ^ n", cioè è specificato in termini di aritmetica, non di rappresentazione della macchina.
Dal momento che proviene da Oracle, che ne dici di una tabella di ricerca di risposte precalcolate. :-D
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 = 3k
riceviamo una risposta sbagliata.
n/3
è sempre minore di n/3
ciò significa che per qualsiasi n=3k
risultato sarebbe k-1
invece di k
.
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 ...
multiply it
. Ciò non implicherebbe l'uso *
dell'operatore proibito ?
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.
(a >= sub)
conta come una sottrazione?
È 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.
Dictionary<number, number>
anziché ripetute in if
modo da avere O(1)
complessità temporale!
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.
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);
}
Scrivi il programma in Pascal e usa l' DIV
operatore.
Dal momento che la domanda è taggata c, 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-compiler
pacchetto 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
int div3(int x)
{
int reminder = abs(x);
int result = 0;
while(reminder >= 3)
{
result++;
reminder--;
reminder--;
reminder--;
}
return result;
}
ADD
e INC
che non hanno gli stessi codici operativi.
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;
}
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;
}
Sarebbe imbarazzante usare l' /
operatore "dietro le quinte" usando eval
e la concatenazione delle stringhe?
Ad esempio, in Javacript, puoi farlo
function div3 (n) {
var div = String.fromCharCode(47);
return eval([n, div, 3].join(""));
}
<?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
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 ...
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));
}
''')
Usando il calcolatore del numero di Hacker Delight Magic
int divideByThree(int num)
{
return (fma(num, 1431655766, 0) >> 32);
}
Dove fma è una funzione di libreria standard definita math.h
nell'intestazione.
-
né l' *
operatore?
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;
}
Penso che la risposta giusta sia:
Perché non dovrei usare un operatore di base per eseguire un'operazione di base?
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);
}
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
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.