Chia số cho 3 mà không sử dụng toán tử *, /, +, -,%


684

Làm thế nào bạn sẽ chia một số cho 3 mà không sử dụng *, /, +, -, %, nhà khai thác?

Số có thể được ký hoặc không dấu.


13
@AlexandreC. - những kỹ thuật này đang sử dụng phép cộng (+).
hatchet - được thực hiện với SOverflow

19
Đây là nhà tiên tri, vậy phần nào của nhà tiên tri bạn được phép sử dụng?
Hogan

8
Bản sao được xác định không phải là bản sao. Lưu ý rằng một số câu trả lời ở đây không sử dụng dịch chuyển hoặc bổ sung bit vì câu hỏi này không hạn chế giải pháp cho các hoạt động đó.
Michael Burr

66
... và đây là cách PL / SQL được sinh ra.
Sedat Kapanoglu

22
Câu hỏi này không chính đáng với SO. Nó thuộc về codegolf.stackexchange.com
Kromster

Câu trả lời:


548

Đây là một chức năng đơn giản thực hiện các hoạt động mong muốn. Nhưng nó đòi hỏi +toán tử, vì vậy tất cả những gì bạn còn lại phải làm là thêm các giá trị bằng toán tử 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; 
}

Như Jim nhận xét điều này hoạt động, bởi vì:

  • n = 4 * a + b
  • n / 3 = a + (a + b) / 3
  • Vì vậy sum += a, n = a + bvà lặp

  • Khi nào a == 0 (n < 4), sum += floor(n / 3);tức là 1,if n == 3, else 0


96
Đây có lẽ là câu trả lời mà Oracle đang tìm kiếm. Nó cho bạn biết cách các toán tử +, -, * và / được thực hiện trên CPU: các thao tác bitwise đơn giản.
craig65535

21
Điều này hoạt động vì n = 4a + b, n / 3 = a + (a + b) / 3, do đó tổng + = a, n = a + b và lặp lại. Khi a == 0 (n <4), tổng + = sàn (n / 3); tức là, 1 nếu n == 3, khác 0.
Jim Balter

7
Đây là một mẹo tôi tìm thấy đã cho tôi một giải pháp tương tự. Trong số thập phân : 1 / 3 = 0.333333, các số lặp lại giúp dễ dàng tính toán bằng cách sử dụng a / 3 = a/10*3 + a/100*3 + a/1000*3 + (..). Trong nhị phân, nó gần giống nhau : 1 / 3 = 0.0101010101 (base 2), dẫn đến a / 3 = a/4 + a/16 + a/64 + (..). Chia cho 4 là nơi dịch chuyển bit đến từ. Kiểm tra cuối cùng về num == 3 là cần thiết vì chúng tôi chỉ có số nguyên để làm việc.
Yorick Sijsling

4
Trong cơ sở 4, nó thậm chí còn tốt hơn : a / 3 = a * 0.111111 (base 4) = a * 4^-1 + a * 4^-2 + a * 4^-3 + (..) = a >> 2 + a >> 4 + a >> 6 + (..). Cơ sở 4 cũng giải thích tại sao chỉ có 3 được làm tròn ở cuối, trong khi 1 và 2 có thể được làm tròn xuống.
Yorick Sijsling

2
@ while1: đó là bitwise AND hoạt động. Ngoài ra, một thực tế nổi tiếng là vì n == 2^knhững điều sau đây là đúng: x % n == x & (n-1)vì vậy, ở đây num & 3được sử dụng để thực hiện num % 4trong khi %không được phép.
aplavin

436

Điều kiện ngu ngốc kêu gọi một giải pháp ngu ngốc:

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

Nếu cũng cần phần thập phân, chỉ cần khai báo resultdoublevà thêm vào phần kết quả của nó fmod(number,divisor).

