Math 如何将奇数整数四舍五入到二的最近幂

Math 如何将奇数整数四舍五入到二的最近幂,math,bit-manipulation,rounding,Math,Bit Manipulation,Rounding,奇数整数加一或减一,使偶数结果更接近二的最近幂 if ( ??? ) x += 1; else x -= 1;// x > 2 and odd 例如,25到47向32进位,25到31加一,33到47减一。23轮向下,16比22,49轮向上,64比50 有没有一种方法可以做到这一点,而不需要找到两个四舍五入的特定幂。我知道如何使用对数或计数位来获得2的特定幂 if ( ??? ) x += 1; else x -= 1;// x > 2 and odd 我的具体使用案例是将奇数大小

奇数整数加一或减一,使偶数结果更接近二的最近幂

if ( ??? ) x += 1; else x -= 1;// x > 2 and odd
例如,25到47向32进位,25到31加一,33到47减一。23轮向下,16比22,49轮向上,64比50

有没有一种方法可以做到这一点,而不需要找到两个四舍五入的特定幂。我知道如何使用对数或计数位来获得2的特定幂

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

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

对于一个32位整数(只有32个条目)保持2的所有幂并没有什么大不了的。对它应该位于的位置进行快速二进制搜索。然后你可以很容易地找出哪个数字更接近从高和低的数字减去,并得到abs。然后,您可以轻松决定添加哪一个

您可以通过获取数字的日志基数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;
    }
#包括
#包括
#包括
常数std::数组幂=
{

1,1对于一个32位整数(只有32个条目),保留2的所有幂并不是什么大问题。对它应该位于的位置进行快速的二进制搜索。然后,通过从较高和较低的数字中减去并获得abs,您可以轻松地确定它更接近哪个数字。然后,您可以轻松地决定添加到哪个数字

您可以通过获取数字的日志基数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;
    }
#包括
#包括
#包括
常数std::数组幂=
{

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

但是,如果你想在一般情况下即时计算,你可以很容易地计算任意数的2的周围幂

#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;
#包括
(...)
双底、上、数、指数;
number=1234;//设置number的值
指数=int(log(number)/log(2.0));//int(10.2691)=10
底部=功率(2,指数);//2^10=1024
顶部=底部*2;//2048
//计算数字、顶部和底部之间的差值,然后进行加减运算
//1相应地
数字=(顶部-数字)<(底部-数字)?数字+1:数字-1;

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

但是,如果你想在一般情况下即时计算,你可以很容易地计算任意数的2的周围幂

#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;
#包括
(...)
双底、上、数、指数;
number=1234;//设置number的值
指数=int(log(number)/log(2.0));//int(10.2691)=10
底部=功率(2,指数);//2^10=1024
顶部=底部*2;//2048
//计算数字、顶部和底部之间的差值,然后进行加减运算
//1相应地
数字=(顶部-数字)<(底部-数字)?数字+1:数字-1;

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


如果((x&(x>>1))>(x>>2))x+=1;否则x-=1;

如果设置了第二个最高有效位,则进行加法,否则进行减法

如果((x&(x>>1))>(x>>2))x+=1;否则x-=1;

表示最近的(不是最大的或相等的)-请参见:

#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;
}

有关最近的(不是最大的或相等的)-请参见:

#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;
}


因此,对于我的用例,即使整数也不改变。检查我的代码,它包含日志索引的解决方案,我将使第一个函数成为constexpr,但您得到了要点,所以对于我的用例,即使整数也不改变。检查我的代码,它包含日志索引的解决方案之一,我将使第一个函数成为一个constexpr,但你得到了点好吧,我想这实际上是非常聪明的;)谢谢。在我最终找到它之前,我有一些错误的开始。我认为在编译时创建一个向量在技术上可能会更快,只是说你可以使用你的技巧生成计算向量OK我想这其实很聪明;)谢谢。在我最终弄明白之前,我有过一些错误的开始。我认为在编译时创建向量在技术上可能会更快,只是说你可以使用你的技巧来生成向量