From 35d06ac10ca9ddb970c1355b3a44c362917a872f Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser <kaspar@schleiser.de> Date: Thu, 8 Oct 2015 13:44:47 +0200 Subject: [PATCH] sys: add header for integer division using multiplication / shifts --- sys/include/div.h | 112 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 sys/include/div.h diff --git a/sys/include/div.h b/sys/include/div.h new file mode 100644 index 0000000000..3b83aad628 --- /dev/null +++ b/sys/include/div.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de> + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @brief Provides integer division functions + * + * This header provides some integer division functions that can be used + * to prevent linking in compiler-generated ones, which are often larger. + * + * @file + * @ingroup sys_util + * @author Kaspar Schleiser <kaspar@schleiser.de> + * @{ + */ + +#ifndef DIV_H +#define DIV_H + +#include <assert.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Integer divide val by 15625 + * + * @pre val <= 16383999997 + * + * @param[in] val dividend + * @return (val / 15625) + */ +static inline uint64_t div_u64_by_15625(uint64_t val) +{ + /* a higher value would overflow 2^64 in the multiplication that follows */ + assert(val <= 16383999997LLU); + + return (val * 0x431bde83UL) >> (12 + 32); +} + +/** + * @brief Integer divide val by 1000000 + * + * @pre val <= 1048575999808 + * + * @param[in] val dividend + * @return (val / 1000000) + */ +static inline uint64_t div_u64_by_1000000(uint64_t val) +{ + /* a higher value would overflow 2^64 in the multiplication that follows */ + assert(val <= 1048575999808LLU); + + return div_u64_by_15625(val>>6); +} + +/** + * @brief Divide val by (15625/512) + * + * This is used to quantize a 1MHz value to the closest 32768Hz value, + * e.g., for timers. + * + * The algorithm actually multiplies by 512 first, then divides by 15625, + * keeping the result closer to a floored floating point division. + * + * @param[in] val dividend + * @return (val / (15625/512)) + */ +static inline uint32_t div_u32_by_15625div512(uint32_t val) +{ + return ((uint64_t)(val) * 0x431bde83ul) >> (12 + 32 - 9); +} + +/** + * @brief Integer divide val by 10 + * + * @param[in] n dividend + * @return (n / 10) + */ +static inline uint32_t div_u32_by_10(uint32_t n) { + uint32_t q, r; + q = (n >> 1) + (n >> 2); + q = q + (q >> 4); + q = q + (q >> 8); + q = q + (q >> 16); + q = q >> 3; + r = n - (((q << 2) + q) << 1); + return q + (r > 9); +} + +/** + * @brief Modulo 10 + * + * @param[in] n dividend + * @return (n % 10) + */ +static inline uint32_t div_u32_mod_10(uint32_t n) +{ + return n - (div_u32_by_10(n)*10); +} + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif /* DIV_H */ -- GitLab