Giải thích về cách thức hoạt động của nó

  1. Các byte fwriteghi number(số là 123456 trong ví dụ trên).
  2. rewind Đặt lại con trỏ tệp về phía trước của tệp.
  3. freadđọc tối đa number"bản ghi" có divisorđộ dài từ tệp và trả về số lượng phần tử mà nó đọc.

Nếu bạn viết 30 byte thì đọc lại tệp theo đơn vị 3, bạn nhận được 10 "đơn vị". 30/3 = 10


13
@earlNamless: bạn không biết những gì họ sử dụng bên trong, họ đang ở trong hộp đen của "triển khai được xác định". Không có gì ngăn cản họ chỉ sử dụng các toán tử bitwise; Dù sao, chúng nằm ngoài miền mã của tôi, vì vậy đó không phải là vấn đề của tôi. :)
Matteo Italia

8
@IvoFlipse từ tôi có thể làm sạch, bạn lấy một cái gì đó lớn và đẩy nó vào một cái gì đó quá nhỏ gấp ba lần, và sau đó xem bao nhiêu trang bị trong đó. Đó là một phần ba.
Pureferret

27
yêu cầu lập trình viên C giỏi nhất (và khó xử nhất trong xã hội) tại công ty chúng tôi để giải thích mã. Sau khi anh ấy làm, tôi nói nó khá khéo léo. Anh ấy nói 'cái quái vật này không phải là một giải pháp' và yêu cầu tôi rời khỏi bàn làm việc của anh ấy
cvursache

6
@cvursache Tôi nghĩ vấn đề là câu hỏi chết não đến mức cho phép câu trả lời chết não. "Lập trình viên C giỏi nhất" tại công ty của bạn "có thể dễ dàng nói" câu hỏi đó không phải là một câu hỏi (đúng) "
JeremyP

17
@JeremyP: chính xác. Quan điểm của tôi là nếu trong đời thực tôi được tặng một trình biên dịch mà không hỗ trợ số học thì điều hợp lý duy nhất là yêu cầu một trình biên dịch tốt hơn , bởi vì làm việc trong những điều kiện đó không có ý nghĩa gì. Nếu người phỏng vấn muốn kiểm tra kiến ​​thức của tôi về cách thực hiện phân chia với các thao tác bitwise, anh ta có thể chỉ cần đơn giản và hỏi nó như một câu hỏi lý thuyết; những loại "bài tập lừa" này chỉ cần hét lên để có câu trả lời như thế này.
Matteo Italia

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

2
Điều này thực sự có thể hoạt động nếu được làm tròn đúng và nếu số lượng không quá lớn.
Bí ẩn

252
Phiên bản cải tiến: log (pow (exp (số), sin (atan2 (1, sqrt (8)))))
Alan Curry

@bitmask, các hàm toán học thường được thực hiện trực tiếp trong asm.
Ca sĩOfTheFall

7
tôi vừa gõ nó vào bảng điều khiển js của mình, nó không hoạt động với số cao hơn 709 (có thể chỉ là hệ thống của tôi) Math.log(Math.pow(Math.exp(709),0.33333333333333333333))Math.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

Bạn có thể sử dụng lắp ráp nội tuyến (phụ thuộc nền tảng), ví dụ: cho x86: (cũng hoạt động cho các số âm)

#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 không bình luận của bạn thất bại với giả định rằng câu trả lời không thể được viết bằng C? Câu hỏi được gắn thẻ "C" sau khi tất cả.
Seth Carnegie

1
@SethCarnegie Câu trả lời không được viết bằng C là quan điểm của tôi. Trình biên dịch x86 không phải là một phần của tiêu chuẩn.
JeremyP

1
@JeremyP đó là sự thật, nhưng asmchỉ thị là vậy. Và tôi sẽ thêm rằng trình biên dịch C không phải là trình biên dịch duy nhất có trình biên dịch nội tuyến, Delphi cũng có điều đó.
Seth Carnegie

7
@SethCarnegie Lệnh asmnày chỉ được đề cập trong tiêu chuẩn C99 theo Phụ lục J - các phần mở rộng phổ biến.
JeremyP

