代码优化之整型除以2的指数并四舍五入

Posted quarryman

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代码优化之整型除以2的指数并四舍五入相关的知识,希望对你有一定的参考价值。

引子

前几天QQ群里一位好友提出来一个问题: "整型(有正有负)除以2的指数结果四舍五入, 应该如何优化呢", 当时做了答, 发表在这里, 希望对大家有用.

符号约记

下取整函数的定义: (leftlfloor x ight floor = max left{ {z in mathbb{Z}:z leqslant x} ight})

上取整函数的定义: (leftlceil x ight ceil = min left{ {z in mathbb{Z}:z geqslant x} ight})

四舍五入取整函数的定义: (left[kern-0.15emleft[ x ight]kern-0.15em ight] = left{ {egin{array}{*{20}{c}} {leftlfloor {x + 0.5} ight floor }&{x > 0} \\ {leftlceil {x - 0.5} ight ceil }&{x leqslant 0} end{array}} ight.)

正文

问题: 整型(有正有负)除以2的指数结果四舍五入, 应该如何优化呢?

问题转化为: 将 (left[kern-0.15emleft[ {frac{m}{2^k}} ight]kern-0.15em ight]) 转化为向下取整的形式,其中 (m) 为整数, (k) 为非负整数.

答: 因为 (left[kern-0.15emleft[ {frac{m}{n}} ight]kern-0.15em ight] = left{ {egin{array}{*{20}{c}} {leftlfloor {frac{m}{n} + frac{1}{2}} ight floor = leftlfloor {frac{1}{n}left( {m + leftlfloor {frac{n}{2}} ight floor } ight)} ight floor }&{mn geqslant 0} \\ {leftlceil {frac{m}{n} - frac{1}{2}} ight ceil = leftlceil {frac{1}{n}left( {m - leftlfloor {frac{n}{2}} ight floor } ight)} ight ceil }&{mn < 0} end{array}} ight.), 其中 (m, n) 均为整数, (n eq 0).

特别地, 设 (n = 2^k) ( (k) 为非负整数) 时, 当 (k=0) 时, (left[kern-0.15emleft[ m ight]kern-0.15em ight] = m);
(k>0) 时, (left[kern-0.15emleft[ {frac{m}{{{2^k}}}} ight]kern-0.15em ight] = left{ {egin{array}{*{20}{c}} {leftlfloor {frac{m}{{{2^k}}} + frac{1}{2}} ight floor = leftlfloor {frac{1}{{{2^k}}}left( {m + leftlfloor {frac{{{2^k}}}{2}} ight floor } ight)} ight floor = leftlfloor {frac{{m + {2^{k - 1}}}}{{{2^k}}}} ight floor }&{m geqslant 0} \\ {leftlceil {frac{m}{{{2^k}}} - frac{1}{2}} ight ceil = leftlceil {frac{1}{{{2^k}}}left( {m - leftlfloor {frac{{{2^k}}}{2}} ight floor } ight)} ight ceil = leftlceil {frac{{m - {2^{k - 1}}}}{{{2^k}}}} ight ceil }&{m < 0} end{array}} ight.).

又因为 (leftlceil {frac{m}{n}} ight ceil = left{ {egin{array}{*{20}{c}} {leftlfloor {frac{{m + n - 1}}{n}} ight floor = leftlfloor {frac{{m - 1}}{n}} ight floor + 1}&{n > 0} \\ {leftlfloor {frac{{m + n + 1}}{n}} ight floor = leftlfloor {frac{{m + 1}}{n}} ight floor + 1}&{n < 0} end{array}} ight.),

所以 (leftlceil {frac{{m - {2^{k - 1}}}}{{{2^k}}}} ight ceil = leftlfloor {frac{{m - {2^{k - 1}} + {2^k} - 1}}{{{2^k}}}} ight floor = leftlfloor {frac{{m + {2^{k - 1}} - 1}}{{{2^k}}}} ight floor).

综上, (left[kern-0.15emleft[ {frac{m}{{{2^k}}}} ight]kern-0.15em ight] = left{ {egin{array}{*{20}{c}} m&{k = 0} \\ {leftlfloor {frac{{m + {2^{k - 1}}}}{{{2^k}}}} ight floor }&{k > 0,m geqslant 0} \\ {leftlfloor {frac{{m + {2^{k - 1}} - 1}}{{{2^k}}}} ight floor }&{k > 0,m < 0} end{array}} ight.).

上式可以很方便地转写为只包含加减和位运算的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("=========================
");
    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
", x, k, val, val1, val2);
        }
        else
        {
            // printf("Pass
");
        }
    }
    printf("=========================
");
    return 0;
}

版权声明

版权声明:自由分享,保持署名-非商业用途-非衍生,知识共享3.0协议。
如果你对本文有疑问或建议,欢迎发留言!转载请保留版权声明!
如果你觉得本文不错, 也可以用微信赞赏一下哈.
技术图片





以上是关于代码优化之整型除以2的指数并四舍五入的主要内容,如果未能解决你的问题,请参考以下文章

数据类型之整型

数据类型之整型(int)

Python基本数据类型之整型和布尔型

Java复习之整型自动转换成浮点型

PHP扩展开发之整型参数传递

go--4大基本数据类型之整型