*, /, +, -,% operatörlerini kullanmadan bir sayıyı 3'e bölün


685

Nasıl kullanmadan 3 bir numara bölmek istiyorum *, /, +, -, %, operatörler?

Numara imzalanmış veya imzalanmamış olabilir.


13
@AlexandreC. - bu teknikler ek (+) kullanıyorsa.
balta - SOverflow ile yapılır

19
Bu kehanetti, bu yüzden hangi kehanetin parçalarını kullanmanıza izin verildi?
Hogan

8
Tanımlanan kopya bir kopya değil. Bu sorunun bu işlemlerle ilgili bir çözümü kısıtlamadığı için, burada birkaç cevabın ne bit kaydırma ne de ekleme kullandığını unutmayın.
Michael Burr

66
... ve PL / SQL böyle doğuyor.
Sedat Kapanoglu

22
Bu soru SO'ya offtopiktir. Bu kodgolf.stackexchange.com'a
Kromster

Yanıtlar:


548

Bu, istenen işlemi gerçekleştiren basit bir işlevdir . Ancak +işleç gerektirir , bu yüzden tek yapmanız gereken değerleri bit işleçleriyle eklemektir:

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

Jim'in yorumladığı gibi, çünkü:

  • n = 4 * a + b
  • n / 3 = a + (a + b) / 3
  • Yani sum += a, n = a + bve tekrar

  • Ne zaman a == 0 (n < 4), sum += floor(n / 3);yani 1,if n == 3, else 0


96
Bu muhtemelen Oracle'ın aradığı cevaptır. +, -, * ve / operatörlerinin gerçekte CPU'ya nasıl uygulandığını bildiğinizi gösterir: basit bitsel işlemler.
craig65535

21
Bu, n = 4a + b, n / 3 = a + (a + b) / 3 olduğu için çalışır, bu nedenle sum + = a, n = a + b ve yineleme. A == 0 (n <4) olduğunda, toplam + = kat (n / 3); ör. n == 3 ise 1, başka 0.
Jim Balter

7
İşte bana benzer bir çözüm sağlayan bir numara var. Ondalık olarak: 1 / 3 = 0.333333yinelenen sayılar bunu kullanarak hesaplamayı kolaylaştırır a / 3 = a/10*3 + a/100*3 + a/1000*3 + (..). İkili dosyada neredeyse aynı: 1 / 3 = 0.0101010101 (base 2)yol açar a / 3 = a/4 + a/16 + a/64 + (..). 4'e bölmek bit kaydırmanın geldiği yerdir. Num == 3 üzerinde son kontrol gerekli çünkü sadece üzerinde çalışacak tamsayılarımız var.
Yorick Sijsling

4
Tabanın 4'te daha iyi olur: a / 3 = a * 0.111111 (base 4) = a * 4^-1 + a * 4^-2 + a * 4^-3 + (..) = a >> 2 + a >> 4 + a >> 6 + (..). Taban 4 ayrıca sonunda sadece 3'ün neden yuvarlanırken 1 ve 2'nin yuvarlanabileceğini açıklar.
Yorick Sijsling

2
@ while1: bitsel VE işlem. Ayrıca, iyi bilinen bir gerçektir için olmasıdır n == 2^k: Aşağıdaki doğrudur x % n == x & (n-1), bu yüzden burada num & 3gerçekleştirmek için kullanılır num % 4iken %izin verilmez.
aplavin

436

İdiyotik koşullar aptalca bir çözüm gerektirir:

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

Ondalık kısmı tabi de, sadece beyan resultolarak doubleve buna sonucunu ekleyin fmod(number,divisor).

Nasıl çalıştığının açıklaması

  1. fwriteyazıyornumber bayt (sayısı, örneğin yukarıda 123456 olmak üzere).
  2. rewind dosya işaretçisini dosyanın önüne sıfırlar.
  3. freaddosyadan en fazla sayıda number"kayıt" okur divisorve okuduğu öğelerin sayısını döndürür.

30 bayt yazarsanız ve dosyayı 3 birim halinde tekrar okursanız, 10 "birim" elde edersiniz. 30/3 = 10


13
@earlNameless: İçlerinde ne kullandıklarını bilmiyorsunuz, "uygulama tanımlı" kara kutudalar. Hiçbir şey onları sadece bitsel işleçleri kullanmak için durduramaz; neyse, onlar benim kod etki alanı dışında, bu yüzden bu benim sorunum değil. :)
Matteo Italia

