标签:++i === 结果 alt min bit 保留 协议 应该
前几天QQ群里一位好友提出来一个问题: "整型(有正有负)除以2的指数结果四舍五入, 应该如何优化呢", 当时做了答, 发表在这里, 希望对大家有用.
下取整函数的定义: \(\left\lfloor x \right\rfloor = \max \left\{ {z \in \mathbb{Z}:z \leqslant x} \right\}\)
上取整函数的定义: \(\left\lceil x \right\rceil = \min \left\{ {z \in \mathbb{Z}:z \geqslant x} \right\}\)
四舍五入取整函数的定义: \(\left[\kern-0.15em\left[ x \right]\kern-0.15em\right] = \left\{ {\begin{array}{*{20}{c}} {\left\lfloor {x + 0.5} \right\rfloor }&{x > 0} \\ {\left\lceil {x - 0.5} \right\rceil }&{x \leqslant 0} \end{array}} \right.\)
问题: 整型(有正有负)除以2的指数结果四舍五入, 应该如何优化呢?
问题转化为: 将 \(\left[\kern-0.15em\left[ {\frac{m}{2^k}} \right]\kern-0.15em\right]\) 转化为向下取整的形式,其中 \(m\) 为整数, \(k\) 为非负整数.
答: 因为 \(\left[\kern-0.15em\left[ {\frac{m}{n}} \right]\kern-0.15em\right] = \left\{ {\begin{array}{*{20}{c}} {\left\lfloor {\frac{m}{n} + \frac{1}{2}} \right\rfloor = \left\lfloor {\frac{1}{n}\left( {m + \left\lfloor {\frac{n}{2}} \right\rfloor } \right)} \right\rfloor }&{mn \geqslant 0} \\ {\left\lceil {\frac{m}{n} - \frac{1}{2}} \right\rceil = \left\lceil {\frac{1}{n}\left( {m - \left\lfloor {\frac{n}{2}} \right\rfloor } \right)} \right\rceil }&{mn < 0} \end{array}} \right.\), 其中 \(m, n\) 均为整数, \(n \neq 0\).
特别地, 设 \(n = 2^k\) ( \(k\) 为非负整数) 时, 当 \(k=0\) 时, \(\left[\kern-0.15em\left[ m \right]\kern-0.15em\right] = m\);
当 \(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.\).
又因为 \(\left\lceil {\frac{m}{n}} \right\rceil = \left\{ {\begin{array}{*{20}{c}} {\left\lfloor {\frac{{m + n - 1}}{n}} \right\rfloor = \left\lfloor {\frac{{m - 1}}{n}} \right\rfloor + 1}&{n > 0} \\ {\left\lfloor {\frac{{m + n + 1}}{n}} \right\rfloor = \left\lfloor {\frac{{m + 1}}{n}} \right\rfloor + 1}&{n < 0} \end{array}} \right.\),
所以 \(\left\lceil {\frac{{m - {2^{k - 1}}}}{{{2^k}}}} \right\rceil = \left\lfloor {\frac{{m - {2^{k - 1}} + {2^k} - 1}}{{{2^k}}}} \right\rfloor = \left\lfloor {\frac{{m + {2^{k - 1}} - 1}}{{{2^k}}}} \right\rfloor\).
综上, \(\left[\kern-0.15em\left[ {\frac{m}{{{2^k}}}} \right]\kern-0.15em\right] = \left\{ {\begin{array}{*{20}{c}} m&{k = 0} \\ {\left\lfloor {\frac{{m + {2^{k - 1}}}}{{{2^k}}}} \right\rfloor }&{k > 0,m \geqslant 0} \\ {\left\lfloor {\frac{{m + {2^{k - 1}} - 1}}{{{2^k}}}} \right\rfloor }&{k > 0,m < 0} \end{array}} \right.\).
上式可以很方便地转写为只包含加减和位运算的C/C++代码.
const int INT_BITS = 32;
int div_exp2(int x, unsigned char k)
{
if (k == 0) return x;
int tail = x >> (INT_BITS - 1);
return (x + (1 << (k - 1)) + tail) >> k;
}
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
int div_exp2_plain(int x, unsigned char k)
{
int den = 1 << k;
if (x > 0)
{
return int(float(x) / den + 0.5);
}
else
{
return int(float(x) / den - 0.5);
}
}
const int INT_BITS = 32;
int div_exp2(int x, unsigned char k)
{
if (k == 0) return x;
int tail = x >> (INT_BITS - 1);
return (x + (1 << (k - 1)) + tail) >> k;
}
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 < 10000; ++i)
{
int x = random(-1111, 11111);
int val1 = div_exp2_plain(x, k);
int val2 = div_exp2(x, k);
if (val1 != val2)
{
float val = float(x) / (1 << k);
printf("%d / 2^%d: %.2f, %d, %d\n", x, k, val, val1, val2);
}
else
{
// printf("Pass\n");
}
}
printf("=========================\n");
return 0;
}
版权声明:自由分享,保持署名-非商业用途-非衍生,知识共享3.0协议。
如果你对本文有疑问或建议,欢迎发留言!转载请保留版权声明!
如果你觉得本文不错, 也可以用微信赞赏一下哈.
标签:++i === 结果 alt min bit 保留 协议 应该
原文地址:https://www.cnblogs.com/quarryman/p/div_exp2.html