[英]Rounding integer to nearest multiple of another integer
我需要將整數舍入為另一個整數的最接近的倍數。 在100的倍數的情況下結果的示例:
等等。
我提出了以下代碼,它有效,但感覺“臟”:
int RoundToMultiple(int toRound, int multiple)
{
return (toRound + (multiple / 2)) / multiple * multiple;
}
這依賴於整數除法的截斷屬性以使其起作用。 我可以指望這個代碼是可移植的嗎? 是否有任何編譯器設置,這將無法給我所需的結果? 如果有,我怎樣才能以便攜方式獲得相同的結果?
如果需要更好的答案,可以假設倍數將是10的冪(包括1的倍數)。 數字也可以假設都是正數。
是的,您可以指望此代碼可移植。 N4296 (這是C ++ 14的最新公開草案)在第5.6節[expr.mul]中說:
對於積分操作數,/運算符產生代數商,丟棄任何小數部分。 [腳注:這通常被稱為截斷為零]
這不是最新C ++的新功能,它也可以在C89中使用。
唯一需要注意的是,如果toRound
為負數 ,則需要減去偏移量。
另一種方法是:
int RoundToMultiple(int toRound, int multiple)
{
const auto ratio = static_cast<double>(toRound) / multiple;
const auto iratio = std::lround(ratio);
return iratio * multiple;
}
這樣可以避免凌亂的+/-偏移,但性能會更差,如果toRound
太大而無法精確地保持雙倍,則會出現問題。 (OTOH,如果這是輸出,那么我懷疑在這種情況下multiple
同樣大,所以你會沒事的。)
C ++標准明確地指定了整數除法的行為:
[expr.mul]
對於積分操作數,/運算符產生代數商,丟棄任何小數部分。
Aka截斷為零。 這是便攜式的。
雖然 - 正如其他人所說 - 積分除法的行為與你期望的一樣,但可能是以下解決方案看起來“不那么有線”(仍然基於意見)。
關於將int轉換為double的解決方案:我個人覺得這只是為了四舍五入而昂貴,但也許有人可以說服我,我的感覺是錯的;
無論如何,通過僅使用整數運算符,以下解決方案討論了double
的尾數是否總能保持每個int
多余:
int RoundToMultiple(int toRound, int multiple) {
toRound += multiple / 2;
return toRound - (toRound%multiple);
}
如果您還想包含負值,則可以按如下方式稍微調整代碼(包括測試):
#include <stdio.h>
int RoundToMultiple(int toRound, int multiple) {
toRound += toRound < 0 ? -multiple / 2 : multiple / 2;
return toRound - (toRound%multiple);
}
int main(int argc, char const *argv[])
{
int tests[] = { 36,99,123,164,-36,-99,-123,-164,0 };
int expectedResults[] = { 0,100,100,200,0,-100,-100,-200,0 };
int i=0;
int test=0, result=0, expectedResult=0;
do {
test = tests[i];
result = RoundToMultiple(test, 100);
expectedResult = expectedResults[i];
printf("test %d: %d==%d ? %s\n", test, result, expectedResult, (expectedResult==result ? "OK" : "NOK!"));
i++;
}
while(test != 0);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.