| /* |
| * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) |
| * |
| * SPDX-License-Identifier: BSD-2-Clause |
| */ |
| |
| #pragma once |
| |
| /* macros for doing basic math */ |
| |
| #include <stdint.h> |
| |
| /* This function can be used to calculate ((a * b) / c) without causing |
| * overflow by doing (a * b). It also allows you to avoid loss of precision |
| * if you attempte to rearrange the algorithm to (a * (c / b)) |
| * It is essentially the Ancient Egyption Multiplication |
| * with (a * (b / c)) but we keep (b / c) in quotient+remainder |
| * form to not lose precision. |
| * This function only works with unsigned 64bit types. It can be |
| * trivially abstracted to other sizes. Dealing with signed is possible |
| * but not included here */ |
| static inline uint64_t muldivu64(uint64_t a, uint64_t b, uint64_t c) |
| { |
| /* quotient and remainder of the final calculation */ |
| uint64_t quotient = 0; |
| uint64_t remainder = 0; |
| /* running quotient and remainder of the current power of two |
| * bit we are looking at. As we look at the different bits |
| * of a we will increase these */ |
| uint64_t cur_quotient = b / c; |
| uint64_t cur_remainder = b % c; |
| /* we will iterate through all the bits of a from least to most |
| * significant, we can stop early once there are no set bits though */ |
| while (a) { |
| /* If this bit is set then the power of two is part of the |
| * construction of a */ |
| if (a & 1) { |
| /* increase final quotient, taking care of any remainder */ |
| quotient += cur_quotient; |
| remainder += cur_remainder; |
| if (remainder >= c) { |
| quotient++; |
| remainder -= c; |
| } |
| } |
| /* Go to the next bit of a. Also means the effective quotient |
| * and remainder of our (b / c) needs increasing */ |
| a >>= 1; |
| cur_quotient <<= 1; |
| cur_remainder <<= 1; |
| /* Keep the remainder sensible, otherewise the remainder check |
| * in the if (a & 1) case has to become a loop */ |
| if (cur_remainder >= c) { |
| cur_quotient++; |
| cur_remainder -= c; |
| } |
| } |
| return quotient; |
| } |