C语言 如何找到任何整数的下一个 10 的倍数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2403631/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:46:39  来源:igfitidea点击:

How do I find the next multiple of 10 of any integer?

calgorithmmath

提问by T.T.T.

Dynamic integer will be any number from 0 to 150.

动态整数可以是 0 到 150 之间的任何数字。

i.e. - number returns 41, need to return 50. If number is 10 need to return 10. Number is 1 need to return 10.

即-number返回41,需要返回50。如果number为10需要返回10,number为1需要返回10。

Was thinking I could use the ceiling function if I modify the integer as a decimal...? then use ceiling function, and put back to decimal?
Only thing is would also have to know if the number is 1, 2 or 3 digits (i.e. - 7 vs 94 vs 136)

是否认为如果我将整数修改为小数,我可以使用天花板函数......?然后使用天花板函数,并放回十进制?
唯一的问题是还必须知道数字是 1、2 还是 3 位数字(即 - 7 vs 94 vs 136)

Is there a better way to achieve this?

有没有更好的方法来实现这一目标?

Thank You,

谢谢你,

回答by R Samuel Klatchko

n + (10 - n % 10)

How this works. The % operator evaluates to the remainder of the division (so 41 % 10evaluates to 1, while 45 % 10evaluates to 5). Subtracting that from 10 evaluates to how much how much you need to reach the next multiple.

这是如何工作的。% 运算符计算为除法的余数(因此41 % 10计算为 1,而45 % 10计算为 5)。从 10 中减去它的计算结果是达到下一个倍数需要多少。

The only issue is that this will turn 40 into 50. If you don't want that, you would need to add a check to make sure it's not already a multiple of 10.

唯一的问题是这会将 40 变成 50。如果您不想要那样,您需要添加一个检查以确保它不是 10 的倍数。

if (n % 10)
    n = n + (10 - n % 10);

回答by AnT

You can do this by performing integer division by 10 rounding up, and then multiplying the result by 10.

您可以通过将整数除以 10向上舍入,然后将结果乘以 10 来实现。

To divide Aby Brounding up, add B - 1to Aand then divide it by Busing "ordinary" integer division

AB四舍五入,添加B - 1A,然后把它B用“普通”的整数除法

Q = (A + B - 1) / B 

So, for your specific problem the while thing together will look as follows

因此,对于您的特定问题,while 的内容将如下所示

A = (A + 9) / 10 * 10

This will "snap" Ato the next greater multiple of 10.

这将“捕捉”A到下一个更大的 10 倍数。

The need for the division and for the alignment comes up so often that normally in my programs I'd have macros for dividing [unsigned] integers with rounding up

除法和对齐的需要经常出现,以至于通常在我的程序中,我会使用宏来将 [无符号] 整数除以四舍五入

#define UDIV_UP(a, b) (((a) + (b) - 1) / (b))

and for aligning an integer to the next boundary

并将整数与下一个边界对齐

#define ALIGN_UP(a, b) (UDIV_UP(a, b) * (b))

which would make the above look as

这将使上面看起来像

A = ALIGN_UP(A, 10);

P.S. I don't know whether you need this extended to negative numbers. If you do, care should be taken to do it properly, depending on what you need as the result.

PS我不知道您是否需要将其扩展为负数。如果您这样做,则应注意正确地执行此操作,具体取决于您需要的结果。

回答by bta

What about ((n + 9) / 10) * 10?

怎么样((n + 9) / 10) * 10

Yields 0 => 0, 1 => 10, 8 => 10, 29 => 30, 30 => 30, 31 => 40

产量 0 => 0, 1 => 10, 8 => 10, 29 => 30, 30 => 30, 31 => 40

回答by Peter Cordes

tl;dr: ((n + 9) / 10) * 10compiles to the nicest (fastest) asm code in more cases, and is easy to read and understand for people that know what integer division does in C. It's a fairly common idiom.

tl;dr:((n + 9) / 10) * 10在更多情况下编译为最好(最快)的 asm 代码,对于知道 C 中整数除法的人来说很容易阅读和理解。这是一个相当常见的习语。

I haven't investigated what the best option is for something that needs to work with negative n, since you might want to round away from zero, instead of still towards +Infinity, depending on the application.

我还没有调查需要使用负数的最佳选择是什么n,因为您可能希望从零舍入,而不是仍然向 +Infinity 舍入,具体取决于应用程序。



Looking at the C operations used by the different suggestions, the most light-weight is Mark Dickinson's (in comments):

