Membagi angka dengan 3 tanpa menggunakan operator *, /, +, -,%


684

Bagaimana Anda membagi nomor dengan 3 tanpa menggunakan *, /, +, -, %, operator?

Nomor tersebut dapat ditandatangani atau tidak ditandatangani.


13
@AlexandreC. - Teknik-teknik tersebut menggunakan penjumlahan (+).
kapak - dilakukan dengan SOverflow

19
Ini oracle jadi bagian oracle apa yang diizinkan untuk Anda gunakan?
Hogan

8
Duplikat yang diidentifikasi bukan duplikat. Perhatikan bahwa beberapa jawaban di sini tidak menggunakan sedikit pun pergeseran atau penambahan karena pertanyaan ini tidak membatasi solusi untuk operasi tersebut.
Michael Burr

66
... dan di sinilah lahirnya PL / SQL.
Sedat Kapanoglu

22
Pertanyaan ini tidak aktif untuk SO. Itu milik codegolf.stackexchange.com
Kromster

Jawaban:


548

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


96
Ini mungkin jawaban yang dicari Oracle. Ini menunjukkan Anda tahu bagaimana +, -, * dan / operator benar-benar diimplementasikan pada CPU: operasi bitwise sederhana.
craig65535

21
Ini bekerja karena n = 4a + b, n / 3 = a + (a + b) / 3, jadi jumlah + = a, n = a + b, dan iterate. Ketika a == 0 (n <4), jumlah + = lantai (n / 3); yaitu, 1 jika n == 3, kalau tidak 0.
Jim Balter

7
Inilah trik yang saya temukan yang memberi saya solusi serupa. Dalam desimal 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.
Yorick Sijsling

4
Dalam basis 4 itu akan lebih baik: 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.
Yorick Sijsling

2
@ while1: bitwise DAN operasi. Juga, fakta yang terkenal adalah bahwa untuk n == 2^kyang berikut ini benar:, x % n == x & (n-1)jadi di sini num & 3digunakan untuk melakukan num % 4sementara %tidak diizinkan.
aplavin

436

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 resultsebagai doubledan tambahkan hasilnya fmod(number,divisor).

Penjelasan tentang cara kerjanya

  1. The fwritemenulis numberbyte (jumlah menjadi 123.456 dalam contoh di atas).
  2. rewind mengatur ulang penunjuk file ke bagian depan file.
  3. freadmembaca maksimum number"catatan" yang divisorpanjangnya 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


13
@earlNameless: Anda tidak tahu apa yang mereka gunakan di dalam, mereka berada di kotak hitam "implementasi yang ditentukan". Tidak ada yang menghentikan mereka untuk hanya menggunakan operator bitwise; Lagi pula, mereka berada di luar domain kode saya, jadi itu bukan masalah saya. :)
Matteo Italia

8
@IvoFlipse dari saya dapat membersihkan, Anda mendapatkan sesuatu yang besar dan mendorongnya menjadi sesuatu yang tiga kali terlalu kecil, dan kemudian melihat berapa banyak yang pas. Itu sekitar sepertiga.
Pureferret

27
tanya programmer C terbaik (dan paling canggung secara sosial) di perusahaan kami untuk menjelaskan kode. setelah itu, saya katakan itu cukup cerdik. Dia mengatakan 'minuman keras ini bukan solusi' dan meminta saya untuk meninggalkan mejanya
cvursache

6
@cvursache Saya pikir intinya adalah bahwa pertanyaannya adalah mati otak, bahwa jawaban mati otak diperbolehkan. "Pemrogram C terbaik" di perusahaan Anda "dapat dengan mudah mengatakan" bahwa kecerobohan bukan pertanyaan (yang pantas) "
JeremyP

17
@ JeremyP: persis. Maksud saya adalah jika dalam kehidupan nyata saya diberi kompiler tanpa dukungan untuk aritmatika , satu-satunya hal yang masuk akal adalah meminta kompiler yang lebih baik , karena bekerja dalam kondisi itu tidak masuk akal. Jika pewawancara ingin memeriksa pengetahuan saya tentang bagaimana menerapkan divisi dengan operasi bitwise, ia bisa langsung dan menanyakannya sebagai pertanyaan teoretis; "latihan trik" semacam ini hanya berteriak untuk jawaban seperti ini.
Matteo Italia

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

2
Ini mungkin benar-benar berfungsi jika dibulatkan dengan benar dan jika jumlahnya tidak terlalu besar.
Mysticial

252
Versi yang ditingkatkan: log (pow (exp (number), sin (atan2 (1, sqrt (8)))))
Alan Curry

@ Bitmask, fungsi matematika biasanya diimplementasikan langsung dalam asm.
SingerOfTheFall

7
saya hanya mengetiknya di konsol js saya, tidak bekerja dengan angka lebih tinggi dari 709 (mungkin hanya sistem saya) Math.log(Math.pow(Math.exp(709),0.33333333333333333333))danMath.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

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

