a * 9
可以拆分成 a * (8+1)
即 a*8+a*1
, 因此可以改为:
a=(a<<3)+a
a = a * 7
分析 a*7
可以拆分成 a*(8-1)
即 a*8-a*1
, 因此可以改为:
a=(a<<3)-a
1)对 2 的 n 次方取余
a % b = a & (b-1) (b=2^n)
1)对 2
的 n
次方取模,N/8
:
N>>3
2)对一个奇数取模,比如: num/9
,
使用 16
(不能超过9的2倍) 替代 9
先对 num 取模,num 对 16 取模后的值肯定大于等于对 9 取模所得的值,使用移位算法可以进行乘 9
的计算,将所得的模值乘9之后再与原值 num
进行比较,第一次对 num进 行16
取模后,num - sum * 9
的差值会分为三种情况:
1)小于 9,也即 num - 9*sum < 16
且小于9,所模值就为sum(只循环一次)
2) 大于等于9,小于16,也即,num-9*sum >= 9
且小于16,此时模值为 sum+1
(只循环一次)
3)大于等于16
,也即,num - 9*sum >= 16
, 由于16>9
, 所以模值 sum 太小,所以还要将 num-9*sum
的值再次对16
取模, 得到 sum1
,将两次模值相加后,再进行 num -(sum+sum1)* 9
和 16
进行比较。将多次对16取模的值进行累加,直到num-(sum+sum1+...+sumx)*9 < 16
即可。
int modulo9_func(int num)
{
int i, sum = 0;
int tmpsum = num;
debug_info("input number is 0x%x\n", num);
while (tmpsum >= 16) {
i++;
tmpsum = tmpsum >> 4;
sum = sum + tmpsum;
debug_info("%d time >> 4 operation sum:%d\n", i, sum);
tmpsum = num - (sum << 3) - sum;
}
if (tmpsum >= 9)
return (sum + 1);
}
static int modulo7_func(int num)
{
int i, sum = 0;
int tmpsum = num;
debug_info("input number is 0x%x\n", num);
while (tmpsum >= 8) {
i++;
tmpsum = tmpsum >> 3;
sum = sum + tmpsum;
debug_info("num %d time >> 3 operation, sum:%d\n", i, sum);
tmpsum = num - (sum << 3) + sum;
}
if (tmpsum >= 7)
return (sum + 1);
return sum;
}
static int power2_test(int num)
{
return ((((num - 0x1) & num) == 0) && (num != 0));
}
例如:有一个32bit 的整型数 data,要求任意交换 m 位和 n 位,其中 m != n, m, n 在0~31之间,要求用宏来定义这个功能:
#define bswap(data, m, n) \
(data & (1 << m)) == (data & (1 << n)) ? data : data ^ ((1 << m) | (1 << n))
如果两个比特位相同,返回原始的data,
如果两个比特位不同,那么利用异或运算将原来的 0变为1,1变为0, 即通過将该比特位与 1 异或 即可以取反了。
字节对齐是在分配内存时需要考虑的问题,两个小算法:
假定目前该变量占用 n 个字节,对齐目标是 align , 求返回的占用实际内存大小。
(1) 最容易想到的算法:
unsigned int calc_align(unsigned int n,unsigned align)
{
if ( n / align * align == n)
return n;
return (n / align + 1) * align;
}
就是判断一下,当前占用的内存字节,是否是 alin 的整数倍。如果是那么直接返回,这个占用字节数;如果不满足,那么直接加一个 align 来对齐。只有当 n 是align 的整数倍的时候,可以实现等于号。
(2) 更好的算法:
#define ALIGN(n, align) ((n + align - 1) & ~(align - 1))
在RT-Thread 的代码中,关于 cache 的操作就用到了这个方法:
rt-thread/rt-thread/libcpu/arm/cortex-m7/cpu_cache.c
void rt_hw_cpu_dcache_ops(int ops, void* addr, int size)
{
rt_uint32_t startAddr = (rt_uint32_t)addr & (rt_uint32_t)~(L1CACHE_LINESIZE_BYTE - 1);
rt_uint32_t size_byte = size + (rt_uint32_t)addr - startAddr;
uint32_t clean_invalid = RT_HW_CACHE_FLUSH | RT_HW_CACHE_INVALIDATE;
if ((ops & clean_invalid) == clean_invalid)
{
SCB_CleanInvalidateDCache_by_Addr((uint32_t *)startAddr, size_byte);
}
else if (ops & RT_HW_CACHE_FLUSH)
{
SCB_CleanDCache_by_Addr((uint32_t *)startAddr, size_byte);
}
else if (ops & RT_HW_CACHE_INVALIDATE)
{
SCB_InvalidateDCache_by_Addr((uint32_t *)startAddr, size_byte);
}
else
{
RT_ASSERT(0);
}
}