如何将奇数整数舍入到最接近2的幂

时间:2013-08-20 02:36:46

标签: math bit-manipulation rounding

在奇数中加一或减一,使得偶数结果更接近最接近2的幂。

if ( ??? ) x += 1; else x -= 1;// x > 2 and odd

例如,25到47轮朝向32,加一到2​​5到31并从33到47减去一轮.23轮向下朝16到22轮和49轮朝向64到50轮。

有没有办法做到这一点,却没有找到两个特定的力量。我知道如何使用对数或计数位来获得2的特定幂。

我的具体用例是将奇数大小的输入分割为karatsuba乘法。

4 个答案:

答案 0 :(得分:4)

如果设置了第二个最高有效位,则添加,否则减去。

if((x&(x>>> 1))>(x>> 2))x + = 1;别的x - = 1;

答案 1 :(得分:1)

将32位整数(仅32个条目)的所有2的幂保持为它应该位于的位置的快速二进制搜索并不是什么大不了的事。然后你可以很容易地找出哪个数字通过从较高和较低的数字中减去并获得绝对值来接近它。然后,您可以轻松决定要添加哪一个。

您可以通过获取数字的日志基数2并使用它来索引数组来避免搜索

更新:提醒您此代码未经过全面测试。

#include <array>
#include <cmath>
#include <iostream>

    const std::array<unsigned int,32> powers = 
    {
        1,1<<1,1<<2,1<<3,1<<4,1<<5,1<<6,1<<7,1<<8,1<<9,1<<10,1<<11,1<<12,1<<13,1<<14,
            1<<15,1<<16,1<<17,1<18,1<<19,1<<20,1<<21,1<<22,1<<23,1<<24,1<<25,1<<26,1<<27,
            1<<28,1<<29,1<<30,1<<31 -1
    };
    std::array<unsigned int,32> powers_of_two() {
        std::array<unsigned int,32> powers_of_two{};
        for (unsigned int i = 0; i < 31; ++i) {
            powers_of_two[i] = 1 << i;
        }
        powers_of_two[31]=~0;
        return powers_of_two;
    }

    unsigned int round_to_closest(unsigned int number) {
        if (number % 2 == 0) return number;
        unsigned int i = std::ceil(std::log2(number));
        //higher index
        return (powers[i]-number) < (number - powers[i-1]) ?
            ++number:--number;
    }

    int main() {
        std::cout << round_to_closest(27) << std::endl;
        std::cout << round_to_closest(23) << std::endl;
        return 0;
    }

由于我不能代表2 ^ 31我使用了最接近的unsigned int(全1)这意味着所有这些中的1个案例都会产生不正确的结果,我认为这不是什么大问题。

我原本以为你可以使用std::vector<bool>作为一个非常大的查找表来添加1或减去1,对于一个看起来运行速度非常快的操作来说似乎有点过分了。

答案 2 :(得分:0)

正如@aaronman所指出的,如果你正在使用整数,那么最快的方法就是在表中拥有2的所有幂,因为没有那么多。通过构造,在无符号32位整数中有32个2的幂(包括数字1),在64位整数中有64个,依此类推。

但是如果你想动态地做一般情况,你可以很容易地计算任何数字2的周围幂。在c / c ++中:

#include <math.h>

(...)

double bottom, top, number, exponent;

number = 1234;    // Set the value for number

exponent = int(log(number) / log(2.0));  // int(10.2691) = 10
bottom = pow(2, exponent);               // 2^10 = 1024
top = bottom * 2;                        // 2048

// Calculate the difference between number, top and bottom and add or subtract
// 1 accordingly
number = (top - number) <  (number - bottom) ? number + 1 : number - 1;

答案 3 :(得分:0)

对于最近(不是最大或相等) - 请参阅:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
  unsigned int val = atoi(argv[1]); 
  unsigned int x = val;
  unsigned int result;
  do {
    result = x;
  } while(x &= x - 1);

  if((result >> 1) & val)
    result <<= 1;

  printf("result=%u\n", result);
  return 0;
}

如果你需要最大或相同 - 改变:

if((result >> 1) & val)

if(result != val)