Last active
May 24, 2017 00:46
-
-
Save johnmcfarlane/3123b5cfbf27f82d47bfabae6a33dcb9 to your computer and use it in GitHub Desktop.
example of zero-cost abstraction using the fixed_point library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Signed 15:16 Fixed-Point Square Function Using sg14::elastic | |
// Here's how to use the fixed_point library on Godbolt.org. | |
// Normally, you'd just add `#include <sg14/fixed_point>`. | |
#define SG14_GODBOLT_ORG | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/bits/config.h> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/bits/config.h> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/cstdint> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/limits> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/type_traits> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/bits/common.h> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/bits/fixed_point_type.h> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/bits/fixed_point_arithmetic.h> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/bits/fixed_point_make.h> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/bits/fixed_point_named.h> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/bits/fixed_point_common_type.h> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/bits/fixed_point_operators.h> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/bits/fixed_point_extras.h> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/auxiliary/elastic_integer.h> | |
#include <https://raw.githubusercontent.com/johnmcfarlane/fixed_point/develop/include/sg14/auxiliary/elastic.h> | |
using namespace sg14; | |
// average two nunbers using 15:16 fixed-point arithmetic | |
// without using a fixed-point library | |
float average_int(float input1, float input2) { | |
// user must scale values by the correct amount | |
auto fixed1 = static_cast<int32_t>(input1 * 65536.f); | |
auto fixed2 = static_cast<int32_t>(input2 * 65536.f); | |
// user must remember to widen the result to avoid overflow | |
auto sum = int64_t{fixed1} + fixed2; | |
// at least division is simple | |
auto avg = sum / 2; | |
// user must return value to the original scale | |
return avg / 65536.f; | |
} | |
// the same function using sg14::elastic_integer | |
float average_elastic_integer(float input1, float input2) { | |
auto fixed1 = elastic_integer<31>{input1 * 65536.f}; | |
auto fixed2 = elastic_integer<31>{input2 * 65536.f}; | |
// elastic_integer automatically widens the result | |
auto sum = fixed1 + fixed2; | |
// showing off: to store 2, you only need a 2-bit integer | |
auto avg = sum / elastic_integer<2>{2}; | |
// but the user must still do all the scaling themselves | |
return static_cast<float>(avg) / 65536.f; | |
} | |
// the same function using sg14::fixed_point | |
float average_fixed_point(float input1, float input2) { | |
// fixed_point handles scaling | |
auto fixed1 = fixed_point<int32_t, -16>{input1}; | |
auto fixed2 = fixed_point<int32_t, -16>{input2}; | |
// but it uses int under the hood; user must still widen | |
auto sum = fixed_point<int64_t, -16>{fixed1} + fixed2; | |
// specal function 'divide' is used when we | |
// want to perform integer division on a real number | |
auto avg = divide(sum, 2); | |
return static_cast<float>(avg); | |
} | |
// finally, the composition of fixed_point and elastic_integer | |
float average_elastic(float input1, float input2) { | |
// alias to fixed_point<elastic_integer<31, int>, -16> | |
auto elastic1 = elastic<15, 16>{input1}; | |
auto elastic2 = elastic<15, 16>{input2}; | |
// concise, safe and zero-cost! | |
auto sum = elastic1 + elastic2; | |
auto avg = sum / elastic<2>{2}; | |
return static_cast<float>(avg); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hmm... this doesn't work for me, even after fixing line 20 to include elastic_fixed_point.h instead of elastic.h: https://godbolt.org/g/N04hY7