将一个数除以3而不使用 *, /, +, -, % 运算符

如何在不使用*/+-%运算符的情况下将数字除以3?

数字可以是有符号的或无符号的。

151607 次浏览

用Pascal编写程序并使用DIV运算符。

由于问题标记为,您可能可以在Pascal中编写一个函数并从您的C程序中调用它;这样做的方法是系统特定的。

但是这里有一个安装了Free Pascalfp-compiler包的Ubuntu系统上的示例。(我这样做完全是出于错位的固执;我没有声称这是有用的。)

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

要构建:

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

示例执行:

$ ./main
Enter a number: 100
100 / 3 = 33

(注意:请参阅下面的编辑2以获得更好的版本!)

这并不像听起来那么棘手,因为您说“不使用[…]+[…]运营商”。如果您想禁止同时使用+字符,请参阅下文。

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

然后说div_by(100,3)100除以3


编辑:您也可以继续替换++运算符:

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

编辑2:稍微快一点的版本,不使用任何包含+-*/%字符的运算符。

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函数的第一个参数,因为我们不能在不使用*字符的情况下表示指针的类型,除非在函数参数列表中,其中语法type[]type* const相同。

FWIW,您可以使用类似的技巧轻松实现乘法函数,以使用AndreyT提出的0x55555556技巧:

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

使用itoa转换为基数3字符串。删除最后一个trit并转换回基数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
}

这是一个简单函数,它执行所需的操作。但它需要+运算符,所以你剩下要做的就是用位运算符添加值:

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

正如吉姆所说,这是有效的,因为:

  • n = 4 * a + b
  • n / 3 = a + (a + b) / 3
  • 所以sum += an = a + b,然后迭代

  • a == 0 (n < 4)sum += floor(n / 3);即1、if n == 3, else 0

要将32位数字除以3,可以将其乘以0x55555556,然后取64位结果的高32位。

现在剩下要做的就是使用位操作和移位来实现乘法。

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

愚蠢的条件需要一个愚蠢的解决方案:

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

如果还需要小数部分,只需将result声明为double并将fmod(number,divisor)的结果添加到其中。

解释它是如何工作的

  1. fwrite写入number字节(在上面的示例中数字为123456)。
  2. rewind将文件指针重置到文件的前面。
  3. fread从文件中读取最大长度为divisornumber“记录”,并返回它读取的元素数。

如果你写30个字节,然后以3为单位读回文件,你会得到10个“单位”。30/3=10

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

您可以使用(依赖于平台的)内联汇编,例如,对于x86:(也适用于负数)

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

使用<强>黑客的喜悦魔法数字计算器

int divideByThree(int num)
{
return (fma(num, 1431655766, 0) >> 32);
}

其中fmamath.h标头中定义的标准库函数。

以下是我的解决方案:

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

首先,请注意

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

剩下的就简单了!

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

现在我们所要做的就是将a的这些位偏移值加在一起!哎呀!我们不能添加,所以相反,我们必须使用按位运算符编写一个添加函数!如果你熟悉按位运算符,我的解决方案应该看起来相当简单……但以防万一你不熟悉,我将在最后介绍一个示例。

另一件需要注意的事情是,首先我左移30!这是为了确保分数不会被四舍五入。

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!

这只是你小时候学到的携带加法!

111
1011
+0110
-----
10001

这个实现失败因为我们不能添加等式的所有项:

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,然后是x <= floor(f(a, i)) < a / 3。当a = 3k时,我们得到错误的答案。

还有另一个解决方案。这应该处理除int的最小值之外的所有整数(包括负整数),int的最小值需要作为硬编码异常处理。这基本上是通过减法进行除法,但只使用位运算符(移位、异或和补码)。为了更快的速度,它减去3*(2的递减幂)。在c#中,它每毫秒执行大约444次DiVideBy3调用(1,000,000次除法为2.2秒),所以不是很慢,但没有简单的x/3快。相比之下,Coodey的好解决方案比这个快5倍左右。

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

这是c#,因为这是我手边的东西,但与c的差异应该很小。