查看不同建议使用的 C 操作,最轻量的是 Mark Dickinson 的(在评论中):

(n+9) - ((n+9)%10)

It looks more efficient than the straightforward divide / multiply suggested by a couple people (including @bta): ((n + 9) / 10) * 10, because it just has an add instead of a multiply. (n+9is a common subexpression that only has to be computed once.)

它看起来比几个人(包括@bta)建议的简单的除法/乘法更有效:((n + 9) / 10) * 10因为它只有加法而不是乘法。(n+9是一个公共子表达式,只需计算一次。)

It turns out that both compile to literally identical code, using the compiler trick of converting division by a constantinto a multiply and shift, see this Q&A for how it works. Unlike a hardware divinstruction that costs the same whether you use the quotient, remainder, or both results, the mul/shift method takes extra steps to get the remainder. So the compiler see that it can get the same result from a cheaper calculation, and ends up compiling both functions to the same code.

事实证明,两者都编译为字面上相同的代码,使用编译器技巧将除以常数转换为乘法和移位,请参阅此问答以了解其工作原理。与div无论使用商、余数还是同时使用两者结果的成本都相同的硬件指令不同,mul/shift 方法需要额外的步骤来获得余数。所以编译器看到它可以从更便宜的计算中得到相同的结果,并最终将两个函数编译为相同的代码。

This is true on x86, ppc, and ARM, and all the other architectures I've looked at on the Godbolt compiler explorer. In the first version of this answer, I saw an sdivfor the %10on Godbolt's gcc4.8 for ARM64, but it's no longer installed (perhaps because it was misconfigured?) ARM64 gcc5.4 doesn't do that.

x86、ppc 和 ARM以及我在 Godbolt 编译器资源管理器上查看的所有其他架构上都是如此。在这个答案的第一个版本,我看到了sdiv%10上Godbolt的gcc4.8为ARM64,但它不再安装(可能是因为它是配置错误?)ARM64 gcc5.4没有做到这一点。

Godbolt has MSVC (CL) installed now, and some of these functions compile differently, but I haven't taken the time to see which compile better.

Godbolt 现在安装了 MSVC (CL),其中一些函数的编译方式不同,但我还没有花时间看看哪个编译器更好。



Note that in the gcc output for x86, multiply by 10 is done cheaply with lea eax, [rdx + rdx*4]to do n*5, then add eax,eaxto double that. imul eax, edx, 10would have 1 cycle higher latency on Intel Haswell, but be shorter (one less uop). gcc / clang don't use it even with -Os -mtune=haswell:/

请注意,在 x86 的 gcc 输出中,乘以 10 可以很便宜lea eax, [rdx + rdx*4]地完成 n*5,然后add eax,eax将其加倍。 imul eax, edx, 10在 Intel Haswell 上会有 1 个周期的延迟,但会更短(少一个 uop)。gcc / clang 甚至不要使用它-Os -mtune=haswell:/



The accepted answer (n + 10 - n % 10) is even cheaper to compute: n+10can happen in parallel with n%10, so the dependency chain is one step shorter. It compiles to one fewer instruction.

接受的答案 ( n + 10 - n % 10) 的计算成本甚至更低:n+10可以与 并行发生n%10,因此依赖链缩短了一步。它编译为少一条指令。

However, it gives the wrong answer for multiples of 10: e.g. 10 -> 20. The suggested fix uses an if(n%10)to decide whether to do anything. This compiles into a cmov, so it's longer and worse than @Bta's code. If you're going to use a conditional, do it to get sane results for negative inputs.

但是,它给出了 10 的倍数的错误答案:例如10 -> 20。建议的修复使用if(n%10)来决定是否执行任何操作。这会编译成cmov,所以它比@Bta 的代码更长更糟。如果您要使用条件,请执行此操作以获得负输入的合理结果。



Here's how all the suggested answers behave, including for negative inputs:

以下是所有建议答案的行为方式,包括否定输入