8
@IvoFlipse temizleyebilirim, büyük bir şey alıyorsunuz ve üç kat çok küçük bir şeye itiyorsunuz ve sonra ne kadar takıldığını görüyorsunuz.
Pureferret

27
şirketimizdeki en iyi C programcısından (ve en sosyal açıdan garip) kodu açıklamasını istedi. yaptıktan sonra oldukça dahice olduğunu söyledim. 'Bu delil bir çözüm değil' dedi ve masasından ayrılmamı istedi
cvursache

6
@cvursache Sanırım asıl soru sorunun beynin ölü olması, beyin ölü cevabına izin verilmesi. "Şirketinizdeki" en iyi C programcısı "kolayca" bu
delil

17
@JeremyP: kesinlikle. Demek istediğim, eğer gerçek hayatta aritmetik desteği olmayan bir derleyici verilirse , mantıklı olan tek şey daha iyi bir derleyici istemek olacaktır , çünkü bu koşullarda çalışmak mantıklı değildir. Görüşmeci bölünmenin bitsel operasyonlarla nasıl uygulanacağına dair bilgimi kontrol etmek isterse, basit olabilir ve teorik bir soru olarak sorabilir; bu tür "hile egzersizleri" sadece böyle cevaplar için çığlık atıyor.
Matteo Italia

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

2
Bu, düzgün şekilde yuvarlanırsa ve sayı çok büyük değilse gerçekten işe yarayabilir.
Mysticial

252
Geliştirilmiş versiyon: log (pow (exp (sayı), sin (atan2 (1, sqrt (8)))))
Alan Curry

@ bitmask, matematik fonksiyonları genellikle doğrudan asm içinde uygulanır.
SingerOfTheFall

7
Sadece js konsoluma yazdım, 709'dan daha yüksek bir sayı ile çalışmıyor (sadece benim sistemim olabilir) Math.log(Math.pow(Math.exp(709),0.33333333333333333333))veMath.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

(Platforma bağlı) satır içi montajı kullanabilirsiniz, örneğin, x86 için: (ayrıca negatif sayılar için de çalışır)

#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, cevabın C ile yazılamayacağı varsayımı üzerine yorumunuz başarısız değil mi? Sonuçta soru "C" olarak etiketlenir.
Seth Carnegie

1
@SethCarnegie Cevap C'de yazılmamış benim açımdan. x86 birleştirici standardın bir parçası değildir.
JeremyP

1
@JeremyP bu doğru, ama asmdirektif. Ve C derleyicilerinin satır içi montajcıları olan tek kişi olmadığını ekleyeceğim, Delphi'de de var.
Seth Carnegie

7
@SethCarnegie asmYönerge yalnızca Ek J - ortak uzantılar altındaki C99 standardında belirtilmiştir.
JeremyP

2
Arm-eabi-gcc'de başarısız.
Damian Yerrick

106

Temel 3 dizeye dönüştürmek için itoa kullanın . Son triti bırakın ve tabana 10 dönün.

// 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 Aslında bunun itoakeyfi bir taban kullanabileceğini bilmiyordum . Kullanarak tam bir çalışma uygulaması itoayaparsanız oyları kaldırırım.
Mysticial

2
Uygulama şunları içerecek /ve %... :-)
R .. GitHub BUZA YARDIMCI DURDUR

2
@R .. printfOndalık sonucunuzu görüntülemek için uygulanması da öyle .
Damian Yerrick

57