设置计算机上很容易实现。

要将整数除以3,请使用右移1位

不过我不确定在这样的平台上是否完全可以实现一个合格的C编译器。我们可能不得不稍微扩展一下规则,比如将“至少8位”解释为“至少能够容纳-128到+127的整数”。

这是我首先想到的。

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

编辑:对不起,我没有注意到标签C。但是你可以使用字符串格式的想法,我想…

这是基地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);
}

使用cblas,作为OS X Accelerate框架的一部分。

[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

没有交叉检查此答案是否已经发布。如果程序需要扩展为浮动数字,可以将数字乘以所需精度的10*,然后再次应用以下代码。

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

这应该适用于任何除数,而不仅仅是三个。目前仅适用于无符号,但将其扩展为有符号应该没有那么困难。

#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;
}
#!/bin/ruby


def div_by_3(i)
i.div 3        # always return int http://www.ruby-doc.org/core-1.9.3/Numeric.html#method-i-div
end

使用fma()库函数的解决方案,适用于任何正数:

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

看我另一个答案

这里是Python中的,基本上是字符串比较和状态机。

def divide_by_3(input):
to_do = {}
enque_index = 0
zero_to_9 = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
leave_over = 0
for left_over in (0, 1, 2):
for digit in zero_to_9:
# left_over, digit => enque, leave_over
to_do[(left_over, digit)] = (zero_to_9[enque_index], leave_over)
if leave_over == 0:
leave_over = 1
elif leave_over == 1:
leave_over = 2
elif leave_over == 2 and enque_index != 9:
leave_over = 0
enque_index = (1, 2, 3, 4, 5, 6, 7, 8, 9)[enque_index]
answer_q = []
left_over = 0
digits = list(str(input))
if digits[0] == "-":
answer_q.append("-")
digits = digits[1:]
for digit in digits:
enque, left_over = to_do[(left_over, int(digit))]
if enque or len(answer_q):
answer_q.append(enque)
answer = 0
if len(answer_q):
answer = int("".join([str(a) for a in answer_q]))
return answer

php中使用bc数学

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

MySQL(来自Oracle的采访)

> SELECT 12345 DIV 3;

Pascal

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

x86-64汇编语言:

mov  r8, 3
xor  rdx, rdx
mov  rax, 12345
idiv r8
int div3(int x)
{
int reminder = abs(x);
int result = 0;
while(reminder >= 3)
{
result++;


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

使用计数器是一个基本的解决方案:

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

它也很容易执行模数函数,检查注释。

使用Linux外壳脚本:

#include <stdio.h>
int main()
{
int number = 30;
char command[25];
snprintf(command, 25, "echo $((%d %c 3)) ", number, 47);
system( command );
return 0;
}

看我另一个答案

以下脚本生成一个C程序,该程序无需使用运算符* / + - %即可解决问题:

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

这真的很容易。

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;

(当然,为了简洁起见,我省略了一些程序。)如果程序员厌倦了全部输入,我相信他或她可以编写一个单独的程序来为他生成它。我碰巧知道某个运算符,/,这将极大地简化他的工作。

通过使用eval和字符串连接来“在幕后”使用/运算符是否会作弊?

例如,在Javacript中,您可以执行

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

好'olbc

$ num=1337; printf "scale=5;${num}\x2F3;\n" | bc
445.66666

如果我们认为__div__不是正写法上的/

def divBy3(n):
return n.__div__(3)


print divBy3(9), 'or', 9//3

3的2进制是11。

所以只要在2进制中用11做长除法(就像在中学一样)。在2进制中比在10进制中更容易。

对于从最高有效位开始的每个位位置:

确定前缀是否小于11。

如果输出为0。

如果不是输出1,则用前缀位替换适当的变化。只有三种情况:

 11xxx ->    xxx    (ie 3 - 3 = 0)
100xxx ->   1xxx    (ie 4 - 3 = 1)
101xxx ->  10xxx    (ie 5 - 3 = 2)

所有其他前缀都无法访问。

重复直到最低位位置,你就完成了。

这是我小时候祖父教我的一种方法。它需要+和/运算符,但它使计算变得容易。

将单个数字相加,然后查看它是否是3的倍数。

但这种方法适用于12以上的数字。

例:36,

3+6=9,是3的倍数。

42岁

4+2=6,是3的倍数。

那么你可以考虑使用类似图/树的结构来解决这个问题。基本上生成与要除以3的数量相同的顶点。然后继续将每个未配对的顶点与其他两个顶点配对。

粗糙伪代码:

function divide(int num)
while(num!=0)
Add a new vertice to vertiexList.
num--
quotient = 0
for each in vertexList(lets call this vertex A)
if vertexList not empty
Add an edge between A and another vertex(say B)
else
your Remainder is 1 and Quotient is quotient
if vertexList not empty
Add an edge between A and another vertex(say C)
else
your remainder is 2 and Quotient is quotient
quotient++
remove A, B, C from vertexList
Remainder is 0 and Quotient is quotient

这显然可以优化,复杂性取决于你的数字有多大,但它应该工作,只要你能做++和--。 这就像只计算冷却器一样好。

这种方法(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;
}

我认为正确的答案是:

为什么我不使用基本运算符来执行基本操作?

第一:

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

然后找出如何解决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))

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

