2021 年 5 月 2 日更新:
下面我原始答案中的代码仅适用于 正 整数。要处理负整数的正确舍入,请参阅我的项目 repo 中的技术:https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/tree/master/c/rounding_integer_division。主文件:rounding_integer_division.cpp.
它包含:
- 这些 C 或 C++ 宏:
DIVIDE_ROUNDUP(numer, denom)
DIVIDE_ROUNDDOWN(numer, denom)
DIVIDE_ROUNDNEAREST(numer, denom)
- 这些 gcc/clang C 或 C++ 语句表达式(比宏更安全):
DIVIDE_ROUNDUP2(numer, denom)
DIVIDE_ROUNDDOWN2(numer, denom)
DIVIDE_ROUNDNEAREST2(numer, denom)
- 这些 C++ 模板:
template <typename T>
T divide_roundup(T numer, T denom)
template <typename T>
T divide_rounddown(T numer, T denom)
template <typename T>
T divide_roundnearest(T numer, T denom)
- 一堆单元测试来测试以上所有内容。
原始答案:
TLDR:这是一个宏;使用它!
// To do (numer/denom), rounded to the nearest whole integer, use:
#define ROUND_DIVIDE(numer, denom) (((numer) + (denom) / 2) / (denom))
使用示例:
int num = ROUND_DIVIDE(13,7); // 13/7 = 1.857 --> rounds to 2, so num is 2
完整答案:
其中一些答案看起来很疯狂!不过,Codeface 搞定了! (参见@0xC0DEFACE 的answer here)。我真的很喜欢函数形式的无类型宏或 gcc 语句表达式形式,但是,所以,我写了这个答案,详细解释了我在做什么(即:为什么这在数学上有效)并将其放入 2 种形式:
1。宏观形式,用详细的注释来解释整个事情:
/// @brief ROUND_DIVIDE(numerator/denominator): round to the nearest whole integer when doing
/// *integer* division only
/// @details This works on *integers only* since it assumes integer truncation will take place automatically
/// during the division!
/// @notes The concept is this: add 1/2 to any number to get it to round to the nearest whole integer
/// after integer trunction.
/// Examples: 2.74 + 0.5 = 3.24 --> 3 when truncated
/// 2.99 + 0.5 = 3.49 --> 3 when truncated
/// 2.50 + 0.5 = 3.00 --> 3 when truncated
/// 2.49 + 0.5 = 2.99 --> 2 when truncated
/// 2.00 + 0.5 = 2.50 --> 2 when truncated
/// 1.75 + 0.5 = 2.25 --> 2 when truncated
/// To add 1/2 in integer terms, you must do it *before* the division. This is achieved by
/// adding 1/2*denominator, which is (denominator/2), to the numerator before the division.
/// ie: `rounded_division = (numer + denom/2)/denom`.
/// ==Proof==: 1/2 is the same as (denom/2)/denom. Therefore, (numer/denom) + 1/2 becomes
/// (numer/denom) + (denom/2)/denom. They have a common denominator, so combine terms and you get:
/// (numer + denom/2)/denom, which is the answer above.
/// @param[in] numerator any integer type numerator; ex: uint8_t, uint16_t, uint32_t, int8_t, int16_t, int32_t, etc
/// @param[in] denominator any integer type denominator; ex: uint8_t, uint16_t, uint32_t, int8_t, int16_t, int32_t, etc
/// @return The result of the (numerator/denominator) division rounded to the nearest *whole integer*!
#define ROUND_DIVIDE(numerator, denominator) (((numerator) + (denominator) / 2) / (denominator))
见a little more on gcc statement expressions here。
/// @brief *gcc statement expression* form of the above macro
#define ROUND_DIVIDE2(numerator, denominator) \
({ \
__typeof__ (numerator) numerator_ = (numerator); \
__typeof__ (denominator) denominator_ = (denominator); \
numerator_ + (denominator_ / 2) / denominator_; \
})
3。 C++函数模板形式:
(2020 年 3 月/4 月添加)
#include <limits>
// Template form for C++ (with type checking to ensure only integer types are passed in!)
template <typename T>
T round_division(T numerator, T denominator)
{
// Ensure only integer types are passed in, as this round division technique does NOT work on
// floating point types since it assumes integer truncation will take place automatically
// during the division!
// - The following static assert allows all integer types, including their various `const`,
// `volatile`, and `const volatile` variations, but prohibits any floating point type
// such as `float`, `double`, and `long double`.
// - Reference page: https://en.cppreference.com/w/cpp/types/numeric_limits/is_integer
static_assert(std::numeric_limits<T>::is_integer, "Only integer types are allowed");
return (numerator + denominator/2)/denominator;
}
在这里运行和测试其中的一些代码:
- OnlineGDB: integer rounding during division
相关答案:
-
Fixed Point Arithmetic in C Programming - 在这个答案中,我讨论了如何将 整数舍入 到最接近的整数,然后是第十位(小数点右侧的 1 个小数位),百位(2 个小数位) ,千位(3 个十进制数字)等。在我的代码 cmets 中搜索名为
BASE 2 CONCEPT: 的部分的答案以获取更多详细信息!
- 我对 gcc 语句表达式的相关回答:MIN and MAX in C
- this 固定类型的函数形式:Rounding integer division (instead of truncating)
- What is the behavior of integer division?
- 要向上舍入而不是最接近的整数,请遵循类似的模式:Rounding integer division (instead of truncating)
参考资料:
- https://www.tutorialspoint.com/cplusplus/cpp_templates.htm
todo:测试这个是否有负面输入,如果可行,请更新这个答案:
#define ROUND_DIVIDE(numer, denom) ((numer < 0) != (denom < 0) ? ((numer) - (denom) / 2) / (denom) : ((numer) + (denom) / 2) / (denom))