# 正文

$k>0$ 时, $\left[\kern-0.15em\left[ {\frac{m}{{{2^k}}}} \right]\kern-0.15em\right] = \left\{ {\begin{array}{*{20}{c}} {\left\lfloor {\frac{m}{{{2^k}}} + \frac{1}{2}} \right\rfloor = \left\lfloor {\frac{1}{{{2^k}}}\left( {m + \left\lfloor {\frac{{{2^k}}}{2}} \right\rfloor } \right)} \right\rfloor = \left\lfloor {\frac{{m + {2^{k - 1}}}}{{{2^k}}}} \right\rfloor }&{m \geqslant 0} \\ {\left\lceil {\frac{m}{{{2^k}}} - \frac{1}{2}} \right\rceil = \left\lceil {\frac{1}{{{2^k}}}\left( {m - \left\lfloor {\frac{{{2^k}}}{2}} \right\rfloor } \right)} \right\rceil = \left\lceil {\frac{{m - {2^{k - 1}}}}{{{2^k}}}} \right\rceil }&{m < 0} \end{array}} \right.$.

int div_exp2(int x, unsigned char k)
{
assert( (k >= 0) && (k < INT_BITS));
if (k == 0) return x;
int tail = x >> (INT_BITS - 1);
int exp2_k_1 = 1 << (k - 1);
// 当 x >=0 时, bias = 1 << (k - 1)
// 当 x < 0 时, bias = (1 << (k - 1)) - 1
// 这时 k > 0, 所以 bias >= 0 恒成立.
int bias = tail + exp2_k_1;

// 当 (x >= 0) && (x + bias < 0) 时, 表明 x + bias 在 int 取值范围内溢出,
// 而其在 unsigned int 取值范围内不会溢出, 所以将其转化为 unsigned int 进行运算.
if ((x >= 0) && (x + bias < 0))
{
return int(((unsigned int)(x + bias)) >> k);
}
else
{
return (x + bias) >> k;
}
}


int(((unsigned int)(x + bias)) >> k);


int mask = ~(-1 << (INT_BITS - k));
return ((x + bias) >> k) & mask;


// 当 (x >= 0) && (x + bias < 0) 时, 由于 tail = 0, condition = -1, 所以 mask = ~(-1 << (INT_BITS - k)), 等效于上面的代码.
// 其他情况下,  mask = -1, ((x + bias) >> k) & mask 等效于 (x + bias) >> k.
int condition = (x + bias) >> (INT_BITS - 1);
int mask = ~( (-1 << (INT_BITS - k) ) & ~tail & condition);
return ((x + bias) >> k) & mask;


int div_exp2(int x, unsigned char k)
{
assert( (k >= 0) && (k < INT_BITS));
if (k == 0) return x;
int tail = x >> (INT_BITS - 1);
int exp2_k_1 = 1 << (k - 1);
// 当 x >=0 时, bias = 1 << (k - 1)
// 当 x < 0 时, bias = (1 << (k - 1)) - 1
// 这时 k > 0, 所以 bias >= 0 恒成立.
int bias = tail + exp2_k_1;

// 当 (x >= 0) && (x + bias < 0) 时, 表明 x + bias 在 int 取值范围溢出,
// 而其在 unsigned int 取值范围内不会溢出, 所以将其转化为 unsigned int 进行运算.
int condition = (x + bias) >> (INT_BITS - 1);
int mask = ~( (-1 << (INT_BITS - k) ) & ~tail & condition);
return ((x + bias) >> k) & mask;
}


# 测试代码

#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <limits.h>
#include <assert.h>

const int INT_BITS = 32;

double div_exp2_float(int x, unsigned char k)
{
assert( (k >= 0) && (k < INT_BITS));
unsigned int den = 1 << k;
return double(x) / den;
}

int div_exp2_plain(int x, unsigned char k)
{
assert( (k >= 0) && (k < INT_BITS));
unsigned int den = 1 << k;
if (x > 0)
{
return int(double(x) / den + 0.5);
}
else
{
return int(double(x) / den - 0.5);
}
}

int div_exp2(int x, unsigned char k)
{
assert( (k >= 0) && (k < INT_BITS));
if (k == 0) return x;
int tail = x >> (INT_BITS - 1);
int exp2_k_1 = 1 << (k - 1);
// 当 x >=0 时, bias = 1 << (k - 1)
// 当 x < 0 时, bias = (1 << (k - 1)) - 1
// 这时 k > 0, 所以 bias >= 0 恒成立.
int bias = tail + exp2_k_1;

// 当 (x >= 0) && (x + bias < 0) 时, 表明 x + bias 在 int 取值范围溢出,
// 而其在 unsigned int 取值范围内不会溢出. 所以将其转化为 unsigned int 进行运算.
int condition = (x + bias) >> (INT_BITS - 1);
int mask = ~( (-1 << (INT_BITS - k) ) & ~tail & condition);
return ((x + bias) >> k) & mask;
}

int random(int lower, int upper)
{
if (lower > upper)
{
int temp = lower;
lower = upper;
upper = temp;
}
return rand() % (upper - lower + 1) + lower;
}

int main()
{
int k = 5;
printf("=========================\n");
for (int i = 0; i < 100; ++i)
{
int x = random(-1111, 11111);
float val = div_exp2_float(x, k);
int val1 = div_exp2_plain(x, k);
int val2 = div_exp2(x, k);
if (val1 != val2)
{
printf("%d / 2^%d: %.2f, %d, %d\n", x, k, val, val1, val2);
}
else
{
// printf("Pass\n");
printf("%d / 2^%d: %.2f, %d, %d\n", x, k, val, val1, val2);
}
}
printf("=========================\n");
printf("%f\n", div_exp2_float(INT_MIN, 31));
printf("%f\n", div_exp2_float(INT_MIN + 1, 31));
printf("%f\n", div_exp2_float(INT_MAX, 31));
printf("%d\n", div_exp2_plain(INT_MIN, 31));
printf("%d\n", div_exp2_plain(INT_MIN + 1, 31));
printf("%d\n", div_exp2_plain(INT_MAX, 31));
printf("%d\n", div_exp2(INT_MIN, 31));
printf("%d\n", div_exp2(INT_MIN + 1, 31));
printf("%d\n", div_exp2(INT_MAX, 31));

return 0;
}



# 版权声明

posted @ 2020-05-24 12:09  quarryman  阅读(128)  评论(0编辑  收藏