2
Thất bại trong arm-eabi-gcc.
Damian Yerrick

106

Sử dụng itoa để chuyển đổi thành chuỗi 3 cơ sở. Thả trit cuối cùng và chuyển đổi trở lại cơ sở 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 Tôi thực sự không biết rằng itoacó thể sử dụng một cơ sở tùy ý. Nếu bạn thực hiện hoàn thành công việc bằng cách sử dụng itoatôi sẽ nâng cấp.
Bí ẩn

2
Việc triển khai sẽ chứa /%... :-)
R .. GitHub DỪNG GIÚP ICE

2
@R .. Việc thực hiện printfđể hiển thị kết quả thập phân của bạn cũng vậy.
Damian Yerrick

57

(lưu ý: xem Chỉnh sửa 2 bên dưới để biết phiên bản tốt hơn!)

Đây không phải là khó khăn như âm thanh, bởi vì bạn nói "mà không sử dụng [..] +[..] các nhà khai thác ". Xem bên dưới, nếu bạn muốn cấm sử dụng +tất cả các nhân vật cùng nhau.

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

sau đó chỉ cần nói div_by(100,3)để chia 100cho 3.


Chỉnh sửa : Bạn cũng có thể tiếp tục và thay thế ++toán tử:

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

Chỉnh sửa 2: Hơi nhanh hơn phiên bản mà không cần sử dụng bất kỳ nhà điều hành có chứa +, -, *, /, % nhân vật .

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

Chúng tôi sử dụng đối số đầu tiên của addhàm vì chúng tôi không thể biểu thị loại con trỏ mà không sử dụng *ký tự, ngoại trừ trong danh sách tham số hàm, trong đó cú pháp type[]giống hệt type* const.

FWIW, bạn có thể dễ dàng thực hiện chức năng nhân bằng một thủ thuật tương tự để sử dụng 0x55555556thủ thuật được đề xuất bởi AndreyT :

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

5
Câu hỏi được gắn thẻ c , không phải SQL, mặc dù Oracle được đề cập.
bitmask

3
Điều này thực sự không giống như SQL!
moooeeeep

64
Nếu bạn có thể sử dụng ++: Tại sao bạn không sử dụng /=?
qwertz

5
@bitmask: ++cũng là một phím tắt: Dành cho num = num + 1.
qwertz

4
@bitmask Vâng, nhưng +=cuối cùng là một phím tắt cho num = num + 1.
qwertz

44

Nó có thể dễ dàng trên máy tính Setun .

Để chia một số nguyên cho 3, dịch chuyển sang phải 1 vị trí .

Tôi không chắc chắn liệu có thể thực hiện một trình biên dịch C phù hợp trên một nền tảng như vậy hay không. Chúng ta có thể phải kéo dài các quy tắc một chút, như diễn giải "ít nhất 8 bit" là "có khả năng giữ ít nhất các số nguyên từ -128 đến +127".


8
Vấn đề là bạn không có toán tử "shift right by 1 place" trong C. >>Toán tử là toán tử "chia cho 2 ^ n", tức là nó được chỉ định dưới dạng số học, không phải đại diện cho máy.
R .. GitHub DỪNG GIÚP ICE

Máy tính Setun không phải là nhị phân theo bất kỳ nghĩa nào của từ này, vì vậy tập lệnh phải chắc chắn khác nhau. Tuy nhiên, tôi hoàn toàn không quen với hoạt động của máy tính đó, vì vậy tôi không thể xác nhận xem phản hồi có thực sự chính xác hay không - nhưng ít nhất nó có ý nghĩa - và có tính nguyên bản cao. +1
virolino

32

Vì nó là từ Oracle, làm thế nào về một bảng tra cứu các câu trả lời được tính toán trước. : -D


32

Đây là giải pháp của tôi:

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

Đầu tiên, lưu ý rằng

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

