Bagaimana Anda membagi nomor dengan 3 tanpa menggunakan *
, /
, +
, -
, %
, operator?
Nomor tersebut dapat ditandatangani atau tidak ditandatangani.
Bagaimana Anda membagi nomor dengan 3 tanpa menggunakan *
, /
, +
, -
, %
, operator?
Nomor tersebut dapat ditandatangani atau tidak ditandatangani.
Jawaban:
Ini adalah fungsi sederhana yang melakukan operasi yang diinginkan. Tapi itu membutuhkan +
operator, jadi yang harus Anda lakukan adalah menambahkan nilai dengan operator 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;
}
Seperti yang dikomentari Jim, ini bekerja, karena:
n = 4 * a + b
n / 3 = a + (a + b) / 3
Jadi sum += a
, n = a + b
, dan iterate
Kapan a == 0 (n < 4)
, sum += floor(n / 3);
yaitu 1,if n == 3, else 0
1 / 3 = 0.333333
:, angka yang berulang membuatnya mudah untuk dihitung menggunakan a / 3 = a/10*3 + a/100*3 + a/1000*3 + (..)
. Dalam biner itu hampir sama 1 / 3 = 0.0101010101 (base 2)
:, yang mengarah ke a / 3 = a/4 + a/16 + a/64 + (..)
. Membagi dengan 4 adalah tempat bit shift berasal. Pemeriksaan terakhir pada num == 3 diperlukan karena kami hanya memiliki bilangan bulat untuk dikerjakan.
a / 3 = a * 0.111111 (base 4) = a * 4^-1 + a * 4^-2 + a * 4^-3 + (..) = a >> 2 + a >> 4 + a >> 6 + (..)
. Basis 4 juga menjelaskan mengapa hanya 3 yang dibulatkan pada akhirnya, sedangkan 1 dan 2 dapat dibulatkan ke bawah.
n == 2^k
yang berikut ini benar:, x % n == x & (n-1)
jadi di sini num & 3
digunakan untuk melakukan num % 4
sementara %
tidak diizinkan.
Kondisi idiot membutuhkan solusi idiot:
#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;
}
Jika juga bagian desimal diperlukan, cukup deklarasikan result
sebagai double
dan tambahkan hasilnya fmod(number,divisor)
.
Penjelasan tentang cara kerjanya
fwrite
menulis number
byte (jumlah menjadi 123.456 dalam contoh di atas).rewind
mengatur ulang penunjuk file ke bagian depan file.fread
membaca maksimum number
"catatan" yang divisor
panjangnya dari file, dan mengembalikan jumlah elemen yang dibacanya.Jika Anda menulis 30 byte kemudian membaca kembali file dalam unit 3, Anda mendapatkan 10 "unit". 30/3 = 10
log(pow(exp(number),0.33333333333333333333)) /* :-) */
Math.log(Math.pow(Math.exp(709),0.33333333333333333333))
danMath.log(Math.pow(Math.exp(709),Math.sin(Math.atan2(1,Math.sqrt(8)))))
Anda dapat menggunakan perakitan inline (tergantung platform), mis. Untuk x86: (juga berfungsi untuk angka negatif)
#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
arahannya. Dan saya akan menambahkan bahwa kompiler C bukan satu-satunya yang memiliki inline assembler, Delphi juga memilikinya.
asm
Arahan hanya disebutkan dalam standar C99 di bawah Lampiran J - ekstensi umum.
Gunakan itoa untuk mengonversi ke string base 3. Jatuhkan trit terakhir dan ubah kembali ke basis 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
bisa menggunakan basis sewenang-wenang. Jika Anda melakukan implementasi kerja yang lengkap menggunakan itoa
saya akan mengungguli.
/
dan %
... :-)
printf
untuk menampilkan hasil desimal Anda.
(catatan: lihat Edit 2 di bawah untuk versi yang lebih baik!)
Ini tidak sesulit kedengarannya, karena Anda mengatakan "tanpa menggunakan operator [..] +
[..] ". Lihat di bawah, jika Anda ingin melarang menggunakan karakter bersama-sama.+
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;
}
lalu katakan saja div_by(100,3)
untuk membagi 100
dengan 3
.
++
operator juga: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)
}
+
, -
, *
, /
, %
karakter .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;
}
Kami menggunakan argumen pertama dari add
fungsi karena kami tidak dapat menunjukkan tipe pointer tanpa menggunakan *
karakter, kecuali dalam daftar parameter fungsi, di mana sintaks type[]
identik dengan type* const
.
FWIW, Anda dapat dengan mudah menerapkan fungsi multiplikasi menggunakan trik serupa untuk menggunakan 0x55555556
trik yang diusulkan oleh AndreyT :
int mul(int const x, int const y) {
return sizeof(struct {
char const ignore[y];
}[x]);
}
++
: Mengapa Anda tidak menggunakan saja /=
?
++
juga merupakan jalan pintas: Untuk num = num + 1
.
+=
akhirnya jalan pintas untuk num = num + 1
.
Mudah dilakukan di komputer Setun .
Untuk membagi bilangan bulat dengan 3, geser ke kanan dengan 1 tempat .
Saya tidak yakin apakah sangat mungkin untuk mengimplementasikan kompiler C yang sesuai pada platform semacam itu. Kita mungkin harus meregangkan aturan sedikit, seperti menafsirkan "setidaknya 8 bit" sebagai "mampu menahan setidaknya bilangan bulat dari -128 ke +127".
>>
Operator adalah operator "division by 2 ^ n", artinya ditentukan dalam hal aritmatika, bukan representasi mesin.
Karena ini dari Oracle, bagaimana dengan tabel pencarian jawaban yang dihitung sebelumnya. :-D
Inilah solusi saya:
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);
}
Pertama, perhatikan itu
1/3 = 1/4 + 1/16 + 1/64 + ...
Sekarang, sisanya sederhana!
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 + ...
Sekarang yang harus kita lakukan adalah menambahkan nilai bit bergeser dari! Ups! Kami tidak dapat menambahkan, jadi alih-alih, kami harus menulis fungsi tambah menggunakan operator bit-wise! Jika Anda terbiasa dengan operator bit-bijaksana, solusi saya harus terlihat cukup sederhana ... tetapi jika Anda tidak, saya akan membahas contoh di akhir.
Satu hal yang perlu diperhatikan adalah saya pertama kali bergeser ke kiri sebanyak 30! Ini untuk memastikan bahwa pecahan tidak dibulatkan.
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!
Ini hanya membawa tambahan yang Anda pelajari sejak kecil!
111
1011
+0110
-----
10001
Implementasi ini gagal karena kami tidak dapat menambahkan semua persyaratan persamaan:
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
Misalkan reslut dari div_by_3(a)
= x, lalu x <= floor(f(a, i)) < a / 3
. Ketika a = 3k
, kami mendapat jawaban yang salah.
n/3
selalu kurang dari n/3
yang berarti bahwa untuk setiap n=3k
hasil akan menjadi k-1
bukan k
.
Untuk membagi angka 32-bit dengan 3 orang dapat mengalikannya dengan 0x55555556
dan kemudian mengambil 32 bit atas dari hasil 64 bit.
Sekarang yang harus dilakukan adalah mengimplementasikan perkalian menggunakan operasi bit dan pergeseran ...
multiply it
. Bukankah itu menyiratkan menggunakan *
operator terlarang ?
Namun solusi lain. Ini harus menangani semua int (termasuk int negatif) kecuali nilai minimum int, yang perlu ditangani sebagai pengecualian kode keras. Ini pada dasarnya melakukan pembagian dengan mengurangi tetapi hanya menggunakan operator bit (shift, xor, & dan pelengkap). Untuk kecepatan yang lebih cepat, ini mengurangi 3 * (mengurangi kekuatan 2). Dalam c #, ia mengeksekusi sekitar 444 dari panggilan DivideBy3 ini per milidetik (2,2 detik untuk 1.000.000 pembagian), jadi tidak terlalu lambat, tapi tidak sedekat kecepatan x / 3 sederhana. Sebagai perbandingan, solusi bagus Coodey adalah sekitar 5 kali lebih cepat daripada yang ini.
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;
}
Ini adalah c # karena itulah yang saya miliki, tetapi perbedaan dari c harus kecil.
(a >= sub)
dihitung sebagai pengurangan?
Ini sangat mudah.
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;
(Tentu saja saya telah menghapus beberapa program demi singkatnya.) Jika programmer bosan mengetik semua ini, saya yakin dia bisa menulis program terpisah untuk membuatnya untuknya. Saya kebetulan mengetahui operator tertentu /
,, yang akan sangat menyederhanakan pekerjaannya.
Dictionary<number, number>
alih - alih berulang if
sehingga Anda dapat memiliki O(1)
kompleksitas waktu!
Menggunakan penghitung adalah solusi dasar:
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
}
}
Juga mudah untuk melakukan fungsi modulus, periksa komentar.
Ini adalah algoritma pembagian klasik di basis 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);
}
Tulis program dalam Pascal dan gunakan DIV
operator.
Karena pertanyaan ini ditandai c, Anda mungkin dapat menulis fungsi dalam Pascal dan memanggilnya dari program C Anda; metode untuk melakukannya adalah spesifik sistem.
Tapi ini adalah contoh yang berfungsi pada sistem Ubuntu saya dengan fp-compiler
paket Free Pascal diinstal. (Saya melakukan ini karena sikap keras kepala yang salah tempat; saya tidak mengklaim bahwa ini berguna.)
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;
}
Untuk membangun:
fpc divide_by_3.pas && gcc divide_by_3.o main.c -o main
Eksekusi sampel:
$ ./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
dan INC
mereka tidak memiliki opcode yang sama.
Tidak memeriksa ulang apakah jawaban ini sudah dipublikasikan. Jika program perlu diperluas ke angka mengambang, angka tersebut dapat dikalikan dengan 10 * jumlah presisi yang diperlukan dan kemudian kode berikut dapat diterapkan kembali.
#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;
}
Ini harus bekerja untuk semua pembagi, tidak hanya tiga. Saat ini hanya untuk yang tidak ditandatangani, tetapi memperpanjangnya untuk ditandatangani seharusnya tidak terlalu sulit.
#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;
}
Apakah curang menggunakan /
operator "di belakang layar" dengan menggunakan eval
dan merangkai tali?
Misalnya, dalam Javacript, Anda bisa melakukannya
function div3 (n) {
var div = String.fromCharCode(47);
return eval([n, div, 3].join(""));
}
Menggunakan BC Math dalam PHP :
<?php
$a = 12345;
$b = bcdiv($a, 3);
?>
MySQL (ini adalah wawancara dari Oracle)
> SELECT 12345 DIV 3;
Pascal :
a:= 12345;
b:= a div 3;
bahasa assembly x86-64:
mov r8, 3
xor rdx, rdx
mov rax, 12345
idiv r8
Pertama yang saya pikirkan.
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: Maaf, saya tidak melihat tag C
. Tetapi Anda dapat menggunakan gagasan tentang pemformatan string, saya kira ...
Script berikut menghasilkan program C yang memecahkan masalah tanpa menggunakan operator * / + - %
:
#!/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));
}
''')
Menggunakan kalkulator angka Magic Hack Delight
int divideByThree(int num)
{
return (fma(num, 1431655766, 0) >> 32);
}
Di mana fma adalah fungsi perpustakaan standar yang didefinisikan dalam math.h
header.
-
maupun *
Operator?
Bagaimana dengan pendekatan ini (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;
}
Saya pikir jawaban yang tepat adalah:
Mengapa saya tidak menggunakan operator dasar untuk melakukan operasi dasar?
Solusi menggunakan fungsi perpustakaan fma () , bekerja untuk semua angka 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);
}
Gunakan cblas , termasuk sebagai bagian dari kerangka kerja Mempercepat 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
Pertama:
x/3 = (x/4) / (1-1/4)
Kemudian cari tahu bagaimana menyelesaikan 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))
dengan 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)
}
Meskipun menggunakan +
, tetapi seseorang sudah mengimplementasikan add by bitwise op.