虽然它使用了+,但已经有人实现了按位操作添加。

好吧,我想我们都同意这不是一个现实世界的问题。所以只是为了好玩,下面是如何使用Ada和多线程来做到这一点:

with Ada.Text_IO;


procedure Divide_By_3 is


protected type Divisor_Type is
entry Poke;
entry Finish;
private
entry Release;
entry Stop_Emptying;
Emptying : Boolean := False;
end Divisor_Type;


protected type Collector_Type is
entry Poke;
entry Finish;
private
Emptying : Boolean := False;
end Collector_Type;


task type Input is
end Input;
task type Output is
end Output;


protected body Divisor_Type is
entry Poke when not Emptying and Stop_Emptying'Count = 0 is
begin
requeue Release;
end Poke;
entry Release when Release'Count >= 3 or Emptying is
New_Output : access Output;
begin
if not Emptying then
New_Output := new Output;
Emptying := True;
requeue Stop_Emptying;
end if;
end Release;
entry Stop_Emptying when Release'Count = 0 is
begin
Emptying := False;
end Stop_Emptying;
entry Finish when Poke'Count = 0 and Release'Count < 3 is
begin
Emptying := True;
requeue Stop_Emptying;
end Finish;
end Divisor_Type;


protected body Collector_Type is
entry Poke when Emptying is
begin
null;
end Poke;
entry Finish when True is
begin
Ada.Text_IO.Put_Line (Poke'Count'Img);
Emptying := True;
end Finish;
end Collector_Type;


Collector : Collector_Type;
Divisor : Divisor_Type;


task body Input is
begin
Divisor.Poke;
end Input;


task body Output is
begin
Collector.Poke;
end Output;


Cur_Input : access Input;


-- Input value:
Number : Integer := 18;
begin
for I in 1 .. Number loop
Cur_Input := new Input;
end loop;
Divisor.Finish;
Collector.Finish;
end Divide_By_3;

相当有趣的是,没有人回答一个通用的划分:

/* For the given integer find the position of MSB */
int find_msb_loc(unsigned int n)
{
if (n == 0)
return 0;


int loc = sizeof(n)  * 8 - 1;
while (!(n & (1 << loc)))
loc--;
return loc;
}




/* Assume both a and b to be positive, return a/b */
int divide_bitwise(const unsigned int a, const unsigned int b)
{
int int_size = sizeof(unsigned int) * 8;
int b_msb_loc = find_msb_loc(b);


int d = 0; // dividend
int r = 0; // reminder
int t_a = a;
int t_a_msb_loc = find_msb_loc(t_a);
int t_b = b << (t_a_msb_loc - b_msb_loc);


int i;
for(i = t_a_msb_loc; i >= b_msb_loc; i--)  {
if (t_a > t_b) {
d = (d << 1) | 0x1;
t_a -= t_b; // Not a bitwise operatiion
t_b = t_b >> 1;
}
else if (t_a == t_b) {
d = (d << 1) | 0x1;
t_a = 0;
}
else { // t_a < t_b
d = d << 1;
t_b = t_b >> 1;
}
}


r = t_a;
printf("==> %d %d\n", d, r);
return d;
}