(not: daha iyi bir sürüm için aşağıdaki Düzen 2'ye bakın!)

Bu, göründüğü kadar zor değil, çünkü "[..] +[..] operatörlerini kullanmadan" dediniz . +Karakterin birlikte kullanılmasını yasaklamak istiyorsanız aşağıya bakın .

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

Sonra sadece söylemek div_by(100,3)bölünmeden 100tarafından 3.


Düzenleme : ++Operatöre devam edebilir ve değiştirebilirsiniz :

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

Düzenleme 2: içeren herhangi operatörü kullanmadan Biraz daha hızlı versiyonu +, -, *, /, % karakterleri .

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

addİşlevin ilk bağımsız değişkenini kullanırız, çünkü *sözdiziminin type[]özdeş olduğu işlev parametre listeleri hariç , karakteri kullanmadan işaretçi türlerini gösteremeyiz type* const.

FWIW, AndreyT0x55555556 tarafından önerilen hileyi kullanmak için benzer bir hile kullanarak kolayca bir çarpma işlevi uygulayabilirsiniz :

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

5
Oracle'dan bahsedilse bile, soru SQL değil c olarak etiketlenir .
bitmask

3
Bu gerçekten SQL gibi görünmüyor!
moooeeeep

64
Kullanabiliyorsanız ++: Neden sadece kullanmıyorsunuz /=?
qwertz

5
@bitmask: ++aynı zamanda bir kısayoldur: İçin num = num + 1.
qwertz

4
@bitmask Evet, ama +=sonunda bir kısayol num = num + 1.
qwertz

44

Setun bilgisayarında kolayca mümkündür .

Bir tamsayıyı 3'e bölmek için sağa 1 yer kaydırın .

Böyle bir platforma uygun bir C derleyicisi uygulamak kesinlikle mümkün olup olmadığından emin değilim. "En az 8 bit" i "-128 ile +127 arasında en az tamsayı tutabilen" olarak yorumlamak gibi kuralları biraz uzatmamız gerekebilir.


8
Sorun, C'de "1 yer sağa kaydırma" operatörünüz olmamasıdır. >>İşleç, "2 ^ n'ye bölünme" operatörüdür, yani makine temsili değil aritmetik olarak belirtilir.
R .. GitHub BUZA YARDIMCI DURDUR

Setun bilgisayarı kelimenin hiçbir anlamında ikili değildir, bu nedenle komut kümesi kesinlikle farklı olmalıdır. Ancak, o bilgisayarın çalışmasını hiç bilmiyorum, bu yüzden yanıtın gerçekten doğru olup olmadığını doğrulayamıyorum - ama en azından mantıklı - ve son derece orijinal. +1
virolino

32

Oracle'dan beri, önceden hesaplanmış cevapların bir arama tablosuna ne dersiniz? :-D


32

İşte benim çözümüm:

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

İlk olarak,

1/3 = 1/4 + 1/16 + 1/64 + ...

Şimdi, gerisi basit!

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

Şimdi tek yapmamız gereken bu! Hata! Yine de ekleyemeyiz, bunun yerine bit bilge operatörleri kullanarak bir ekleme işlevi yazmamız gerekecek! Bit bilge operatörlere aşina iseniz, çözümüm oldukça basit görünmelidir ... ancak sadece olmamanız durumunda, sonunda bir örnek üzerinde duracağım.

Dikkat edilmesi gereken başka bir şey, önce 30'a sola kaydırmam! Bu, kesirlerin yuvarlanmadığından emin olmak içindir.

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!

Çocukken öğrendiğiniz bir ek taşıma!

111
 1011
+0110
-----
10001

Denklemin tüm terimlerini ekleyemediğimiz için bu uygulama başarısız oldu :

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

div_by_3(a)= X sonucunun yeniden alındığını varsayalım x <= floor(f(a, i)) < a / 3. Ne zaman a = 3k, yanlış cevap alırız.


2
3 girişi için çalışıyor mu? 1/4, 1/16, ... hepsi 3 için 0 döndürür, bu yüzden 0'a eşit olur, ancak 3/3 = 1.
balta - SOverflow

1
Mantık iyidir ama uygulama sorunludur. Seri yaklaşımı n/3her zamankinden daha azdır n/3; bu n=3k, sonuç k-1yerine herhangi bir sonuç için olacağı anlamına gelir k.
Xyand

@Albert, Bu, birkaç varyasyonla denediğim ilk yaklaşımdı, ancak hepsi ya 3'e eşit olarak bölünebilen ya da 2'ye eşit olarak bölünebilen belirli sayılarda başarısız oldu (varyasyona bağlı olarak). Bu yüzden daha basit bir şey denedim. İşe yarayan bu yaklaşımın bir uygulamasını görmek, nerede vidalandığımı görmek istiyorum.
balta - SOverflow ile yapılır

@hatchet, Soru kapalı, bu yüzden yeni bir cevap gönderemiyorum ama fikir ikili div uygulamaktır. Aramak kolay olmalı.
Xyand


25

32 bitlik bir sayıyı 3'e bölmek için, sayı ile çarpılabilir 0x55555556ve sonra 64 bitlik sonucun üst 32 bitini alabilir.

Şimdi tek yapmanız gereken bit işlemleri ve vardiyaları kullanarak çarpmayı uygulamak ...


1
Bu yavaş bölümler üzerinde çalışmak için ortak bir derleyici hilesi. Ancak 0x55555556 / 2 ** 32 tam olarak 1/3 olmadığından, muhtemelen bazı düzeltmeler yapmanız gerekir.
CodesInChaos

multiply it. Bu yasak *operatörü kullanmak anlamına gelmez mi ?
luiscubal

8
@luiscubal: Hayır, olmayacak. Bu yüzden dedim ki: "Artık geriye kalan tek şey bit işlemlerini ve vardiyaları kullanarak çarpmayı uygulamak "
AnT

18

Yine başka bir çözüm. Bu, sabit kodlanmış bir istisna olarak ele alınması gereken bir int değerinin min değeri hariç tüm girişleri (negatif girişler dahil) ele almalıdır. Bu temelde çıkarma yoluyla bölme yapar, ancak sadece bit işleçleri (vardiya, xor ve ve tamamlayıcı) kullanır. Daha yüksek hız için 3 * çıkarır (2'nin azalan gücü). C # 'da, milisaniye başına bu DivideBy3 çağrılarının yaklaşık 444'ünü (1.000.000 bölme için 2.2 saniye) yürütür, bu yüzden korkunç derecede yavaş değildir, ancak basit bir x / 3 kadar hızlı bir yerde yoktur. Karşılaştırıldığında, Coodey'in güzel çözümü bundan 5 kat daha hızlıdır.

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

Bu c # çünkü ben kullanışlı vardı, ama c farklılıkları küçük olmalıdır.


Sadece bir kez sub çıkartmaya çalışmanız gerekir, çünkü eğer onu iki kez çıkarırsanız, o zaman iki kat daha büyük olduğunda önceki yinelemeyi çıkarabilirsiniz.
Neil

(a >= sub)Çıkarma sayılır mı ?
Neil

@Neil, bence haklı olabilirsin. İç süre, döngünün ikinci yinelemesinden gereksiz bir karşılaştırma kaydedildiğinde basit bir ile değiştirilebilir. > = Çıkarma ile ilgili ... Umarım değil, çünkü bu bunu oldukça zorlaştırır! Ne demek istediğini anlıyorum, ama sanırım> = 'nin çıkarma olarak sayılmadığı tarafa yaslanacağım.
balta - SOverflow ile yapılır

@Neil, zamanı yarıya indiren bu değişikliği yaptım (gereksiz Negatifleri de kurtardı).
balta - SOverflow ile yapılır

16

Gerçekten çok kolay.

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;

(Elbette kısalık uğruna programın bir kısmını atladım.) Programcı hepsini yazmaktan yorulursa, onu kendisi için oluşturmak için ayrı bir program yazabileceğinden eminim. Belirli bir operatörün farkındayım /, bu da işini son derece basitleştirecek.


8
Zaman karmaşıklığı elde etmek için Dictionary<number, number>tekrarlanan ififadeler yerine kullanabilirsiniz O(1)!
Peter Olson

@EnesUnal No, sayı arttıkça zaman doğrusal olarak artar, çünkü ifadeler gittikçe daha fazla hareket etmelidir.
Peter Olson

Teorik olarak
artmıyor

@PeterOlson, EresUnal Bir anahtar ifadesi kullansaydım, O (1) :-) olurdu
thedayturns

Veya bir dizi oluşturabilir ve dinamik programlama kullanabilirsiniz. x / 3 = y ise, y << 2 + y = x - x% 3.
lsiebert

14

Sayaçları kullanmak temel bir çözümdür:

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

Ayrıca bir modül işlevi gerçekleştirmek kolaydır, yorumları kontrol edin.


@Enes Ünal: küçük sayılar için değil :) Bu algoritma çok basit.
GJ.