2
@ JeremyP tidakkah komentar Anda gagal dengan asumsi bahwa jawabannya tidak dapat ditulis dalam C? Bagaimanapun juga, pertanyaan itu ditandai "C".
Seth Carnegie

1
@SethCarnegie Jawabannya tidak ditulis dalam C adalah poin saya. assembler x86 bukan bagian dari standar.
JeremyP

1
@ JeremyP itu benar, tetapi asmarahannya. Dan saya akan menambahkan bahwa kompiler C bukan satu-satunya yang memiliki inline assembler, Delphi juga memilikinya.
Seth Carnegie

7
@SethCarnegie asmArahan hanya disebutkan dalam standar C99 di bawah Lampiran J - ekstensi umum.
JeremyP

2
Gagal pada arm-eabi-gcc.
Damian Yerrick

106

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
}

4
@ cshemby Saya sebenarnya tidak tahu yang itoabisa menggunakan basis sewenang-wenang. Jika Anda melakukan implementasi kerja yang lengkap menggunakan itoasaya akan mengungguli.
Mysticial

2
Implementasi akan berisi /dan %... :-)
R .. GitHub BERHENTI MEMBANTU ICE

2
@ R .. Begitu juga implementasi printfuntuk menampilkan hasil desimal Anda.
Damian Yerrick

57

(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 100dengan 3.


Sunting : Anda dapat melanjutkan dan mengganti ++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)
}

Edit 2: Sedikit lebih cepat versi tanpa menggunakan operator manapun yang berisi +, -, *, /, % 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 addfungsi 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 0x55555556trik yang diusulkan oleh AndreyT :

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

5
Pertanyaannya ditandai c , bukan SQL, meskipun Oracle disebutkan.
bitmask

3
Ini memang tidak terlihat seperti SQL!
moooeeeep

64
Jika Anda dapat menggunakan ++: Mengapa Anda tidak menggunakan saja /=?
qwertz

5
@ bitmask: ++juga merupakan jalan pintas: Untuk num = num + 1.
qwertz

4
@ Bitmask Ya, tapi +=akhirnya jalan pintas untuk num = num + 1.
qwertz

44

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


8
Masalahnya adalah Anda tidak memiliki operator "shift right by 1 place" di C. >>Operator adalah operator "division by 2 ^ n", artinya ditentukan dalam hal aritmatika, bukan representasi mesin.
R .. GitHub BERHENTI MEMBANTU ICE

Komputer Setun bukan biner dalam arti kata, jadi set instruksi pasti berbeda. Namun, saya sama sekali tidak akrab dengan pengoperasian komputer itu, jadi saya tidak dapat mengkonfirmasi apakah responsnya benar - tetapi setidaknya masuk akal - dan sangat asli. +1
virolino

32

Karena ini dari Oracle, bagaimana dengan tabel pencarian jawaban yang dihitung sebelumnya. :-D


32

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.


2
apakah itu berfungsi untuk input 3? 1/4, 1/16, ... semua mengembalikan 0 untuk 3, jadi akan berjumlah 0, tetapi 3/3 = 1.
kapak - dilakukan dengan SOverflow

1
Logikanya bagus tetapi implementasinya bermasalah. Serangkaian aproksimasi n/3selalu kurang dari n/3yang berarti bahwa untuk setiap n=3khasil akan menjadi k-1bukan k.
Xyand

@Albert, Ini adalah pendekatan pertama yang saya coba, dengan beberapa variasi, tetapi mereka semua gagal pada angka-angka tertentu yang dapat dibagi dengan 3 atau secara merata dibagi dengan 2 (tergantung pada variasi). Jadi saya mencoba sesuatu yang lebih mudah. Saya ingin melihat implementasi dari pendekatan ini yang berfungsi, untuk melihat di mana saya mengacau.
kapak - dilakukan dengan SOverflow

@hatchet, Pertanyaannya sudah ditutup jadi saya tidak bisa mengirim jawaban baru tetapi idenya adalah untuk mengimplementasikan binary div. Saya harus mudah mencarinya.
Xyand


25

Untuk membagi angka 32-bit dengan 3 orang dapat mengalikannya dengan 0x55555556dan kemudian mengambil 32 bit atas dari hasil 64 bit.

Sekarang yang harus dilakukan adalah mengimplementasikan perkalian menggunakan operasi bit dan pergeseran ...


1
Ini adalah trik kompiler umum untuk mengatasi divisi yang lambat. Tetapi Anda mungkin perlu melakukan beberapa perbaikan, karena 0x55555556 / 2 ** 32 tidak persis 1/3.
CodesInChaos

multiply it. Bukankah itu menyiratkan menggunakan *operator terlarang ?
luiscubal