./a.out | awk -v fmt='\t%4s' '{ for(i=1;i<=NF;i++){ a[i]=a[i] sprintf(fmt, $i); } } END { for (i in a) print a[i]; }'
       i     -22     -21     -20     -19     -18     -12     -11     -10      -9      -8      -2      -1       0       1       2       8       9      10      11      12         18      19      20      21      22
    mark     -10     -10     -10     -10       0       0       0       0       0       0       0       0       0      10      10      10      10      10      20      20         20      20      20      30      30
    igna     -10     -10     -10       0       0       0       0       0      10      10      10      10      10      10      10      10      10      20      20      20         20      20      30      30      30
    utaal    -20     -20     -20     -10     -10     -10     -10     -10       0       0       0       0       0      10      10      10      10      10      20      20         20      20      20      30      30
     bta     -10     -10     -10     -10       0       0       0       0       0      10      10      10      10      10      10      10      10      10      20      20         20      20      20      30      30
    klatchko -10     -10     -10     -10       0       0       0       0       0       0       0       0       0      10      10      10      10      10      20      20         20      20      20      30      30
    branch   -10     -10     -20       0       0       0       0     -10      10      10      10      10       0      10      10      10      10      10      20      20         20      20      20      30      30

(transpose awk program)

转置awk程序

Ignacio's n + (((9 - (n % 10)) + 1) % 10)works "correctly" for negative integers, rounding towards +Infinity, but is much more expensive to compute. It requires two modulo operations, so it's essentially twice as expensive. It compiles to about twice as many x86 instructions, doing about twice the work of the other expressions.

Ignacio'sn + (((9 - (n % 10)) + 1) % 10)对负整数“正确”工作,向 +Infinity 四舍五入,但计算成本要高得多。它需要两次模运算,所以它的成本基本上是它的两倍。它编译为大约两倍的 x86 指令,执行其他表达式大约两倍的工作。

Result-printing program (same as the godbolt links above)

结果打印程序(与上面的godbolt链接相同)

#include <stdio.h>
#include <stdlib.h>

int f_mark(int n) { return (n+9) - ((n+9)%10); }                   // good
int f_bta(int n) { return ((n + 9) / 10) * 10; }                   // compiles to literally identical code

int f_klatchko(int n) { return n + 10 - n % 10; }                  // wrong, needs a branch to avoid changing multiples of 10
int f_ignacio(int n) { return n + (((9 - (n % 10)) + 1) % 10); }   // slow, but works for negative
int roundup10_utaal(int n) {  return ((n - 1) / 10 + 1) * 10; }

int f_branch(int n) { if (n % 10) n += (10 - n % 10); return n; }  // gcc uses cmov after f_accepted code

int main(int argc, char**argv)
{
    puts("i\tmark\tigna\tutaal\tbta\tklatch\tbranch");
    for (int i=-25 ; i<25 ; i++)
    if (abs(i%10) <= 2 || 10 - abs(i%10) <= 2)  // only sample near interesting points
        printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\n", i, f_mark(i), f_accepted(i),
           f_ignacio(i), roundup10_utaal(i), f_bta(i), f_branch(i));
}

回答by Harvey

How about using integer math:

如何使用整数数学:

N=41
N+=9   // Add 9 first to ensure rounding.
N/=10  // Drops the ones place
N*=10  // Puts the ones place back with a zero

回答by Utaal

in C, one-liner:

C 中单行

int inline roundup10(int n) {
  return ((n - 1) / 10 + 1) * 10;
}

回答by Jive Dadson

Be aware that answers based on the div and mod operators ("/" and "%") will not work for negative numbers without an if-test, because C and C++ implement those operators incorrectly for negative numbers. (-3 mod 5) is 2, but C and C++ calculate (-3 % 5) as -3.

请注意,基于 div 和 mod 运算符(“/”和“%”)的答案在没有 if-test 的情况下不适用于负数,因为 C 和 C++ 错误地为负数实现了这些运算符。(-3 mod 5) 是 2,但 C 和 C++ 计算 (-3 % 5) 为 -3。

You can define your own div and mod functions. For example,

您可以定义自己的 div 和 mod 函数。例如,

int mod(int x, int y) {
  // Assert y > 0
  int ret = x % y;
  if(ret < 0) {
    ret += y;
  }
  return ret;
}

回答by Alex

You could do the number mod 10. Then take that result subtract it from ten. Then add that result to the original.

您可以对数字进行模数 10。然后将结果从 10 中减去。然后将该结果添加到原始结果中。

if N%10 != 0  #added to account for multiples of ten 
  a=N%10
  N+=10-a

回答by Ignacio Vazquez-Abrams

n + (((9 - (n % 10)) + 1) % 10)

回答by e2-e4

int n,res;
...

res = n%10 ? n+10-(n%10) : n;

or

或者

res = (n / 10)*10 + ((n % 10) ? 10:0);