动态整数将是0到150之间的任何数字.
即 - 数字返回41,需要返回50.如果数字是10则需要返回10.数字是1需要返回10.
如果我将整数修改为小数,我以为我可以使用天花板功能......?然后使用天花板功能,并回到十进制?
唯一的事情也是必须知道这个数字是1,2或3位数(即-7 vs 94 vs 136)
有没有更好的方法来实现这一目标?
谢谢,
R S*_*hko 84
n + (10 - n % 10)
Run Code Online (Sandbox Code Playgroud)
这是如何工作的.%运算符计算除法的其余部分(因此41 % 10计算结果为1,而45 % 10计算结果为5).从10个评估中减去您需要多少到达下一个倍数.
唯一的问题是,这将把40变为50.如果你不想这样,你需要添加一个检查,以确保它不是10的倍数.
if (n % 10)
n = n + (10 - n % 10);
Run Code Online (Sandbox Code Playgroud)
AnT*_*AnT 40
你可以通过整数除以10 舍入,然后将结果乘以10来做到这一点.
要划分A由B四舍五入,添加B - 1到A,然后把它B用"普通"的整数除法
Q = (A + B - 1) / B
Run Code Online (Sandbox Code Playgroud)
因此,对于您的具体问题,同时在一起的事情将如下所示
A = (A + 9) / 10 * 10
Run Code Online (Sandbox Code Playgroud)
这将"捕捉" A到下一个10的倍数.
分裂和对齐的需要经常出现,通常在我的程序中,我有用于将[unsigned]整数除以四舍五入的宏
#define UDIV_UP(a, b) (((a) + (b) - 1) / (b))
Run Code Online (Sandbox Code Playgroud)
并用于将整数与下一个边界对齐
#define ALIGN_UP(a, b) (UDIV_UP(a, b) * (b))
Run Code Online (Sandbox Code Playgroud)
这将使上述看起来像
A = ALIGN_UP(A, 10);
Run Code Online (Sandbox Code Playgroud)
PS我不知道你是否需要扩展到负数.如果这样做,应该注意正确地做,取决于你需要的结果.
bta*_*bta 24
怎么样((n + 9) / 10) * 10?
收率0 => 0,1 => 10,8 => 10,29 => 30,30 => 30,31 => 40
Pet*_*des 10
tl; dr:((n + 9) / 10) * 10在更多情况下编译为最好的(最快的)asm代码,并且易于阅读和理解知道C中整数除法的人.这是一个相当常见的习语.
我还没有研究什么是需要使用负面效果的最佳选项n,因为您可能希望从零开始,而不是仍然朝向+ Infinity,具体取决于应用程序.
看看不同建议所使用的C操作,最轻量级的是Mark Dickinson(评论中):
(n+9) - ((n+9)%10)
Run Code Online (Sandbox Code Playgroud)
它看起来比几个人(包括@bta)建议的直接除法/乘法更有效:((n + 9) / 10) * 10因为它只有一个加法而不是乘法.(n+9是一个常见的子表达式,只需要计算一次.)
事实证明,两者都编译为字面上完全相同的代码,使用将除法转换为常数转换为乘法和移位的编译技巧,请参阅此Q&A了解其工作原理.与div使用商,余数或两者结果的成本相同的硬件指令不同,mul/shift方法需要额外的步骤来获得余数.因此编译器看到它可以从更便宜的计算得到相同的结果,并最终将两个函数编译为相同的代码.
这在x86,ppc和ARM以及我在Godbolt编译器资源管理器上看到的所有其他架构都是如此.在这个答案的第一个版本中,我看到了sdiv针对%10ARM64的Godbolt的gcc4.8,但是它已经不再安装了(也许是因为配置错误了?)ARM64 gcc5.4没有这样做.
Godbolt现在安装了MSVC(CL),其中一些函数编译方式不同,但我没有花时间看看哪个编译更好.
请注意,在x86的gcc输出中,乘以10便宜lea eax, [rdx + rdx*4]地完成n*5,然后add eax,eax将其加倍. imul eax, edx, 10在英特尔Haswell上会有1个周期更高的延迟,但要更短(少一个uop).gcc/clang甚至不使用它-Os -mtune=haswell:/
接受的答案(n + 10 - n % 10)甚至更便宜计算:n+10可以与之并行发生n%10,因此依赖链缩短了一步.它编译为少一条指令.
但是,它给出了10的倍数的错误答案:例如10 -> 20.建议的修复程序使用a if(n%10)来决定是否执行任何操作.这编译成a cmov,所以它比@ Bta的代码更长,更糟.如果您打算使用条件,请执行以获得负面输入的合理结果.
以下是所有建议答案的行为方式,包括负输入:
./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
Run Code Online (Sandbox Code Playgroud)
(转置awk程序)
Ignacio n + (((9 - (n % 10)) + 1) % 10)对于负整数"正确"工作,向+ Infinity四舍五入,但计算成本要高得多.它需要两个模运算,因此它的成本基本上是原来的两倍.它编译的x86指令大约是其两倍,其工作量大约是其他表达式的两倍.
结果打印程序(与上面的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));
}
Run Code Online (Sandbox Code Playgroud)
如何使用整数数学:
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
Run Code Online (Sandbox Code Playgroud)