Bây giờ, phần còn lại là đơn giản!

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

Bây giờ tất cả những gì chúng ta phải làm là cộng các giá trị dịch chuyển bit này lại với nhau! Giáo sư! Mặc dù vậy, chúng tôi không thể thêm, vì vậy thay vào đó, chúng tôi sẽ phải viết một hàm thêm bằng các toán tử bit-khôn ngoan! Nếu bạn quen thuộc với các toán tử bit khôn ngoan, giải pháp của tôi sẽ trông khá đơn giản ... nhưng chỉ trong trường hợp bạn không, tôi sẽ xem qua một ví dụ ở cuối.

Một điều cần lưu ý là đầu tiên tôi thay đổi 30 tuổi! Điều này là để đảm bảo rằng các phân số không được làm tròn.

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!

Nó chỉ đơn giản là mang thêm mà bạn đã học khi còn nhỏ!

111
 1011
+0110
-----
10001

Việc triển khai này thất bại vì chúng tôi không thể thêm tất cả các điều khoản của phương trình:

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

Giả sử reslut của div_by_3(a)= x, sau đó x <= floor(f(a, i)) < a / 3. Khi nào a = 3k, chúng ta nhận được câu trả lời sai.


2
Nó hoạt động cho đầu vào của 3? 1/4, 1/16, ... tất cả trả về 0 cho 3, vì vậy sẽ tổng bằng 0, nhưng 3/3 = 1.
hatchet - được thực hiện với SOverflow

1
Logic là tốt nhưng việc thực hiện có vấn đề. Giá trị gần đúng của chuỗi n/3luôn nhỏ hơn n/3có nghĩa là với bất kỳ n=3kkết quả nào sẽ k-1thay thế k.
Xyand

@Albert, Đây là cách tiếp cận đầu tiên tôi đã thử, với một vài biến thể, nhưng tất cả chúng đều thất bại ở một số số nhất định chia hết cho 3 hoặc chia đều cho 2 (tùy thuộc vào biến thể). Vì vậy, tôi đã thử một cái gì đó đơn giản hơn. Tôi muốn thấy một triển khai của phương pháp này hoạt động, để xem nơi tôi đang làm hỏng việc.
hatchet - được thực hiện với SOverflow

@hatchet, Câu hỏi đã bị đóng nên tôi không thể đăng câu trả lời mới nhưng ý tưởng là triển khai div nhị phân. Tôi nên dễ dàng tìm kiếm nó.
Xyand


25

Để chia số 32 bit cho 3, người ta có thể nhân số đó với 0x55555556sau đó lấy 32 bit trên của kết quả 64 bit.

Bây giờ tất cả những gì còn lại phải làm là thực hiện phép nhân bằng cách sử dụng các thao tác bit và dịch chuyển ...


1
Đây là một thủ thuật biên dịch phổ biến để làm việc xung quanh các phân chia chậm. Nhưng có lẽ bạn cần thực hiện một số sửa lỗi, vì 0x55555556 / 2 ** 32 không chính xác bằng 1/3.
CodeInChaos

multiply it. Điều đó có nghĩa là sử dụng *toán tử bị cấm ?
luiscubal

8
@luiscubal: Không, nó sẽ không. Đây là lý do tại sao tôi nói: "Bây giờ tất cả những gì còn lại phải làm là thực hiện phép nhân bằng cách sử dụng các thao tác và dịch chuyển bit "
AnT

18

Một giải pháp khác. Điều này sẽ xử lý tất cả các int (bao gồm cả int âm) ngoại trừ giá trị tối thiểu của một int, cần phải được xử lý như một ngoại lệ được mã hóa cứng. Điều này về cơ bản không phân chia bằng phép trừ mà chỉ sử dụng các toán tử bit (shift, xor, & và bổ sung). Đối với tốc độ nhanh hơn, nó trừ 3 * (giảm sức mạnh 2). Trong c #, nó thực hiện khoảng 444 trong số các cuộc gọi DivideBy3 này mỗi mili giây (2,2 giây cho 1.000.000 lần chia), do đó, không chậm khủng khiếp, nhưng không nhanh bằng tốc độ x / 3 đơn giản. Để so sánh, giải pháp tốt đẹp của Coodey nhanh hơn khoảng 5 lần so với giải pháp này.

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