8
@luiscubal: Tidak, tidak akan. Inilah sebabnya saya mengatakan: "Sekarang yang tersisa untuk dilakukan adalah menerapkan perkalian menggunakan operasi bit dan shift "
AnT

18

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.


Anda hanya perlu mencoba untuk mengurangi sub sekali, karena jika Anda bisa mengurangkannya dua kali maka Anda bisa menguranginya iterasi sebelumnya ketika itu dua kali lebih besar dari sekarang.
Neil

Apakah (a >= sub)dihitung sebagai pengurangan?
Neil

@Neil, saya pikir Anda mungkin benar. Sementara bagian dalam dapat diganti dengan sederhana jika, menyimpan perbandingan yang tidak dibutuhkan dari iterasi kedua loop. Mengenai> = menjadi pengurangan ... Saya harap tidak, karena itu akan membuat melakukan ini cukup sulit! Saya mengerti maksud Anda, tetapi saya pikir saya akan bersandar pada sisi yang mengatakan> = tidak dihitung sebagai pengurangan.
kapak - dilakukan dengan SOverflow

@ Neil, saya membuat perubahan itu, yang memotong waktu menjadi dua (juga menghemat Negate yang tidak dibutuhkan).
kapak - dilakukan dengan SOverflow

16

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.


8
Anda bisa menggunakan pernyataan Dictionary<number, number>alih - alih berulang ifsehingga Anda dapat memiliki O(1)kompleksitas waktu!
Peter Olson

@EnalUnal Tidak, waktu meningkat secara linear seiring meningkatnya angka, karena harus melintasi lebih banyak jika pernyataan.
Peter Olson

Secara teoritis itu tidak meningkat :)
totten

@PeterOlson, EresUnal jika saya menggunakan pernyataan switch, itu akan menjadi O (1) :-)
thedayturns

Atau Anda bisa menghasilkan array, dan menggunakan pemrograman dinamis. jika x / 3 = y, maka y << 2 + y = x - x% 3.
lsiebert

14

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.


@ Enes Unal: bukan untuk angka kecil :) Algoritma ini sangat mendasar.
GJ.

Setiap keprimitifan mencakup kelemahan :)
dimulai

11

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

10

Tulis program dalam Pascal dan gunakan DIVoperator.

Karena pertanyaan ini ditandai , 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-compilerpaket 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

8
int div3(int x)
{
  int reminder = abs(x);
  int result = 0;
  while(reminder >= 3)
  {
     result++;

     reminder--;
     reminder--;
     reminder--;
  }
  return result;
}

3
++ dan - operaors berbeda dari + dan - operaors! Dalam bahasa assembly ada dua instruksi ADDdan INCmereka tidak memiliki opcode yang sama.
Amir Saniyan

7

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

7

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

7

Apakah curang menggunakan /operator "di belakang layar" dengan menggunakan evaldan merangkai tali?

Misalnya, dalam Javacript, Anda bisa melakukannya

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

7

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

1
Keren cerita, ini ditandai C dan sudah sejak hari pertama. Selain itu, Anda benar-benar gagal memahami maksud pertanyaan.
Lundin

6

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


5

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


4

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

Ini ditandai C dan sudah sejak hari pertama.
Lundin

4

Saya pikir jawaban yang tepat adalah:

Mengapa saya tidak menggunakan operator dasar untuk melakukan operasi dasar?


Karena yang ingin mereka ketahui adalah jika Anda tahu cara kerja prosesor secara internal ... menggunakan operator matematika pada akhirnya akan melakukan operasi yang sangat mirip dengan jawaban di atas.
RaptorX

Atau mereka ingin tahu apakah Anda bisa mengenali masalah yang tidak berguna.
Gregoire

1
@ Gregoire Saya setuju, Ada aboloultley tidak perlu melakukan implementasi seperti itu, Bit dalam kehidupan komersial (Orcale) tidak perlu untuk menghindari memenuhi persyaratan yang tidak berguna: Jawaban yang benar adalah: "Ini tidak masuk akal sama sekali, mengapa kehilangan uang untuk itu? ")
AlexWien

4

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

Lihat jawaban saya yang lain .


Penggunaan perpustakaan yang bagus. Mengapa Anda tidak langsung menggunakan hasil ++?
Green goblin

maka orang mungkin mengatakan bahwa + telah digunakan.
Delapan

3

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

Yah, itu hanya detail implementasi sehingga saya bisa mengetiknya sebagai 3.0 / 1.0 bukannya 0.333333, tapi saya harus bermain sesuai aturan. Tetap!
wjl

Saya awalnya memilikinya sebagai 3.0 / 1.0, yang tidak dalam pengujian saya. Dengan menggunakan angka presisi yang lebih tinggi, mereka harus mendapatkan hasil yang cukup akurat. gist.github.com/3401496
wjl

3

Secara umum, solusi untuk ini adalah:

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


3

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.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.