按位加法已经在其中一个答案中给出,所以跳过它。

所有的答案可能都不是面试官喜欢听到的:

我的回答:

“我永远不会那样做,谁会为这样愚蠢的事情付钱?没有人 将有一个优势,它不是更快,它只是愚蠢的。 处理器设计者必须知道这一点,但这必须适用于所有数字,而不仅仅是除以3"

似乎没有人提到用二进制表示的3的除法标准——偶数的和应该等于奇数的和(类似于十进制中的11的标准)。在检查一个数是否可以被3整除下有使用这个技巧的解决方案。

我想这是迈克尔·伯尔的编辑提到的可能的副本。

其中InputValue是除以3的数字

SELECT AVG(NUM)
FROM (SELECT InputValue NUM from sys.dual
UNION ALL SELECT 0 from sys.dual
UNION ALL SELECT 0 from sys.dual) divby3
#include <stdio.h>


typedef struct { char a,b,c; } Triple;


unsigned long div3(Triple *v, char *r) {
if ((long)v <= 2)
return (unsigned long)r;
return div3(&v[-1], &r[1]);
}


int main() {
unsigned long v = 21;
int r = div3((Triple*)v, 0);
printf("%ld / 3 = %d\n", v, r);
return 0;
}

为什么我们不应用大学学习的定义呢?结果可能效率低下但很清楚,因为乘法只是递归减法,减法是加法,那么加法可以通过递归异或/和逻辑端口组合来执行。

#include <stdio.h>


int add(int a, int b){
int rc;
int carry;
rc = a ^ b;
carry = (a & b) << 1;
if (rc & carry)
return add(rc, carry);
else
return rc ^ carry;
}


int sub(int a, int b){
return add(a, add(~b, 1));
}


int div( int D, int Q )
{
/* lets do only positive and then
* add the sign at the end
* inversion needs to be performed only for +Q/-D or -Q/+D
*/
int result=0;
int sign=0;
if( D < 0 ) {
D=sub(0,D);
if( Q<0 )
Q=sub(0,Q);
else
sign=1;
} else {
if( Q<0 ) {
Q=sub(0,Q);
sign=1;
}
}
while(D>=Q) {
D = sub( D, Q );
result++;
}
/*
* Apply sign
*/
if( sign )
result = sub(0,result);
return result;
}


int main( int argc, char ** argv )
{
printf( "2 plus 3=%d\n", add(2,3) );
printf( "22 div 3=%d\n", div(22,3) );
printf( "-22 div 3=%d\n", div(-22,3) );
printf( "-22 div -3=%d\n", div(-22,-3) );
printf( "22 div 03=%d\n", div(22,-3) );
return 0;
}

正如有人所说…首先使这个工作。请注意,算法应该适用于负Q…

一般来说,解决这个问题的方法是:

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

我会使用此代码来划分所有正的,非浮点数。基本上你想要将除数位向左对齐以匹配股息位。对于股息的每个部分(除数的大小),你要检查以确保股息部分是否大于除数,然后你要在第一个注册器中向左移动,然后进行OR。这个概念最初创建于2004年(我相信是站着的),这是一个使用该概念的C版本。注意:(我稍微修改了一下)

int divide(int a, int b)
{
int c = 0, r = 32, i = 32, p = a + 1;
unsigned long int d = 0x80000000;


while ((b & d) == 0)
{
d >>= 1;
r--;
}


while (p > a)
{
c <<= 1;
p = (b >> i--) & ((1 << r) - 1);
if (p >= a)
c |= 1;
}
return c; //p is remainder (for modulus)
}

示例用法:

int n = divide( 3, 6); //outputs 2

这将工作:

smegma$ curl http://www.wolframalpha.com/input/?i=14+divided+by+3 2>/dev/null | gawk 'match($0, /link to /input/\?i=([0-9.+-]+)/, ary) { print substr( $0, ary[1, "start"], ary[1, "length"] )}' 4.6666666666666666666666666666666666666666666666666666

用你的数字代替“14”和“3”。

如果你提醒自己标准的除法方法并用二进制进行,你会发现,在3的情况下,你只对一组有限的值进行除法和减法(在这种情况下从0到5)。这些可以用Switch语句来处理,以摆脱算术运算符。

static unsigned lamediv3(unsigned n)
{
unsigned result = 0, remainder = 0, mask = 0x80000000;


// Go through all bits of n from MSB to LSB.
for (int i = 0; i < 32; i++, mask >>= 1)
{
result <<= 1;
// Shift in the next bit of n into remainder.
remainder = remainder << 1 | !!(n & mask);


// Divide remainder by 3, update result and remainer.
// If remainder is less than 3, it remains intact.
switch (remainder)
{
case 3:
result |= 1;
remainder = 0;
break;


case 4:
result |= 1;
remainder = 1;
break;


case 5:
result |= 1;
remainder = 2;
break;
}
}


return result;
}


#include <cstdio>


int main()
{
// Verify for all possible values of a 32-bit unsigned integer.
unsigned i = 0;


do
{
unsigned d = lamediv3(i);


if (i / 3 != d)
{
printf("failed for %u: %u != %u\n", i, d, i / 3);
return 1;
}
}
while (++i != 0);
}

要将数字除以3,而不使用乘法,除法,余数,减法或加法操作,在汇编编程语言中,唯一可用的指令是LEA(地址有效加载),SHL(向左移动)和SHR(向右移动)。

对于这个解决方案,我没有使用与运算符相关的操作 + - * /%

我假设输出数字为定点格式(整数部分的16位和小数部分的16位),并且输入数字为短int类型;然而,我已经近似了输出数量,因为我只能信任整数部分,因此我返回一个短int类型的值。

65536/6是相当于1/3浮点数的定点值,等于21845。

21845=16384+4096+1024+256+64+16+4+1。

所以,为了乘以1/3(21845),我使用指令LEA和SHL。

short int DivideBy3( short int num )
//In : eax= 16 Bit short int input number (N)
//Out: eax= N/3 (32 Bit fixed point output number
//          (Bit31-Bit16: integer part, Bit15-Bit0: digits after comma)
{
__asm
{
movsx eax, num          // Get first argument


// 65536 / 3 = 21845 = 16384 + 4096 + 1024 + 256 + 64 + 16 + 4 + 1


lea edx,[4*eax+eax]     // EDX= EAX * 5
shl eax,4
lea edx,[eax+edx]       // EDX= EDX + EAX * 16
shl eax,2
lea edx,[eax+edx]       // EDX= EDX + EAX * 64
shl eax,2
lea edx,[eax+edx]       // EDX= EDX + EAX * 256
shl eax,2
lea edx,[eax+edx]       // EDX= EDX + EAX * 1024
shl eax,2
lea edx,[eax+edx]       // EDX= EDX + EAX * 4096
shl eax,2
lea edx,[eax+edx+08000h] // EDX= EDX + EAX * 16384


shr edx,010h
movsx eax,dx


}
// Return with result in EAX
}

它也适用于负数;结果与正数有最小近似值(逗号后最后一位数字为-1)。

如果您不打算使用运算符 + - * /% 来执行除以3,但可以使用与它们相关的操作,我提出了第二种解决方案。

int DivideBy3Bis( short int num )
//In : eax= 16 Bit short int input number (N)
//Out: eax= N/3 (32 Bit fixed point output number
//          (Bit31-Bit16: integer part, Bit15-Bit0: digits after comma)
{
__asm
{
movsx   eax, num        // Get first argument


mov     edx,21845
imul    edx
}
// Return with result in EAX
}