Her ilkel zayıflık zayıflık içerir :)
Ağustos'ta

11

Bu, taban 2'deki klasik bölüm algoritmasıdır:

#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

Programı Pascal'a yazın ve DIVoperatörü kullanın .

Soru etiketlendiğinden , Pascal'da bir işlev yazabilir ve C programınızdan çağırabilirsiniz; bunu yapmanın yöntemi sisteme özgüdür.

Ancak, Free Pascal fp-compilerpaketi kurulu olarak Ubuntu sistemimde çalışan bir örnek . (Bunu yanlış yerleştirilmiş inatçılıktan yapıyorum; bunun yararlı olduğunu iddia etmiyorum.)

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

İnşa etmek:

fpc divide_by_3.pas && gcc divide_by_3.o main.c -o main

Örnek yürütme:

$ ./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
++ ve - operatörleri + ve - operatörlerinden farklıdır! Montaj dilinde iki talimat vardır ADDve INCbunların aynı opcode sahip olmamaları.
Amir Saniyan

7

Bu cevabın zaten yayınlanıp yayınlanmadığını kontrol etmedi. Programın kayan sayılara genişletilmesi gerekiyorsa, sayılar gereken hassasiyet sayısı 10 * ile çarpılabilir ve ardından aşağıdaki kod tekrar uygulanabilir.