Đây là c # vì đó là những gì tôi có, nhưng sự khác biệt so với c chỉ là nhỏ.


Bạn chỉ cần cố gắng trừ phụ một lần, bởi vì nếu bạn có thể trừ nó hai lần thì bạn có thể trừ đi lần lặp trước đó khi nó lớn gấp đôi so với bây giờ.
Neil

(a >= sub)được tính là một phép trừ?
Neil

@Neil, tôi nghĩ bạn có thể đúng. Nội bộ trong khi có thể được thay thế bằng một đơn giản nếu, lưu một so sánh không cần thiết từ lần lặp thứ hai của vòng lặp. Về> = bị trừ ... Tôi hy vọng là không, vì điều đó sẽ làm cho việc này khá khó khăn! Tôi thấy quan điểm của bạn, nhưng tôi nghĩ rằng tôi sẽ nghiêng về phía nói rằng = = không được tính là phép trừ.
hatchet - được thực hiện với SOverflow

@Neil, tôi đã thực hiện thay đổi đó, giúp giảm thời gian xuống một nửa (cũng lưu các phủ định không cần thiết).
hatchet - được thực hiện với SOverflow

16

Nó thực sự khá dễ dàng.

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;

(Tất nhiên tôi đã bỏ qua một số chương trình vì lý do ngắn gọn.) Nếu lập trình viên cảm thấy mệt mỏi khi phải gõ tất cả, tôi chắc chắn rằng anh ấy hoặc cô ấy có thể viết một chương trình riêng để tạo ra nó cho anh ấy. Tôi tình cờ nhận ra một nhà điều hành nào đó /, điều đó sẽ đơn giản hóa công việc của anh ta vô cùng.


8
Bạn có thể sử dụng Dictionary<number, number>thay vì lặp đi lặp lại ifđể bạn có thể có O(1)độ phức tạp thời gian!
Peter Olson

@EnesUnal Không, thời gian tăng tuyến tính khi số lượng tăng lên, bởi vì nó phải đi qua ngày càng nhiều nếu các câu lệnh.
Peter Olson

Theoritically nó không làm tăng :)
totten

@PeterOlson, EresUnal nếu tôi đã sử dụng câu lệnh chuyển đổi, đó sẽ là O (1) :-)
thedayturns

Hoặc bạn có thể tạo một mảng và sử dụng lập trình động. nếu x / 3 = y, thì y << 2 + y = x - x% 3.
lsiebert

14

Sử dụng quầy là một giải pháp cơ bản:

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

Nó cũng dễ dàng để thực hiện một chức năng mô-đun, kiểm tra các ý kiến.


@Enes Unal: không dành cho số lượng nhỏ :) Thuật toán này rất cơ bản.
GJ.

Mọi tính
ưu việt

11

Đây là thuật toán phân chia cổ điển trong cơ sở 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

Viết chương trình trong Pascal và sử dụng DIVtoán tử.

Vì câu hỏi được gắn thẻ , bạn có thể có thể viết một hàm trong Pascal và gọi nó từ chương trình C của bạn; phương pháp để làm như vậy là cụ thể hệ thống.

Nhưng đây là một ví dụ hoạt động trên hệ thống Ubuntu của tôi với fp-compilergói Pascal miễn phí được cài đặt. (Tôi đang làm điều này vì sự bướng bỉnh không đúng chỗ; tôi không khẳng định rằng điều này hữu ích.)

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

Để xây dựng:

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

Thực hiện mẫu:

$ ./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
++ và - nhà hát khác với + và - nhà hát! Trong ngôn ngữ lắp ráp có hai hướng dẫn ADDINCchúng không có cùng opcodes.
Amir Saniyan

7

Không kiểm tra chéo nếu câu trả lời này đã được công bố. Nếu chương trình cần được mở rộng thành số nổi, số có thể được nhân với 10 * số độ chính xác cần thiết và sau đó mã sau có thể được áp dụng lại.

#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

Điều này sẽ làm việc cho bất kỳ ước số, không chỉ ba. Hiện tại chỉ dành cho người chưa ký, nhưng việc mở rộng nó thành đã ký không nên quá khó khăn.

#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

Sẽ là gian lận khi sử dụng /toán tử "đằng sau hậu trường" bằng cách sử dụng evalvà nối chuỗi?

Ví dụ, trong Javacript, bạn có thể làm

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

7

Sử dụng BC Math trong PHP :

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

MySQL (đó là một cuộc phỏng vấn từ Oracle)

> SELECT 12345 DIV 3;

Pascal :

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

ngôn ngữ lắp ráp x86-64:

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

1
Câu chuyện thú vị, điều này được gắn thẻ C và đã được như vậy kể từ ngày đầu tiên. Ngoài ra, bạn hoàn toàn không nắm bắt được điểm của câu hỏi.
Lundin

6

Đầu tiên tôi đã nghĩ ra.

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: Xin lỗi, tôi đã không chú ý đến thẻ C. Nhưng bạn có thể sử dụng ý tưởng về định dạng chuỗi, tôi đoán ...


5

Kịch bản sau đây tạo chương trình C giải quyết vấn đề mà không cần sử dụng toán tử * / + - %:

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

Làm thế nào về phương pháp này (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;
    }

Điều này được gắn thẻ C và đã được như vậy kể từ ngày đầu tiên.
Lundin

4

Tôi nghĩ rằng câu trả lời đúng là:

Tại sao tôi không sử dụng toán tử cơ bản để thực hiện thao tác cơ bản?


Bởi vì những gì họ muốn biết là nếu bạn biết cách bộ xử lý hoạt động bên trong ... sử dụng toán tử toán học cuối cùng sẽ thực hiện một thao tác rất giống với câu trả lời ở trên.
RaptorX

Hoặc họ muốn biết nếu bạn có thể nhận ra một vấn đề vô ích.
Gregoire

1
@Gregoire Tôi đồng ý, Có aboloultley không cần phải thực hiện như vậy, Bit trong đời sống thương mại (Orcale) không cần thiết phải tránh thực hiện những yêu cầu vô ích: Câu trả lời đúng là: "Điều này không có ý nghĩa gì cả, tại sao lại mất tiền cho điều đó? ")
AlexWien

4

Giải pháp sử dụng hàm thư viện fma () , hoạt động với mọi số dương:

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

Xem câu trả lời khác của tôi .


Sử dụng tốt của thư viện. Tại sao bạn không trực tiếp sử dụng kết quả ++?
tinh xanh

sau đó mọi người có thể nói rằng + đã được sử dụng.
Tám

3

Sử dụng cblas , được bao gồm như là một phần của khung Tăng tốc của 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

Chà, đó chỉ là một chi tiết triển khai nên tôi có thể gõ nó là 3.0 / 1.0 thay vì 0.333333, nhưng tôi nên chơi theo luật. Đã sửa!
wjl

Ban đầu tôi có nó là 3.0 / 1.0, đã làm trong bài kiểm tra của tôi. Bằng cách sử dụng số chính xác cao hơn, họ sẽ nhận được kết quả chính xác hợp lý. gist.github.com/3401496
wjl

3

Nói chung, một giải pháp cho vấn đề này sẽ là:

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


3

Đầu tiên:

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

Sau đó tìm ra cách giải 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))

với 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)
}

Mặc dù nó sử dụng +, nhưng ai đó đã thực hiện thêm bằng bitwise op.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.