如何将一个数除3而不使用*、/、+、-、%等运算符?
号码可以有签名,也可以没有签名。
如何将一个数除3而不使用*、/、+、-、%等运算符?
号码可以有签名,也可以没有签名。
当前回答
要将一个数除以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
}
其他回答
这应该适用于任何除数,而不仅仅是3。目前仅适用于unsigned,但将其扩展到signed应该没有那么困难。
#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;
}
#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;
}
很有趣的是,没有人回答一个泛泛的划分:
/* 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;
}
按位加法已经在其中一个答案中给出,所以跳过它。
int div3(int x)
{
int reminder = abs(x);
int result = 0;
while(reminder >= 3)
{
result++;
reminder--;
reminder--;
reminder--;
}
return result;
}
这是我小时候爷爷教我的一个方法。它需要+和/运算符,但计算起来很简单。
把每个数字相加,然后看看它是否是3的倍数。
但这种方法适用于大于12的数字。
例如:36岁,
3+6=9,是3的倍数。
42,
4+2=6,是3的倍数。