#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

Bu sadece üç değil, herhangi bir bölen için işe yarayacaktır. Şu anda sadece imzasız, ancak imzalı olarak genişletmek o kadar zor olmamalı.

#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

/"String'in arkasında" operatörünü evalve string bitiştirmeyi kullanarak kullanmak hile olur mu?

Örneğin, Javacript'te şunları yapabilirsiniz:

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

7

Kullanılması M.Ö. Matematik içinde PHP :

<?php
    $a = 12345;
    $b = bcdiv($a, 3);   
?>

MySQL (Oracle'dan bir röportaj)

> SELECT 12345 DIV 3;

Pascal :

a:= 12345;
b:= a div 3;

x86-64 montaj dili:

mov  r8, 3
xor  rdx, rdx   
mov  rax, 12345
idiv r8

1
Harika hikaye, bu C olarak etiketlendi ve ilk günden beri öyle. Buna ek olarak, sorunun noktasını tamamen kavrayamazsınız.
Lundin

6

Önce ben geldim.

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: Üzgünüm, etiketi fark etmedim C. Ama dize biçimlendirme fikrini kullanabilirsiniz sanırım ...


5

Aşağıdaki komut dosyası, işleçleri kullanmadan sorunu çözen bir C programı oluşturur * / + - %:

#!/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

Bu yaklaşıma ne dersiniz (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;
    }

Bu C olarak etiketlendi ve ilk günden beri böyle.
Lundin

4

Bence doğru cevap:

Temel bir işlemi yapmak için neden temel bir operatör kullanmıyorum?


Çünkü bilmek istedikleri, işlemcinin dahili olarak nasıl çalıştığını biliyorsanız ... bir matematik operatörü kullanmak, sonunda yukarıdaki cevaba çok benzer bir işlem gerçekleştirecektir.
RaptorX

Veya işe yaramaz bir sorunu fark edip edemeyeceğinizi bilmek isterler.
Gregoire

1
@Gregoire Katılıyorum, aboloultley böyle bir uygulama yapmaya gerek yok, Ticari yaşamda Bit (Orcale) yararsız gereksinimleri yerine getirmekten kaçınmak için gerekli: Doğru cevap: "Bu hiç mantıklı değil, neden para kaybetmek bunun için? ")
AlexWien

4

Fma () kitaplık işlevini kullanan çözüm , herhangi bir pozitif sayı için çalışır:

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

Başka bir cevabımı gör .


Kütüphanenin güzel kullanımı. Neden doğrudan sonuç ++ kullanmadınız?
Green goblin

insanlar + kullanıldığını söyleyebilir.
Sekiz

3

OS X'in Accelerate çerçevesinin bir parçası olarak dahil edilen cblas'ı kullanın .

[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

Bu sadece bir uygulama detayıydı, bu yüzden 0.333333 yerine 3.0 / 1.0 olarak yazabilirdim, ancak kurallara göre oynamalıyım. Sabit!
wjl

Başlangıçta testimde 3.0 / 1.0 olarak yaptım. Daha yüksek hassasiyetli bir sayı kullanarak, makul doğrulukta bir sonuç almalıdırlar. gist.github.com/3401496
wjl

3

Genel olarak, bunun çözümü şöyle olur:

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


3

İlk:

x/3 = (x/4) / (1-1/4)

Sonra x / (1 - y) 'nin nasıl çözüleceğini öğrenin:

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

y = 1/4 ile:

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

Her ne kadar kullansa da +, birileri zaten uygular bitwise op tarafından ekleyin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.