如何将整数四舍五入到最接近的整数倍?

时间:2019-05-02 21:37:17

标签: c rounding

我正在尝试将整数四舍五入为数字的最接近倍数。

说数字等于80

是否有比x -= (x % the_number)更有效的方法?

这是一个例子:

#include <stdio.h>

int main(void)
{
        int x = 191;
        int the_number = 80;
        printf("x == %d\n", x);
        x -= (x % the_number);
        printf("x - (x %% the_number) == %d\n", x);
        return 0;
}

这是另一个例子。它不是一个像以前的那样可以完全正常工作的程序,但是我想做的更清楚:

#define LIGHT_GRAY 0x0700
#define COLUMNS 80

void pm_putchar(int c, void **ptr)
{
        c &= 0xff;
        c |= LIGHT_GRAY;

        if(c == '\n' | LIGHT_GRAY)
                *ptr += COLUMNS;
        else if(c == '\r' | LIGHT_GRAY)
                *ptr -= (*ptr % COLUMNS);

        **(short **)ptr = (short)c;
        (*ptr) += 2;
}

在上面的示例中,假设*ptr等于或高于VGA文本缓冲区(0x0b8000)的位置。

4 个答案:

答案 0 :(得分:3)

好吧,如果您仅尝试使用整数除数(您要除以的数字),总会有storeData,但是这是否更好取决于您。但是,我不知道有什么更好的方法,但是您也许可以重新定位this thread上的某些答案。

答案 1 :(得分:3)

  

我正在尝试将整数四舍五入为数字的最接近倍数。   [...]   是否有比x -= (x % the_number)更有效的方法?

在一般情况下,不会。有效率相似的替代方案,例如

x = (x / the_number) * the_number

,但是您不会用少于两个算术运算来做到这一点。 (在某些体系结构上,-的效率也比*高,并且/%的效率通常差不多)。

但是,如果您要截断到2的先进进阶幂,则可以通过使用单个按位&来掩盖低阶位来做到这一点。例如,要截断到最接近的16的较低倍数(== 0x10),您可以编写

x &= ~0xf;  // truncate an int x to a multiple of 16

答案 2 :(得分:2)

只有一种检查方法:

int r1(int r, const int n)
{
    return r -= (r % n);
}

int r2(int r, const int n)
{
    return (r / n) * n;
}

和生成的代码

r1:
        mov     eax, edi
        cdq
        idiv    esi
        mov     eax, edi
        sub     eax, edx
        ret
r2:
        mov     eax, edi
        cdq
        idiv    esi
        imul    eax, esi
        ret

div / mul方法的指令较少,但考虑到延迟和执行时间,imul可能会更慢。

答案 3 :(得分:0)

如果您怀疑该值可能是2的幂,则检查单个除数并使用移位和掩码处理mod是值得的。少数比特的收益递减,但可能值得。

if (!(b & (b-1))) {
    x = a & (b-1);
} else {
    x = a % b;
}

我对CPU不能简化这种简单情况感到惊讶,它在随机的64位mod上似乎是4-5倍。