├── extras ├── Hello.txt ├── Credits.md ├── Important.txt └── AFixedPointPrimer.md ├── library.properties ├── library.json ├── .github ├── PULL_REQUEST_TEMPLATE │ └── pull_request_template.md └── ISSUE_TEMPLATE │ ├── feature-request.md │ └── bug-report.md ├── src ├── FixedPoints.h ├── FixedPointsCommon.h ├── FixedPointsCommon │ ├── FixedPointsCommon.h │ ├── UFixedCommon.h │ └── SFixedCommon.h └── FixedPoints │ ├── FixedPoints.h │ ├── Details.h │ ├── Utils.h │ ├── UFixed.h │ ├── SFixed.h │ ├── UFixedMemberFunctions.h │ ├── SFixedMemberFunctions.h │ ├── SFixedFreeFunctions.h │ └── UFixedFreeFunctions.h ├── keywords.txt ├── examples └── FixedPointCalculations │ └── FixedPointCalculations.ino ├── README.md └── LICENCE /extras/Hello.txt: -------------------------------------------------------------------------------- 1 | 2 | /\___/\ ~ 3 | ( O . O ) \\ 4 | > ^ < // 5 | ( \ / )// 6 | u U U u 7 | 8 | ヘロー エブリニャン! 9 | -------------------------------------------------------------------------------- /extras/Credits.md: -------------------------------------------------------------------------------- 1 | ## Main Credits: 2 | 3 | - [Pharap](https://github.com/Pharap) - main programmer 4 | 5 | ## Extra special thanks to: 6 | 7 | - [bakagamedev](https://github.com/bakagamedev) - extra-handy duck 8 | - [filmote](https://github.com/filmote) - testing and debugging 9 | - [eried](https://github.com/eried) - testing and debugging 10 | 11 | ## Special mentions: 12 | 13 | - crait 14 | - Bergasms 15 | -------------------------------------------------------------------------------- /extras/Important.txt: -------------------------------------------------------------------------------- 1 | Do not attempt to use anything from the Details namespace. 2 | Everything in the Details namespace is merely an implementation detail which may be changed without notice, 3 | thus any attempt to use anything from the Details namespace may result in your own code breaking in future updates. 4 | 5 | To wrap the fixed point types in the FixedPoints namespace (e.g. in case of name conflicts): 6 | #define FIXED_POINTS_USE_NAMESPACE -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=FixedPoints 2 | version=1.1.2 3 | author=Pharap 4 | maintainer=Pharap 5 | sentence=A template library for defining fixed point types of varying sizes. 6 | paragraph=The library is designed to be generic so it should be applicable to almost all size requirements and processor architectures. 7 | category=Data Processing 8 | url=https://github.com/Pharap/FixedPointsArduino 9 | architectures=* 10 | includes=FixedPoints.h, FixedPointsCommon.h 11 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FixedPoints", 3 | "description": "A templated header-only fixed point arithmetic library aimed at Arduino", 4 | "keywords": "maths, fixed, point, fixed point, arithmetic", 5 | "authors": 6 | { 7 | "name": "Pharap", 8 | "url": "https://github.com/Pharap" 9 | }, 10 | "repository": 11 | { 12 | "type": "git", 13 | "url": "https://github.com/Pharap/FixedPointsArduino.git" 14 | }, 15 | "license": "Apache-2.0", 16 | "version": "1.1.2", 17 | "frameworks": "arduino" 18 | } -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/pull_request_template.md: -------------------------------------------------------------------------------- 1 | **Important** 2 | 3 | _Please do not create a pull request unless you have created an appropriate issue, discussed the issue with the authors/maintainers and received the explicit approval of the library's authors/maintainers to provide a bug fix or feature implementation._ 4 | 5 | _Creating pull requests without adequately discussing the situation with the authors/maintainers is likely to get your pull request closed._ 6 | 7 | _This rule is in place to ensure that all issues are properly discussed, evaluated and agreed upon._ 8 | -------------------------------------------------------------------------------- /src/FixedPoints.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "FixedPoints/FixedPoints.h" -------------------------------------------------------------------------------- /src/FixedPointsCommon.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "FixedPointsCommon/FixedPointsCommon.h" -------------------------------------------------------------------------------- /src/FixedPointsCommon/FixedPointsCommon.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "../FixedPoints.h" 16 | 17 | #include "SFixedCommon.h" 18 | #include "UFixedCommon.h" -------------------------------------------------------------------------------- /src/FixedPoints/FixedPoints.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "Details.h" 16 | 17 | #include "UFixed.h" 18 | #include "SFixed.h" 19 | 20 | #include "Utils.h" -------------------------------------------------------------------------------- /src/FixedPointsCommon/UFixedCommon.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "../FixedPoints.h" 18 | 19 | FIXED_POINTS_BEGIN_NAMESPACE 20 | using UQ4x4 = UFixed<4, 4>; 21 | using UQ8x8 = UFixed<8, 8>; 22 | using UQ16x16 = UFixed<16, 16>; 23 | using UQ32x32 = UFixed<32, 32>; 24 | 25 | using UQ1x7 = UFixed<1, 7>; 26 | using UQ1x15 = UFixed<1, 15>; 27 | using UQ1x31 = UFixed<1, 31>; 28 | using UQ1x63 = UFixed<1, 63>; 29 | FIXED_POINTS_END_NAMESPACE -------------------------------------------------------------------------------- /src/FixedPointsCommon/SFixedCommon.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "../FixedPoints.h" 18 | 19 | FIXED_POINTS_BEGIN_NAMESPACE 20 | using SQ3x4 = SFixed<3, 4>; 21 | using SQ7x8 = SFixed<7, 8>; 22 | using SQ15x16 = SFixed<15, 16>; 23 | using SQ31x32 = SFixed<31, 32>; 24 | 25 | using SQ1x6 = SFixed<1, 6>; 26 | using SQ1x14 = SFixed<1, 14>; 27 | using SQ1x30 = SFixed<1, 30>; 28 | using SQ1x62 = SFixed<1, 62>; 29 | FIXED_POINTS_END_NAMESPACE 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: The standard template for a feature request 4 | title: 'Add this specified feature' 5 | labels: 'Feature Request' 6 | assignees: Pharap 7 | 8 | --- 9 | 10 | _Please ensure that the title of your issue begins with a capitalised imperative verb, such as 'Add'._ 11 | 12 | _Delete and replace any italicised text and instructions before submitting._ 13 | _You may also delete a section heading when instructed to delete a section._ 14 | 15 | **Proposed Feature** 16 | 17 | _Provide an explanation of your proposed feature._ 18 | 19 | **Use Case** 20 | 21 | _Provide an explanation of one or more situations in which your proposed feature would be beneficial._ 22 | 23 | **Problem** 24 | 25 | _If your proposed feature solves one or more specific problems, provide an explanation of the problem or problems than it solves. Otherwise, delete this section._ 26 | 27 | **Justification** 28 | 29 | _If your proposed feature entails a specific implementation of a solution to a problem, please provide an explanation of why your proposed solution is the most suitable solution. Otherwise, delete this section._ 30 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | 2 | #################################### 3 | # Syntax Colouring For FixedPoints # 4 | #################################### 5 | 6 | #################################### 7 | # Datatypes (KEYWORD1) # 8 | #################################### 9 | 10 | SFixed KEYWORD1 11 | UFixed KEYWORD1 12 | UQ4x4 KEYWORD1 13 | UQ8x8 KEYWORD1 14 | UQ16x16 KEYWORD1 15 | UQ32x32 KEYWORD1 16 | UQ1x7 KEYWORD1 17 | UQ1x15 KEYWORD1 18 | UQ1x31 KEYWORD1 19 | UQ1x63 KEYWORD1 20 | SQ3x4 KEYWORD1 21 | SQ7x8 KEYWORD1 22 | SQ15x16 KEYWORD1 23 | SQ31x32 KEYWORD1 24 | SQ1x6 KEYWORD1 25 | SQ1x14 KEYWORD1 26 | SQ1x30 KEYWORD1 27 | SQ1x62 KEYWORD1 28 | 29 | #################################### 30 | # Methods and Functions (KEYWORD2) # 31 | #################################### 32 | 33 | getInternal KEYWORD2 34 | getInteger KEYWORD2 35 | getFraction KEYWORD2 36 | fromInternal KEYWORD2 37 | multiply KEYWORD2 38 | floorFixed KEYWORD2 39 | ceilFixed KEYWORD2 40 | roundFixed KEYWORD2 41 | truncFixed KEYWORD2 42 | signbitFixed KEYWORD2 43 | absFixed KEYWORD2 44 | copysignFixed KEYWORD2 45 | nextafterFixed KEYWORD2 46 | randomUFixed KEYWORD2 47 | randomSFixed KEYWORD2 48 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: The standard template for a bug report 4 | title: 'Problem with ...' 5 | labels: 'Bug Report' 6 | assignees: Pharap 7 | 8 | --- 9 | 10 | _Delete and replace any italicised text and instructions before submitting._ 11 | _You may also delete a section heading when instructed to delete a section._ 12 | 13 | **Brief Description** 14 | 15 | _Provide a brief summary of the problem._ 16 | 17 | **Observed Behaviour** 18 | 19 | _Provide a description of what behaviour you observed._ 20 | 21 | **Expected Behaviour** 22 | 23 | _Provide a description of what behaviour you expected._ 24 | 25 | **Compiler Error** 26 | 27 | _If the bug results in a compile time error, provide the full text of any relevant compiler errors as reported by the compiler. Otherwise delete this section._ 28 | 29 | **Source Code** 30 | 31 | _Provide some source code demonstrating the issue, preferably as a concise stand-alone `.ino` file._ 32 | 33 | _Alternatively if the issue was exhibited by a complex program and the issue cannot be isolated, provide a link to a repository hosting said program. This link should ideally link to a precise commit snapshot rather than to a branch or repo because a commit snapshot won't change if more commits are added and won't break if branches are deleted._ 34 | 35 | **Extra Information** 36 | 37 | _Fill in the relevant information fields. Please be as precise as possible._ 38 | 39 | * Target Board: _Arduino Uno R3_ 40 | * Compiler Version: _avr-g++ 5.4.0_ 41 | * Arduino IDE Version: _1.8.13_ 42 | * OS: _Windows 10_ 43 | -------------------------------------------------------------------------------- /extras/AFixedPointPrimer.md: -------------------------------------------------------------------------------- 1 | # A Fixed Point Primer 2 | 3 | ## What Are Fixed Point Numbers? 4 | 5 | Normally computers operate on what are called 'integers'. 6 | Integers are numbers that do not have a fractional component in them. 7 | For example 0, 1, 42, 128, 10000 are all integers 8 | 9 | Numbers that do have a fractional component are called 'rational' numbers. 10 | They are often represented either as fractions or as numbers with a 'radix point' in them (often called a 'decimal point' in day-to-day maths). 11 | For example 0.5, 1.75, 42.42, 128.367 and 10000.00001 are all rational numbers. 12 | 13 | Normally computers represent these in what is called a 'floating point' format. 14 | The name 'floating point' refers to the fact that the radix point can change position within the number, i.e. the radix point can 'float' around. 15 | 16 | Another way to represent real numbers is what is called a 'fixed point' format. 17 | The name 'fixed point' refers to the fact that the radix point does not change position within the number, i.e. it is 'fixed' in place. 18 | This means that the range of numbers that can be represented by a fixed point is much more limited in terms of scale (how large or small the numbers can be). 19 | 20 | ## Why Use Fixed Point Numbers? 21 | 22 | To allow the ability to move the radix point, the most common floating point formats are quite complicated and typically need special hardware or lots of complicated functions to implement them. 23 | 24 | Almost all modern CPUs have floating point capabilities built into them. 25 | However many CPUs intended for use in embedded systems do not have this capability built in because it is not always needed and it is often cheaper to leave it out. 26 | 27 | This is where fixed points come in. 28 | 29 | By limiting the format so that the radix point is fixed in place, the implementation of fixed point numbers becomes a lot simpler. 30 | 31 | In fact for the most basic operations, addition and subtraction, the operations are exactly the same as they are for integers. Some of the more complicated operations like multiplication and division are very similar and merely involve a bit of bit shifting to adjust the results. 32 | 33 | This means that even the simplest of CPUs can use fixed point numbers without any special hardware support. As long as they support integer and bit shifting operations, they can support fixed point numbers. 34 | 35 | ## Why Aren't Fixed Point Numbers Used More Often? 36 | 37 | Fixed point numbers have fallen out of favour because modern CPUs tend to come with floating point support as standard. The wide range of support for floating points and the sheer dominance of the IEEE 754 floating point format means that for most cases using floating points to perform operations on real numbers is preferred. 38 | 39 | Even if a particular application could be sped up by switching to fixed points, there are many reasons why people tend not to choose this option, not least because of the lack of awareness of fixed point numbers and because of the lack of available fixed point libraries. 40 | 41 | Indeed, finding information about fixed point numbers can be quite a struggle. 42 | 43 | ## How Do Fixed Points Work? 44 | 45 | Fixed point numbers are comprised of two parts, the integer part and the fractional part. 46 | Each part takes up a set number of bits. For example, a common format (often called `Q8.8`) has `8` bits for the integer part and 8 bits for the fractional part. 47 | 48 | The integer part stores the digits to the left of the radix point. 49 | This part behaves exactly like a regular integer and for all intents and purposes can be imagined as one. If you understand how computers represent integers, you already understand the integer part. 50 | 51 | For example, in the `Q8.8` format, there are `8` bits in the integer part, thus it is capable of holding `256` values. The values are `0` to `255` when unsigned or `-128` to `127` when signed and in two's complement format. 52 | 53 | The fractional part stores the digits to the right of the radix point. 54 | This part has special behaviour that can be a bit tricky to comprehend at first. 55 | The simplest way to think of it is as a fraction. 56 | 57 | For example in the `Q8.8` format, there are `8` bits for the fractional part, which means it is capable of holding `256` values. 58 | When thought of as a fraction, the fractional part is treated as an unsigned integer, meaning it can hold values of `0` to `255`. This integer is then imagined as the numerator of a fraction in which the denominator is the number of possible values that can be held, i.e. `256`. 59 | 60 | If the fractional part had the integer value of `64`, then its effective value can be represented as `64/256`, which would be equivalent to the decimal value of `0.25`. 61 | 62 | As a more in depth example, consider a Q8.8 value where the integer part is `5` and the fractional part has an integer value of `37`. This can be thought of as a mixed fraction `5 37/256`. 63 | Using a calculator to divide `37` by `256` you will find that `37/256 = 0.14453125`, which means that the number being represented is `5.14453125`. 64 | 65 | ## Further Reading 66 | 67 | - Wikipedia's article about [Radix Points](https://en.wikipedia.org/wiki/Radix_point) 68 | - Wikipedia's article about [Integers](https://en.wikipedia.org/wiki/Integer) 69 | - Wikipedia's article about [Rational Numbers](https://en.wikipedia.org/wiki/Rational_number) 70 | -------------------------------------------------------------------------------- /examples/FixedPointCalculations/FixedPointCalculations.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void TestUQ8x8(void) 5 | { 6 | Serial.println(F("The size of UQ8x8 on your system is:")); 7 | Serial.println(sizeof(UQ8x8)); 8 | Serial.println(); 9 | 10 | UQ8x8 a = 1.5; 11 | Serial.println(F("Displaying a as float:")); 12 | Serial.println(static_cast(a)); 13 | Serial.println(); 14 | 15 | Serial.println(F("Displaying the integer part of a")); 16 | Serial.println(a.getInteger()); 17 | Serial.println(); 18 | 19 | Serial.println(F("Displaying floorFixed(a):")); 20 | Serial.println(static_cast(floorFixed(a))); 21 | Serial.println(); 22 | 23 | Serial.println(F("Displaying ceilFixed(a):")); 24 | Serial.println(static_cast(ceilFixed(a))); 25 | Serial.println(); 26 | 27 | Serial.println(F("Displaying roundFixed(a):")); 28 | Serial.println(static_cast(roundFixed(a))); 29 | Serial.println(); 30 | 31 | Serial.println(F("Displaying truncFixed(a):")); 32 | Serial.println(static_cast(truncFixed(a))); 33 | Serial.println(); 34 | 35 | UQ8x8 b = 5.25; 36 | Serial.println(F("Displaying b as float:")); 37 | Serial.println(static_cast(b)); 38 | Serial.println(); 39 | 40 | Serial.println(F("Displaying the integer part of b")); 41 | Serial.println(b.getInteger()); 42 | Serial.println(); 43 | 44 | Serial.println(F("Displaying floorFixed(b):")); 45 | Serial.println(static_cast(floorFixed(b))); 46 | Serial.println(); 47 | 48 | Serial.println(F("Displaying ceilFixed(b):")); 49 | Serial.println(static_cast(ceilFixed(b))); 50 | Serial.println(); 51 | 52 | Serial.println(F("Displaying roundFixed(b):")); 53 | Serial.println(static_cast(roundFixed(b))); 54 | Serial.println(); 55 | 56 | Serial.println(F("Displaying truncFixed(b):")); 57 | Serial.println(static_cast(truncFixed(b))); 58 | Serial.println(); 59 | 60 | Serial.println(F("Displaying a + b as float:")); 61 | Serial.println(static_cast(a + b)); 62 | Serial.println(); 63 | 64 | Serial.println(F("Displaying a - b as float:")); 65 | Serial.println(F("(Note the underflow due lack of sign bit)")); 66 | Serial.println(static_cast(a - b)); 67 | Serial.println(); 68 | 69 | Serial.println(F("Displaying b - a as float:")); 70 | Serial.println(static_cast(b - a)); 71 | Serial.println(); 72 | 73 | Serial.println(F("Displaying a * b as float:")); 74 | Serial.println(static_cast(a * b)); 75 | Serial.println(); 76 | 77 | Serial.println(F("Displaying a / b as float:")); 78 | Serial.println(static_cast(a / b)); 79 | Serial.println(); 80 | } 81 | 82 | void TestSQ7x8(void) 83 | { 84 | Serial.println(F("The size of SQ7x8 on your system is:")); 85 | Serial.println(sizeof(SQ7x8)); 86 | Serial.println(); 87 | 88 | SQ7x8 a = 1.5; 89 | Serial.println(F("Displaying a as float:")); 90 | Serial.println(static_cast(a)); 91 | Serial.println(); 92 | 93 | Serial.println(F("Displaying the integer part of a")); 94 | Serial.println(a.getInteger()); 95 | Serial.println(); 96 | 97 | Serial.println(F("Displaying floorFixed(a):")); 98 | Serial.println(static_cast(floorFixed(a))); 99 | Serial.println(); 100 | 101 | Serial.println(F("Displaying ceilFixed(a):")); 102 | Serial.println(static_cast(ceilFixed(a))); 103 | Serial.println(); 104 | 105 | Serial.println(F("Displaying roundFixed(a):")); 106 | Serial.println(static_cast(roundFixed(a))); 107 | Serial.println(); 108 | 109 | Serial.println(F("Displaying truncFixed(a):")); 110 | Serial.println(static_cast(truncFixed(a))); 111 | Serial.println(); 112 | 113 | SQ7x8 b = 5.25; 114 | Serial.println(F("Displaying b as float:")); 115 | Serial.println(static_cast(b)); 116 | Serial.println(); 117 | 118 | Serial.println(F("Displaying the integer part of b")); 119 | Serial.println(b.getInteger()); 120 | Serial.println(); 121 | 122 | Serial.println(F("Displaying floorFixed(b):")); 123 | Serial.println(static_cast(floorFixed(b))); 124 | Serial.println(); 125 | 126 | Serial.println(F("Displaying ceilFixed(b):")); 127 | Serial.println(static_cast(ceilFixed(b))); 128 | Serial.println(); 129 | 130 | Serial.println(F("Displaying roundFixed(b):")); 131 | Serial.println(static_cast(roundFixed(b))); 132 | Serial.println(); 133 | 134 | Serial.println(F("Displaying truncFixed(b):")); 135 | Serial.println(static_cast(truncFixed(b))); 136 | Serial.println(); 137 | 138 | Serial.println(F("Displaying a + b as float:")); 139 | Serial.println(static_cast(a + b)); 140 | Serial.println(); 141 | 142 | Serial.println(F("Displaying a - b as float:")); 143 | Serial.println(F("(Note this is correct due to sign bit)")); 144 | Serial.println(static_cast(a - b)); 145 | Serial.println(); 146 | 147 | Serial.println(F("Displaying b - a as float:")); 148 | Serial.println(static_cast(b - a)); 149 | Serial.println(); 150 | 151 | Serial.println(F("Displaying a * b as float:")); 152 | Serial.println(static_cast(a * b)); 153 | Serial.println(); 154 | 155 | Serial.println(F("Displaying a / b as float:")); 156 | Serial.println(static_cast(a / b)); 157 | Serial.println(); 158 | } 159 | 160 | void setup() 161 | { 162 | Serial.begin(9600); 163 | while(!Serial); 164 | 165 | TestUQ8x8(); 166 | TestSQ7x8(); 167 | } 168 | 169 | void loop() 170 | { 171 | } 172 | -------------------------------------------------------------------------------- /src/FixedPoints/Details.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #if defined(FIXED_POINTS_USE_NAMESPACE) 22 | #define FIXED_POINTS_NAMESPACE FixedPoints 23 | #define FIXED_POINTS_BEGIN_NAMESPACE namespace FIXED_POINTS_NAMESPACE\ 24 | { 25 | #define FIXED_POINTS_END_NAMESPACE } 26 | #define FIXED_POINTS_DETAILS Details 27 | #else 28 | #define FIXED_POINTS_NAMESPACE 29 | #define FIXED_POINTS_BEGIN_NAMESPACE 30 | #define FIXED_POINTS_END_NAMESPACE 31 | #define FIXED_POINTS_DETAILS FixedPointsDetails 32 | #endif 33 | 34 | #if !defined(__AVR__) 35 | #define FIXED_POINTS_NO_RANDOM 36 | #endif 37 | 38 | // Pay no attention to the man behind the curtains 39 | 40 | FIXED_POINTS_BEGIN_NAMESPACE 41 | namespace FIXED_POINTS_DETAILS 42 | { 43 | template< typename T > 44 | struct BitSize 45 | { 46 | BitSize() = delete; 47 | static constexpr auto Value = sizeof(T) * CHAR_BIT; 48 | }; 49 | 50 | template< bool Condition, typename TTrue, typename TFalse > 51 | struct Conditional; 52 | 53 | template< typename TTrue, typename TFalse > 54 | struct Conditional< true, TTrue, TFalse > { using Type = TTrue; }; 55 | 56 | template< typename TTrue, typename TFalse > 57 | struct Conditional< false, TTrue, TFalse > { using Type = TFalse; }; 58 | 59 | template< bool Condition, typename TTrue, typename TFalse > 60 | using ConditionalT = typename Conditional::Type; 61 | 62 | template< typename T, typename U > 63 | using LargerType = ConditionalT<(BitSize::Value > BitSize::Value), T, U>; 64 | 65 | template< typename T, typename U > 66 | using StrictLargerType = ConditionalT< (BitSize::Value > BitSize::Value), T, ConditionalT< (BitSize::Value > BitSize::Value), U, void > >; 67 | 68 | template< typename T, typename U > 69 | using SmallerType = ConditionalT<(BitSize::Value < BitSize::Value), T, U>; 70 | 71 | template< typename T, typename U > 72 | using StrictSmallerType = ConditionalT< (BitSize::Value < BitSize::Value), T, ConditionalT< (BitSize::Value < BitSize::Value), U, void > >; 73 | 74 | template< unsigned Bits, typename... Ts > 75 | struct LeastTypeHelper; 76 | 77 | template< unsigned Bits, typename T, typename... Ts > 78 | struct LeastTypeHelper 79 | { 80 | LeastTypeHelper() = delete; 81 | using Type = ConditionalT<(Bits <= BitSize::Value), T, typename LeastTypeHelper::Type>; 82 | }; 83 | 84 | template< unsigned Bits > 85 | struct LeastTypeHelper 86 | { 87 | LeastTypeHelper() = delete; 88 | using Type = void; 89 | }; 90 | 91 | 92 | template< unsigned Bits, typename... Ts > 93 | using LeastType = typename LeastTypeHelper::Type; 94 | 95 | template< unsigned Bits > 96 | struct LeastUIntDef 97 | { 98 | static_assert(Bits <= BitSize::Value, "No type large enough"); 99 | LeastUIntDef() = delete; 100 | using Type = LeastType; 101 | }; 102 | 103 | 104 | template< unsigned Bits > 105 | using LeastUInt = typename LeastUIntDef::Type; 106 | 107 | template< unsigned Bits > 108 | struct LeastIntDef 109 | { 110 | static_assert(Bits <= BitSize::Value, "No type large enough"); 111 | LeastIntDef() = delete; 112 | using Type = LeastType; 113 | }; 114 | 115 | template< unsigned Bits > 116 | using LeastInt = typename LeastIntDef::Type; 117 | 118 | template< unsigned Bits > 119 | struct MsbMask 120 | { 121 | MsbMask() = delete; 122 | static constexpr LeastUInt Value = (1ull << (Bits - 1)); 123 | }; 124 | 125 | template< unsigned Bits > 126 | struct IdentityMask 127 | { 128 | IdentityMask() = delete; 129 | static constexpr LeastUInt Value = 1 | (static_cast>(IdentityMask::Value) << 1); 130 | }; 131 | 132 | template<> 133 | struct IdentityMask<0> 134 | { 135 | IdentityMask() = delete; 136 | static constexpr LeastUInt<0> Value = 0; 137 | }; 138 | 139 | #if !defined(FIXED_POINTS_NO_RANDOM) 140 | template< typename T > 141 | struct RandomHelper; 142 | 143 | template<> 144 | struct RandomHelper 145 | { 146 | static inline uint8_t Random() { return static_cast(random()); } 147 | }; 148 | 149 | template<> 150 | struct RandomHelper 151 | { 152 | static inline uint16_t Random() { return static_cast(random()); } 153 | }; 154 | 155 | template<> 156 | struct RandomHelper 157 | { 158 | static inline uint32_t Random() { return static_cast(random()); } 159 | }; 160 | 161 | template<> 162 | struct RandomHelper 163 | { 164 | static inline uint64_t Random() { return (static_cast(random()) << 32) | static_cast(random()); } 165 | }; 166 | 167 | template<> 168 | struct RandomHelper 169 | { 170 | static inline int8_t Random() { return static_cast(random()); } 171 | }; 172 | 173 | template<> 174 | struct RandomHelper 175 | { 176 | static inline int16_t Random() { return static_cast(random()); } 177 | }; 178 | 179 | template<> 180 | struct RandomHelper 181 | { 182 | static inline int32_t Random() { return static_cast(random()); } 183 | }; 184 | 185 | template<> 186 | struct RandomHelper 187 | { 188 | static inline int64_t Random() { return (static_cast(random()) << 32) | static_cast(random()); } 189 | }; 190 | #endif 191 | 192 | /////////////////////// 193 | // Here be dragons!! // 194 | // // 195 | // /\___/\ _ // 196 | // ( O . O ) \\ // 197 | // > ^ < // // 198 | // ( \ / )// // 199 | // u U U u // 200 | // // 201 | // Or cats?... // 202 | // ~Mwrow~ // 203 | /////////////////////// 204 | } 205 | FIXED_POINTS_END_NAMESPACE 206 | -------------------------------------------------------------------------------- /src/FixedPoints/Utils.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "Details.h" 18 | #include "UFixed.h" 19 | #include "SFixed.h" 20 | 21 | // 22 | // Declaration 23 | // 24 | 25 | FIXED_POINTS_BEGIN_NAMESPACE 26 | 27 | template< unsigned Integer, unsigned Fraction > 28 | constexpr UFixed floorFixed(const UFixed & value); 29 | 30 | template< unsigned Integer, unsigned Fraction > 31 | constexpr SFixed floorFixed(const SFixed & value); 32 | 33 | template< unsigned Integer, unsigned Fraction > 34 | constexpr UFixed ceilFixed(const UFixed & value); 35 | 36 | template< unsigned Integer, unsigned Fraction > 37 | constexpr SFixed ceilFixed(const SFixed & value); 38 | 39 | template< unsigned Integer, unsigned Fraction > 40 | constexpr UFixed roundFixed(const UFixed & value); 41 | 42 | template< unsigned Integer, unsigned Fraction > 43 | constexpr SFixed roundFixed(const SFixed & value); 44 | 45 | template< unsigned Integer, unsigned Fraction > 46 | constexpr bool signbitFixed(const SFixed & value); 47 | 48 | template< unsigned Integer, unsigned Fraction > 49 | constexpr SFixed absFixed(const SFixed & value); 50 | 51 | template< unsigned Integer, unsigned Fraction > 52 | constexpr SFixed copysignFixed(const SFixed & x, const SFixed & y); 53 | 54 | template< unsigned Integer, unsigned Fraction > 55 | constexpr SFixed nextafterFixed(const SFixed & from, const SFixed & to); 56 | 57 | template< unsigned Integer, unsigned Fraction > 58 | constexpr UFixed nextafterFixed(const UFixed & from, const UFixed & to); 59 | 60 | // 61 | // Unsigned Random 62 | // 63 | 64 | #if !defined(FIXED_POINTS_NO_RANDOM) 65 | template< unsigned Integer, unsigned Fraction > 66 | UFixed randomUFixed(); 67 | 68 | template< unsigned Integer, unsigned Fraction > 69 | UFixed randomUFixed(const UFixed & exclusiveUpperBound); 70 | 71 | template< unsigned Integer, unsigned Fraction > 72 | UFixed randomUFixed(const UFixed & inclusiveLowerBound, const UFixed & exclusiveUpperBound); 73 | #endif 74 | 75 | // 76 | // Signed Random 77 | // 78 | 79 | #if !defined(FIXED_POINTS_NO_RANDOM) 80 | template< unsigned Integer, unsigned Fraction > 81 | SFixed randomSFixed(); 82 | 83 | template< unsigned Integer, unsigned Fraction > 84 | SFixed randomSFixed(const SFixed & exclusiveUpperBound); 85 | 86 | template< unsigned Integer, unsigned Fraction > 87 | SFixed randomSFixed(const SFixed & inclusiveLowerBound, const SFixed & exclusiveUpperBound); 88 | #endif 89 | 90 | FIXED_POINTS_END_NAMESPACE 91 | 92 | // 93 | // Definition 94 | // 95 | 96 | FIXED_POINTS_BEGIN_NAMESPACE 97 | 98 | template< unsigned Integer, unsigned Fraction > 99 | constexpr UFixed floorFixed(const UFixed & value) 100 | { 101 | using OutputType = UFixed; 102 | using InternalType = typename OutputType::InternalType; 103 | return OutputType::fromInternal(static_cast(value.getInternal() & ~OutputType::FractionMask)); 104 | } 105 | 106 | template< unsigned Integer, unsigned Fraction > 107 | constexpr SFixed floorFixed(const SFixed & value) 108 | { 109 | using OutputType = SFixed; 110 | using InternalType = typename OutputType::InternalType; 111 | return OutputType::fromInternal(static_cast(value.getInternal() & ~OutputType::FractionMask)); 112 | } 113 | 114 | template< unsigned Integer, unsigned Fraction > 115 | constexpr UFixed ceilFixed(const UFixed & value) 116 | { 117 | return UFixed((value.getFraction() == 0) ? value.getInteger() : (value.getInteger() + 1), 0); 118 | } 119 | 120 | template< unsigned Integer, unsigned Fraction > 121 | constexpr SFixed ceilFixed(const SFixed & value) 122 | { 123 | return SFixed((value.getFraction() == 0) ? value.getInteger() : (value.getInteger() + 1), 0); 124 | } 125 | 126 | template< unsigned Integer, unsigned Fraction > 127 | constexpr UFixed roundFixed(const UFixed & value) 128 | { 129 | using OutputType = UFixed; 130 | return (value.getFraction() >= OutputType(0.5).getFraction()) ? ceilFixed(value) : floorFixed(value); 131 | } 132 | 133 | template< unsigned Integer, unsigned Fraction > 134 | constexpr SFixed roundFixed(const SFixed & value) 135 | { 136 | using OutputType = SFixed; 137 | return 138 | signbitFixed(value) ? 139 | ((value.getFraction() <= OutputType(0.5).getFraction()) ? floorFixed(value) : ceilFixed(value)) : 140 | ((value.getFraction() >= OutputType(0.5).getFraction()) ? ceilFixed(value) : floorFixed(value)); 141 | } 142 | 143 | template< unsigned Integer, unsigned Fraction > 144 | constexpr UFixed truncFixed(const UFixed & value) 145 | { 146 | return UFixed(value.getInteger(), 0); 147 | } 148 | 149 | template< unsigned Integer, unsigned Fraction > 150 | constexpr SFixed truncFixed(const SFixed & value) 151 | { 152 | using OutputType = SFixed; 153 | return 154 | (value.getInternal() < 0) ? 155 | OutputType::fromInternal(value.getInternal() & ~OutputType::FractionMask) + OutputType(1, 0) : 156 | OutputType::fromInternal(value.getInternal() & ~OutputType::FractionMask); 157 | } 158 | 159 | template< unsigned Integer, unsigned Fraction > 160 | constexpr bool signbitFixed(const SFixed & value) 161 | { 162 | return (value.getInternal() < 0); 163 | } 164 | 165 | template< unsigned Integer, unsigned Fraction > 166 | constexpr SFixed absFixed(const SFixed & value) 167 | { 168 | return (signbitFixed(value)) ? -value : value; 169 | } 170 | 171 | template< unsigned Integer, unsigned Fraction > 172 | constexpr SFixed copysignFixed(const SFixed & x, const SFixed & y) 173 | { 174 | return (signbitFixed(x) != signbitFixed(y)) ? -x : x; 175 | } 176 | 177 | template< unsigned Integer, unsigned Fraction > 178 | constexpr SFixed nextafterFixed(const SFixed & from, const SFixed & to) 179 | { 180 | using ResultType = SFixed; 181 | return 182 | (from < to) ? 183 | ResultType::fromInternal(from.getInternal() + 1) : 184 | (from > to) ? 185 | ResultType::fromInternal(from.getInternal() - 1) : 186 | to; 187 | } 188 | 189 | template< unsigned Integer, unsigned Fraction > 190 | constexpr UFixed nextafterFixed(const UFixed & from, const UFixed & to) 191 | { 192 | using ResultType = UFixed; 193 | return 194 | (from < to) ? 195 | ResultType::fromInternal(from.getInternal() + 1) : 196 | (from > to) ? 197 | ResultType::fromInternal(from.getInternal() - 1) : 198 | to; 199 | } 200 | 201 | // 202 | // Unsigned Random 203 | // 204 | 205 | #if !defined(FIXED_POINTS_NO_RANDOM) 206 | template< unsigned Integer, unsigned Fraction > 207 | UFixed randomUFixed() 208 | { 209 | using InternalType = typename UFixed::InternalType; 210 | return UFixed::fromInternal(FIXED_POINTS_DETAILS::RandomHelper::Random()); 211 | } 212 | 213 | template< unsigned Integer, unsigned Fraction > 214 | UFixed randomUFixed(const UFixed & exclusiveUpperBound) 215 | { 216 | using InternalType = typename UFixed::InternalType; 217 | return UFixed::fromInternal(FIXED_POINTS_DETAILS::RandomHelper::Random() % exclusiveUpperBound.getInternal()); 218 | } 219 | 220 | template< unsigned Integer, unsigned Fraction > 221 | UFixed randomUFixed(const UFixed & inclusiveLowerBound, const UFixed & exclusiveUpperBound) 222 | { 223 | using InternalType = typename UFixed::InternalType; 224 | return UFixed::fromInternal(inclusiveLowerBound.getInternal() + (FIXED_POINTS_DETAILS::RandomHelper::Random() % (exclusiveUpperBound.getInternal() - inclusiveLowerBound.getInternal()))); 225 | } 226 | #endif 227 | 228 | // 229 | // Signed Random 230 | // 231 | 232 | #if !defined(FIXED_POINTS_NO_RANDOM) 233 | template< unsigned Integer, unsigned Fraction > 234 | SFixed randomSFixed() 235 | { 236 | using InternalType = typename SFixed::InternalType; 237 | return SFixed::fromInternal(FIXED_POINTS_DETAILS::RandomHelper::Random()); 238 | } 239 | 240 | template< unsigned Integer, unsigned Fraction > 241 | SFixed randomSFixed(const SFixed & exclusiveUpperBound) 242 | { 243 | using InternalType = typename SFixed::InternalType; 244 | return SFixed::fromInternal(FIXED_POINTS_DETAILS::RandomHelper::Random() % exclusiveUpperBound.getInternal()); 245 | } 246 | 247 | template< unsigned Integer, unsigned Fraction > 248 | SFixed randomSFixed(const SFixed & inclusiveLowerBound, const SFixed & exclusiveUpperBound) 249 | { 250 | using InternalType = typename SFixed::InternalType; 251 | auto value = FIXED_POINTS_DETAILS::RandomHelper::Random(); 252 | return SFixed::fromInternal(inclusiveLowerBound.getInternal() + (abs(value) % (exclusiveUpperBound.getInternal() - inclusiveLowerBound.getInternal()))); 253 | } 254 | #endif 255 | 256 | FIXED_POINTS_END_NAMESPACE 257 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FixedPoints 2 | A portable fixed point arithmetic library. 3 | 4 | Some knowledge of how fixed point types are formatted is required to used this library to full effect. 5 | No knowledge of how these operations are implemented is required to use them. 6 | 7 | This library was written with Arduino in mind, as well as CPUs with limited floating point support. 8 | However, given the templated nature of the library, it should still function on a wide variety of CPUs. 9 | 10 | ## Project Showcase 11 | 12 | Here's a list of projects that use `FixedPoints`: 13 | 14 | * [1943](https://github.com/filmote/Nineteen43) for the [Arduboy](https://arduboy.com/) by [@filmote](https://github.com/filmote) 15 | * [XOD Powered Rechargeable Solar Lamp](http://www.instructables.com/id/XOD-powered-Rechargeable-Solar-Lamp/) by [Victorian DeLorean](http://www.instructables.com/member/Victorian%20DeLorean/) 16 | * [Pod Manager](https://github.com/felipemanga/PodManager) for the [Arduboy](https://arduboy.com/) by [@felipemanga](https://github.com/felipemanga) 17 | 18 | If you have a project that uses `FixedPoints` and would like your work to be showcased here, 19 | please [raise an issue](https://github.com/Pharap/FixedPointsArduino/issues/new). 20 | 21 | ## Requirements: 22 | 23 | - The Compiler must be C++11 compliant. 24 | - The user should ideally be familar with the [Q number format](https://en.wikipedia.org/wiki/Q_(number_format)) for fixed points. 25 | 26 | ## Licence 27 | 28 | This code uses the Apache 2.0 Licence. 29 | This means: 30 | 31 | - This code comes with _no warranty_. 32 | - The licensor and any contributors **cannot** be held liable for damages. 33 | - If you use this code, modified or unmodified: 34 | - You **must** package a copy of LICENCE with your code. 35 | - You **must** package a copy of NOTICE with your code. 36 | - You are not required to distribute the source code. 37 | - You **must not** use any trademarks owned by the licensor. 38 | - Unless you have specific permission to do so. 39 | - You **may** modify the source code. 40 | - If you modify the code, you **must** state this fact prominently within the source file. 41 | - E.g. in a comment at the top of the source file. 42 | - You are under no obligation to distribute the source code of your modifications. 43 | - You may incorporate any part of the code into another project. 44 | - That project **may** use a different licence. 45 | - That code **must** retain the Apache 2.0 licence notice, including the copyright notice. 46 | - If the code is modified, the modifications **may** be published under a different licence. 47 | - The Apache 2.0 licence still applies to unmodified portions. 48 | - The copyright and licence notices for the unmodified portions **must** still be prominently displayed. 49 | - It is advised that you do not do this, as it is highly unusual and untested in court. 50 | 51 | ## Conditional Compilation 52 | 53 | These are symbols you can define prior to library inclusion to alter the behaviour of the library. 54 | 55 | - `FIXED_POINTS_USE_NAMESPACE`: Define this to wrap all classes and functions in the namespace `FixedPoints`. Useful for preventing naming conflicts. 56 | - `FIXED_POINTS_NO_RANDOM`: Define this to disable the random utility functions. Useful for systems that don't have access to `long random(void)` from avr-libc. 57 | 58 | ## FAQ 59 | 60 | * Why can't I multiply `UQ32x32` or `SQ31x32` by another type? 61 | * Because it would require a 128-bit integer type to provide enough precision for accurate multiplication. 62 | 63 | ## Contents 64 | This library supplies two core types and sixteen type aliases. 65 | 66 | ### Defines 67 | 68 | - `FIXED_POINTS_NAMESPACE`: The namespace used by FixedPoints. This is empty unless `FIXED_POINTS_USE_NAMESPACE` is defined prior to inclusion. 69 | - `FIXED_POINTS_DETAILS`: An infrastructure macro that should not be used in user code. It is safe to undefine this if it is causing problems. 70 | - `FIXED_POINTS_BEGIN_NAMESPACE`: An infrastructure macro that should not be used in user code. It is safe to undefine this if it is causing problems. 71 | - `FIXED_POINTS_END_NAMESPACE`: An infrastructure macro that should not be used in user code. It is safe to undefine this if it is causing problems. 72 | 73 | ### Core Types: 74 | The core types are provided by `FixedPoints.h`. 75 | 76 | - `UFixed`: An unsigned fixed point type where I is the number of bits used for the integer part of the number and F is the number of bits used for the fractional part of the number. 77 | - `SFixed`: An signed fixed point type where I is the number of bits used for the integer part of the number (excluding the implicit sign bit) and F is the number of bits used for the fractional part of the number. 78 | 79 | ### Aliases: 80 | The common aliases are provided by `FixedPointsCommon.h`. 81 | 82 | - `UQ4x4`: An alias for `UFixed<4, 4>`, an 8-bit unsigned fixed point in the Q4.4 format. 83 | - `UQ8x8`: An alias for `UFixed<8, 8>`, a 16-bit unsigned fixed point in the Q8.8 format. 84 | - `UQ16x16`: An alias for `UFixed<16, 16>`, a 32-bit unsigned fixed point in the Q16.16 format. 85 | - `UQ32x32`: An alias for `UFixed<32, 32>`, a 64-bit unsigned fixed point in the Q32.32 format. 86 | - `UQ1x7`: An alias for `UFixed<1, 7>`, an 8-bit unsigned fixed point in the Q1.7 format. 87 | - `UQ1x15`: An alias for `UFixed<1, 15>`, a 16-bit unsigned fixed point in the Q1.15 format. 88 | - `UQ1x31`: An alias for `UFixed<1, 31>`, a 32-bit unsigned fixed point in the Q1.31 format. 89 | - `UQ1x63`: An alias for `UFixed<1, 63>`, a 64-bit unsigned fixed point in the Q1.63 format. 90 | - `SQ3x4`: An alias for `SFixed<3, 4>`, an 8-bit signed fixed point in the Q3.4 format with implicit sign bit. 91 | - `SQ7x8`: An alias for `SFixed<7, 8>`, a 16-bit signed fixed point in the Q7.8 format with implicit sign bit. 92 | - `SQ15x16`: An alias for `SFixed<15, 16>`, a 32-bit signed fixed point in the Q15.16 format with implicit sign bit. 93 | - `SQ31x32`: An alias for `SFixed<31, 32>`, a 64-bit signed fixed point in the Q31.32 format with implicit sign bit. 94 | - `SQ1x6`: An alias for `SFixed<1, 6>`, an 8-bit signed fixed point in the Q1.6 format with implicit sign bit. 95 | - `SQ1x14`: An alias for `SFixed<1, 14>`, a 16-bit signed fixed point in the Q1.14 format with implicit sign bit. 96 | - `SQ1x30`: An alias for `SFixed<1, 30>`, a 32-bit signed fixed point in the Q1.30 format with implicit sign bit. 97 | - `SQ1x62`: An alias for `SFixed<1, 62>`, a 64-bit signed fixed point in the Q1.62 format with implicit sign bit. 98 | 99 | ([About Q Format](https://en.wikipedia.org/wiki/Q_(number_format)).) 100 | 101 | ### Operators: 102 | 103 | - `+`: Adds two `UFixed`s or two `SFixed`s 104 | - `-`: Subtracts two `UFixed`s or two `SFixed`s 105 | - `*`: Multiplies two `UFixed`s or two `SFixed`s 106 | - `/`: Divides two `UFixed`s or two `SFixed`s 107 | - `==`: Compares two `UFixed`s or two `SFixed`s 108 | - `!=`: Compares two `UFixed`s or two `SFixed`s 109 | - `<`: Compares two `UFixed`s or two `SFixed`s 110 | - `<=`: Compares two `UFixed`s or two `SFixed`s 111 | - `>`: Compares two `UFixed`s or two `SFixed`s 112 | - `>=`: Compares two `UFixed`s or two `SFixed`s 113 | 114 | ### Free Functions: 115 | 116 | - `floorFixed`: The floor operation. 117 | - `ceilFixed`: The Ceiling operation 118 | - `roundFixed`: Rounding operation. 119 | - `truncFixed`: Truncation operation. 120 | - `signbitFixed`: Returns `true` for signed numbers and `false` for unsigned numbers. 121 | - `copysignFixed`: Returns a value with the magnitude of the first argument and the sign of the second argument. 122 | - `multiply`: Multiplies two `UFixed`s or two `SFixed`s, returns a result that is twice the resolution of the input. 123 | 124 | ### Member Functions: 125 | 126 | - `UFixed::getInteger`: Gets the integer part of an unsigned fixed point. 127 | - `UFixed::getFraction`: Gets the fractional part of an unsigned fixed point. 128 | - `UFixed::getInternal`: Gets the internal representation of an unsigned fixed point. 129 | 130 | - `SFixed::getInteger`: Gets the integer part of a signed fixed point. 131 | - `SFixed::getFraction`: Gets the fractional part of a signed fixed point. 132 | - `SFixed::getInternal`: Gets the internal representation of a signed fixed point. 133 | 134 | ### Static Functions: 135 | 136 | - `UFixed::fromInternal`: Produces an unsigned fixed point number from its internal representation. 137 | - `SFixed::fromInternal`: Produces a signed fixed point number from its internal representation. 138 | 139 | ## Construction: 140 | 141 | Note that both `UFixed` and `SFixed` are implicitly compile-time constructable from all integer and decimal literals. 142 | This means that you may write code such as `UFixed<8, 8> value = 0.5;` without incurring a runtime cost for converting from `double` to `UFixed<8, 8>` because the constructor is `constexpr`. 143 | 144 | `UFixed` is constructable from: 145 | - Any integer literal type, regardless of sign. 146 | -- This constructs the fixed point as an integer with no fractional part. 147 | -- A value that does not fit shall be truncated without warning. 148 | -- If a constant value is used, the fixed point shall be constructed at compile time. 149 | - An unsigned integer part and an unsigned fractional part. 150 | -- The integer part is of the smallest type capable of representing `I` bits. 151 | -- The fractional part is of the smallest type capable of representing `F` bits. 152 | -- If constant values are used, the fixed point shall be constructed at compile time. 153 | - Any decimal literal type, regardless of sign. 154 | -- This constructs the fixed point as a best approximation of the provided value. 155 | -- A value that does not fit shall be truncated without warning. 156 | -- If a constant value is used, the fixed point shall be constructed at compile time. 157 | 158 | `SFixed` is constructable from: 159 | - Any integer literal type, regardless of sign. 160 | -- This constructs the fixed point as an integer with no fractional part. 161 | -- A value that does not fit shall be truncated without warning. 162 | -- If a constant value is used, the fixed point shall be constructed at compile time. 163 | - A signed integer part and an unsigned fractional part. 164 | -- The integer part is of the smallest type capable of representing `I + 1` bits. 165 | -- The fractional part is of the smallest type capable of representing `F` bits. 166 | -- If constant values are used, the fixed point shall be constructed at compile time. 167 | - Any decimal literal type, regardless of sign. 168 | -- This constructs the fixed point as a best approximation of the provided value. 169 | -- A value that does not fit shall be truncated without warning. 170 | -- If a constant value is used, the fixed point shall be constructed at compile time. 171 | 172 | ### Casts: 173 | 174 | `UFixed` is explicitly convertible to: 175 | - `float`. 176 | - `double`. 177 | - The smallest unsigned type capable of holding its integer part. I.e. a type of at least `I` bits. 178 | - Another `UFixed` type of a different scale. E.g. `UFixed<4, 4>` may be converted to `UFixed<8, 8>` and vice versa. 179 | 180 | `SFixed` is explicitly convertible to: 181 | - `float`. 182 | - `double`. 183 | - The smallest signed type capable of holding its integer part. I.e. a type of at least `I + 1` bits. 184 | - Another `SFixed` type of a different scale. E.g. `SFixed<3, 4>` may be converted to `SFixed<7, 8>` and vice versa. 185 | 186 | 187 | -------------------------------------------------------------------------------- /src/FixedPoints/UFixed.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "Details.h" 18 | 19 | FIXED_POINTS_BEGIN_NAMESPACE 20 | 21 | // 22 | // Declaration 23 | // 24 | 25 | template< unsigned Integer, unsigned Fraction > 26 | class SFixed; 27 | 28 | template< unsigned Integer, unsigned Fraction > 29 | class UFixed 30 | { 31 | public: 32 | static constexpr uintmax_t IntegerSize = Integer; 33 | static constexpr uintmax_t FractionSize = Fraction; 34 | static constexpr uintmax_t LogicalSize = IntegerSize + FractionSize; 35 | static constexpr uintmax_t Scale = UINTMAX_C(1) << FractionSize; 36 | 37 | public: 38 | static_assert(LogicalSize <= FIXED_POINTS_DETAILS::BitSize::Value, "Platform does not have a native type large enough for UFixed."); 39 | 40 | public: 41 | using IntegerType = FIXED_POINTS_DETAILS::LeastUInt; 42 | using FractionType = FIXED_POINTS_DETAILS::LeastUInt; 43 | using InternalType = FIXED_POINTS_DETAILS::LeastUInt; 44 | 45 | static constexpr uintmax_t InternalSize = FIXED_POINTS_DETAILS::BitSize::Value; 46 | 47 | using ShiftType = FIXED_POINTS_DETAILS::LeastUInt; 48 | using MaskType = FIXED_POINTS_DETAILS::LeastUInt; 49 | 50 | public: 51 | static constexpr ShiftType IntegerShift = FractionSize; 52 | static constexpr ShiftType FractionShift = 0; 53 | 54 | static constexpr MaskType IntegerMask = FIXED_POINTS_DETAILS::IdentityMask::Value; 55 | static constexpr MaskType FractionMask = FIXED_POINTS_DETAILS::IdentityMask::Value; 56 | 57 | static constexpr MaskType IdentityMask = (IntegerMask << IntegerShift) | (FractionMask << FractionShift); 58 | 59 | static constexpr MaskType MidpointMask = FIXED_POINTS_DETAILS::MsbMask::Value; 60 | static constexpr MaskType LesserMidpointMask = MidpointMask - 1; 61 | 62 | protected: 63 | class RawType 64 | { 65 | private: 66 | const InternalType value; 67 | 68 | public: 69 | constexpr explicit RawType(const InternalType & value) : value(value) {} 70 | constexpr explicit operator InternalType() const { return this->value; } 71 | }; 72 | 73 | protected: 74 | InternalType value; 75 | 76 | protected: 77 | constexpr UFixed(const RawType & value); 78 | 79 | public: 80 | constexpr UFixed(); 81 | constexpr UFixed(const IntegerType & integer, const FractionType & fraction); 82 | constexpr UFixed(const char & value); 83 | constexpr UFixed(const unsigned char & value); 84 | constexpr UFixed(const signed char & value); 85 | constexpr UFixed(const unsigned short int & value); 86 | constexpr UFixed(const signed short int & value); 87 | constexpr UFixed(const unsigned int & value); 88 | constexpr UFixed(const signed int & value); 89 | constexpr UFixed(const unsigned long int & value); 90 | constexpr UFixed(const signed long int & value); 91 | constexpr UFixed(const unsigned long long int & value); 92 | constexpr UFixed(const signed long long int & value); 93 | constexpr UFixed(const double & value); 94 | constexpr UFixed(const float & value); 95 | constexpr UFixed(const long double & value); 96 | 97 | public: 98 | constexpr InternalType getInternal() const; 99 | constexpr IntegerType getInteger() const; 100 | constexpr FractionType getFraction() const; 101 | 102 | constexpr explicit operator char() const; 103 | constexpr explicit operator unsigned char() const; 104 | constexpr explicit operator signed char() const; 105 | constexpr explicit operator unsigned short int() const; 106 | constexpr explicit operator signed short int() const; 107 | constexpr explicit operator unsigned int() const; 108 | constexpr explicit operator signed int() const; 109 | constexpr explicit operator unsigned long int() const; 110 | constexpr explicit operator signed long int() const; 111 | constexpr explicit operator unsigned long long int() const; 112 | constexpr explicit operator signed long long int() const; 113 | 114 | constexpr explicit operator float() const; 115 | constexpr explicit operator double() const; 116 | constexpr explicit operator long double() const; 117 | 118 | template< unsigned IntegerOut, unsigned FractionOut > 119 | constexpr explicit operator UFixed() const; 120 | 121 | template< unsigned IntegerOut, unsigned FractionOut > 122 | constexpr explicit operator SFixed() const; 123 | 124 | constexpr explicit operator SFixed() const; 125 | 126 | static constexpr UFixed fromInternal(const InternalType & value); 127 | 128 | UFixed & operator ++(); 129 | UFixed & operator --(); 130 | UFixed & operator +=(const UFixed & other); 131 | UFixed & operator -=(const UFixed & other); 132 | UFixed & operator *=(const UFixed & other); 133 | UFixed & operator /=(const UFixed & other); 134 | 135 | public: 136 | static constexpr UFixed Epsilon = UFixed::fromInternal(1); 137 | static constexpr UFixed MinValue = UFixed::fromInternal(0); 138 | static constexpr UFixed MaxValue = UFixed::fromInternal(~0); 139 | 140 | // 40 digits is probably enough for these 141 | static constexpr UFixed Pi = 3.1415926535897932384626433832795028841971; 142 | static constexpr UFixed E = 2.718281828459045235360287471352662497757; 143 | static constexpr UFixed Phi = 1.6180339887498948482045868343656381177203; 144 | static constexpr UFixed Tau = 6.2831853071795864769252867665590057683943; 145 | }; 146 | 147 | 148 | // 149 | // Free functions 150 | // 151 | 152 | template< unsigned Integer, unsigned Fraction > 153 | constexpr UFixed multiply(const UFixed & left, const UFixed & right); 154 | 155 | 156 | // 157 | // Basic Logic Operations 158 | // 159 | 160 | template< unsigned Integer, unsigned Fraction > 161 | constexpr bool operator ==(const UFixed & left, const UFixed & right); 162 | 163 | template< unsigned Integer, unsigned Fraction > 164 | constexpr bool operator !=(const UFixed & left, const UFixed & right); 165 | 166 | template< unsigned Integer, unsigned Fraction > 167 | constexpr bool operator <(const UFixed & left, const UFixed & right); 168 | 169 | template< unsigned Integer, unsigned Fraction > 170 | constexpr bool operator >(const UFixed & left, const UFixed & right); 171 | 172 | template< unsigned Integer, unsigned Fraction > 173 | constexpr bool operator <=(const UFixed & left, const UFixed & right); 174 | 175 | template< unsigned Integer, unsigned Fraction > 176 | constexpr bool operator >=(const UFixed & left, const UFixed & right); 177 | 178 | // 179 | // Inter-size Logic Operations 180 | // 181 | 182 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 183 | constexpr bool operator ==(const UFixed & left, const UFixed & right); 184 | 185 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 186 | constexpr bool operator !=(const UFixed & left, const UFixed & right); 187 | 188 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 189 | constexpr bool operator <(const UFixed & left, const UFixed & right); 190 | 191 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 192 | constexpr bool operator >(const UFixed & left, const UFixed & right); 193 | 194 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 195 | constexpr bool operator <=(const UFixed & left, const UFixed & right); 196 | 197 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 198 | constexpr bool operator >=(const UFixed & left, const UFixed & right); 199 | 200 | // 201 | // Basic Arithmetic Operations 202 | // 203 | 204 | template< unsigned Integer, unsigned Fraction > 205 | constexpr UFixed operator +(const UFixed & left, const UFixed & right); 206 | 207 | template< unsigned Integer, unsigned Fraction > 208 | constexpr UFixed operator -(const UFixed & left, const UFixed & right); 209 | 210 | template< unsigned Integer, unsigned Fraction > 211 | constexpr UFixed operator *(const UFixed & left, const UFixed & right); 212 | 213 | template< unsigned Integer, unsigned Fraction > 214 | constexpr UFixed operator /(const UFixed & left, const UFixed & right); 215 | 216 | // 217 | // Inter-size Arithmetic Operations 218 | // 219 | 220 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 221 | constexpr auto operator +(const UFixed & left, const UFixed & right) 222 | -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed >; 223 | 224 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 225 | constexpr auto operator -(const UFixed & left, const UFixed & right) 226 | -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed >; 227 | 228 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 229 | constexpr auto operator *(const UFixed & left, const UFixed & right) 230 | -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed >; 231 | 232 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 233 | inline constexpr auto operator /(const UFixed & left, const UFixed & right) 234 | -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed >; 235 | 236 | FIXED_POINTS_END_NAMESPACE 237 | 238 | #include "UFixedMemberFunctions.h" 239 | #include "UFixedFreeFunctions.h" -------------------------------------------------------------------------------- /src/FixedPoints/SFixed.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "Details.h" 18 | 19 | FIXED_POINTS_BEGIN_NAMESPACE 20 | 21 | // 22 | // Declaration 23 | // 24 | 25 | template< unsigned Integer, unsigned Fraction > 26 | class UFixed; 27 | 28 | template< unsigned Integer, unsigned Fraction > 29 | class SFixed 30 | { 31 | public: 32 | static constexpr uintmax_t IntegerSize = Integer + 1; 33 | static constexpr uintmax_t FractionSize = Fraction; 34 | static constexpr uintmax_t LogicalSize = IntegerSize + FractionSize; 35 | static constexpr uintmax_t Scale = UINTMAX_C(1) << FractionSize; 36 | 37 | public: 38 | static_assert(LogicalSize <= FIXED_POINTS_DETAILS::BitSize::Value, "Platform does not have a native type large enough for SFixed."); 39 | 40 | public: 41 | using IntegerType = FIXED_POINTS_DETAILS::LeastInt; 42 | using FractionType = FIXED_POINTS_DETAILS::LeastUInt; 43 | using InternalType = FIXED_POINTS_DETAILS::LeastInt; 44 | 45 | static constexpr uintmax_t InternalSize = FIXED_POINTS_DETAILS::BitSize::Value; 46 | 47 | using ShiftType = FIXED_POINTS_DETAILS::LeastInt; 48 | using MaskType = FIXED_POINTS_DETAILS::LeastUInt; 49 | 50 | public: 51 | static constexpr ShiftType IntegerShift = FractionSize; 52 | static constexpr ShiftType FractionShift = 0; 53 | 54 | static constexpr MaskType IntegerMask = FIXED_POINTS_DETAILS::IdentityMask::Value; 55 | static constexpr MaskType FractionMask = FIXED_POINTS_DETAILS::IdentityMask::Value; 56 | 57 | static constexpr MaskType IdentityMask = (IntegerMask << IntegerShift) | (FractionMask << FractionShift); 58 | 59 | static constexpr MaskType MidpointMask = FIXED_POINTS_DETAILS::MsbMask::Value; 60 | static constexpr MaskType LesserMidpointMask = MidpointMask - 1; 61 | 62 | protected: 63 | class RawType 64 | { 65 | private: 66 | const InternalType value; 67 | 68 | public: 69 | constexpr explicit RawType(const InternalType & value) : value(value) {} 70 | constexpr explicit operator InternalType() const { return this->value; } 71 | }; 72 | 73 | protected: 74 | InternalType value; 75 | 76 | protected: 77 | constexpr SFixed(const RawType & value); 78 | 79 | public: 80 | constexpr SFixed(); 81 | constexpr SFixed(const IntegerType & integer, const FractionType & fraction); 82 | constexpr SFixed(const char & value); 83 | constexpr SFixed(const unsigned char & value); 84 | constexpr SFixed(const signed char & value); 85 | constexpr SFixed(const unsigned short int & value); 86 | constexpr SFixed(const signed short int & value); 87 | constexpr SFixed(const unsigned int & value); 88 | constexpr SFixed(const signed int & value); 89 | constexpr SFixed(const unsigned long int & value); 90 | constexpr SFixed(const signed long int & value); 91 | constexpr SFixed(const unsigned long long int & value); 92 | constexpr SFixed(const signed long long int & value); 93 | constexpr SFixed(const double & value); 94 | constexpr SFixed(const float & value); 95 | constexpr SFixed(const long double & value); 96 | 97 | constexpr InternalType getInternal() const; 98 | constexpr IntegerType getInteger() const; 99 | constexpr FractionType getFraction() const; 100 | 101 | constexpr explicit operator char() const; 102 | constexpr explicit operator unsigned char() const; 103 | constexpr explicit operator signed char() const; 104 | constexpr explicit operator unsigned short int() const; 105 | constexpr explicit operator signed short int() const; 106 | constexpr explicit operator unsigned int() const; 107 | constexpr explicit operator signed int() const; 108 | constexpr explicit operator unsigned long int() const; 109 | constexpr explicit operator signed long int() const; 110 | constexpr explicit operator unsigned long long int() const; 111 | constexpr explicit operator signed long long int() const; 112 | 113 | constexpr explicit operator float() const; 114 | constexpr explicit operator double() const; 115 | constexpr explicit operator long double() const; 116 | 117 | template< unsigned IntegerOut, unsigned FractionOut > 118 | constexpr explicit operator SFixed() const; 119 | 120 | template< unsigned IntegerOut, unsigned FractionOut > 121 | constexpr explicit operator UFixed() const; 122 | 123 | constexpr explicit operator UFixed() const; 124 | 125 | static constexpr SFixed fromInternal(const InternalType & value); 126 | 127 | constexpr SFixed operator -() const; 128 | SFixed & operator ++(); 129 | SFixed & operator --(); 130 | SFixed & operator +=(const SFixed & other); 131 | SFixed & operator -=(const SFixed & other); 132 | SFixed & operator *=(const SFixed & other); 133 | SFixed & operator /=(const SFixed & other); 134 | 135 | public: 136 | static constexpr SFixed Epsilon = SFixed::fromInternal(1); 137 | static constexpr SFixed MinValue = SFixed::fromInternal(FIXED_POINTS_DETAILS::MsbMask::Value); 138 | static constexpr SFixed MaxValue = SFixed::fromInternal(~FIXED_POINTS_DETAILS::MsbMask::Value); 139 | 140 | // 40 digits is probably enough for these 141 | static constexpr SFixed Pi = 3.1415926535897932384626433832795028841971; 142 | static constexpr SFixed E = 2.718281828459045235360287471352662497757; 143 | static constexpr SFixed Phi = 1.6180339887498948482045868343656381177203; 144 | static constexpr SFixed Tau = 6.2831853071795864769252867665590057683943; 145 | }; 146 | 147 | 148 | // 149 | // Free functions 150 | // 151 | 152 | template< unsigned Integer, unsigned Fraction > 153 | constexpr SFixed multiply(const SFixed & left, const SFixed & right); 154 | 155 | // 156 | // Basic Logic Operations 157 | // 158 | 159 | template< unsigned Integer, unsigned Fraction > 160 | constexpr bool operator ==(const SFixed & left, const SFixed & right); 161 | 162 | template< unsigned Integer, unsigned Fraction > 163 | constexpr bool operator !=(const SFixed & left, const SFixed & right); 164 | 165 | template< unsigned Integer, unsigned Fraction > 166 | constexpr bool operator <(const SFixed & left, const SFixed & right); 167 | 168 | template< unsigned Integer, unsigned Fraction > 169 | constexpr bool operator >(const SFixed & left, const SFixed & right); 170 | 171 | template< unsigned Integer, unsigned Fraction > 172 | constexpr bool operator <=(const SFixed & left, const SFixed & right); 173 | 174 | template< unsigned Integer, unsigned Fraction > 175 | constexpr bool operator >=(const SFixed & left, const SFixed & right); 176 | 177 | // 178 | // Inter-size Logic Operations 179 | // 180 | 181 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 182 | constexpr bool operator ==(const SFixed & left, const SFixed & right); 183 | 184 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 185 | constexpr bool operator !=(const SFixed & left, const SFixed & right); 186 | 187 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 188 | constexpr bool operator <(const SFixed & left, const SFixed & right); 189 | 190 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 191 | constexpr bool operator >(const SFixed & left, const SFixed & right); 192 | 193 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 194 | constexpr bool operator <=(const SFixed & left, const SFixed & right); 195 | 196 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 197 | constexpr bool operator >=(const SFixed & left, const SFixed & right); 198 | 199 | // 200 | // Basic Arithmetic Operations 201 | // 202 | 203 | template< unsigned Integer, unsigned Fraction > 204 | constexpr SFixed operator +(const SFixed & left, const SFixed & right); 205 | 206 | template< unsigned Integer, unsigned Fraction > 207 | constexpr SFixed operator -(const SFixed & left, const SFixed & right); 208 | 209 | template< unsigned Integer, unsigned Fraction > 210 | constexpr SFixed operator *(const SFixed & left, const SFixed & right); 211 | 212 | template< unsigned Integer, unsigned Fraction > 213 | constexpr SFixed operator /(const SFixed & left, const SFixed & right); 214 | 215 | // 216 | // Inter-size Arithmetic Operations 217 | // 218 | 219 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 220 | constexpr auto operator +(const SFixed & left, const SFixed & right) 221 | -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed >; 222 | 223 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 224 | constexpr auto operator -(const SFixed & left, const SFixed & right) 225 | -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed >; 226 | 227 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 228 | constexpr auto operator *(const SFixed & left, const SFixed & right) 229 | -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed >; 230 | 231 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 232 | inline constexpr auto operator /(const SFixed & left, const SFixed & right) 233 | -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed >; 234 | 235 | FIXED_POINTS_END_NAMESPACE 236 | 237 | #include "SFixedMemberFunctions.h" 238 | #include "SFixedFreeFunctions.h" -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/FixedPoints/UFixedMemberFunctions.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | FIXED_POINTS_BEGIN_NAMESPACE 16 | 17 | // 18 | // Constructors 19 | // 20 | 21 | template< unsigned Integer, unsigned Fraction > 22 | constexpr UFixed::UFixed(const RawType & value) 23 | : value(static_cast(value)) 24 | { 25 | } 26 | 27 | template< unsigned Integer, unsigned Fraction > 28 | constexpr UFixed::UFixed() 29 | : value(0) 30 | { 31 | } 32 | 33 | template< unsigned Integer, unsigned Fraction > 34 | constexpr UFixed::UFixed(const IntegerType & integer, const FractionType & fraction) 35 | : value((static_cast(integer) << FractionSize) | fraction) 36 | { 37 | } 38 | 39 | template< unsigned Integer, unsigned Fraction > 40 | constexpr UFixed::UFixed(const char & value) 41 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 42 | { 43 | } 44 | 45 | template< unsigned Integer, unsigned Fraction > 46 | constexpr UFixed::UFixed(const unsigned char & value) 47 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 48 | { 49 | } 50 | 51 | template< unsigned Integer, unsigned Fraction > 52 | constexpr UFixed::UFixed(const signed char & value) 53 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 54 | { 55 | } 56 | 57 | template< unsigned Integer, unsigned Fraction > 58 | constexpr UFixed::UFixed(const unsigned short int & value) 59 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 60 | { 61 | } 62 | 63 | template< unsigned Integer, unsigned Fraction > 64 | constexpr UFixed::UFixed(const signed short int & value) 65 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 66 | { 67 | } 68 | 69 | template< unsigned Integer, unsigned Fraction > 70 | constexpr UFixed::UFixed(const unsigned int & value) 71 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 72 | { 73 | } 74 | 75 | template< unsigned Integer, unsigned Fraction > 76 | constexpr UFixed::UFixed(const signed int & value) 77 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 78 | { 79 | } 80 | 81 | template< unsigned Integer, unsigned Fraction > 82 | constexpr UFixed::UFixed(const unsigned long int & value) 83 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 84 | { 85 | } 86 | 87 | template< unsigned Integer, unsigned Fraction > 88 | constexpr UFixed::UFixed(const signed long int & value) 89 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 90 | { 91 | } 92 | 93 | template< unsigned Integer, unsigned Fraction > 94 | constexpr UFixed::UFixed(const unsigned long long int & value) 95 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 96 | { 97 | } 98 | 99 | template< unsigned Integer, unsigned Fraction > 100 | constexpr UFixed::UFixed(const signed long long int & value) 101 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 102 | { 103 | } 104 | 105 | template< unsigned Integer, unsigned Fraction > 106 | constexpr UFixed::UFixed(const double & value) 107 | : value(static_cast(value * static_cast(Scale))) 108 | { 109 | } 110 | 111 | template< unsigned Integer, unsigned Fraction > 112 | constexpr UFixed::UFixed(const float & value) 113 | : value(static_cast(value * static_cast(Scale))) 114 | { 115 | } 116 | 117 | template< unsigned Integer, unsigned Fraction > 118 | constexpr UFixed::UFixed(const long double & value) 119 | : value(static_cast(value * static_cast(Scale))) 120 | { 121 | } 122 | 123 | // 124 | // Getters 125 | // 126 | 127 | template< unsigned Integer, unsigned Fraction > 128 | constexpr typename UFixed::InternalType UFixed::getInternal() const 129 | { 130 | return this->value; 131 | } 132 | 133 | template< unsigned Integer, unsigned Fraction > 134 | constexpr typename UFixed::IntegerType UFixed::getInteger() const 135 | { 136 | return static_cast(this->value >> IntegerShift) & IntegerMask; 137 | } 138 | 139 | template< unsigned Integer, unsigned Fraction > 140 | constexpr typename UFixed::FractionType UFixed::getFraction() const 141 | { 142 | return static_cast(this->value >> FractionShift) & FractionMask; 143 | } 144 | 145 | // 146 | // Cast Operators 147 | // 148 | 149 | template< unsigned Integer, unsigned Fraction > 150 | constexpr UFixed::operator char() const 151 | { 152 | return this->getInteger(); 153 | } 154 | 155 | template< unsigned Integer, unsigned Fraction > 156 | constexpr UFixed::operator unsigned char() const 157 | { 158 | return this->getInteger(); 159 | } 160 | 161 | template< unsigned Integer, unsigned Fraction > 162 | constexpr UFixed::operator signed char() const 163 | { 164 | return this->getInteger(); 165 | } 166 | 167 | template< unsigned Integer, unsigned Fraction > 168 | constexpr UFixed::operator unsigned short int() const 169 | { 170 | return this->getInteger(); 171 | } 172 | 173 | template< unsigned Integer, unsigned Fraction > 174 | constexpr UFixed::operator signed short int() const 175 | { 176 | return this->getInteger(); 177 | } 178 | 179 | template< unsigned Integer, unsigned Fraction > 180 | constexpr UFixed::operator unsigned int() const 181 | { 182 | return this->getInteger(); 183 | } 184 | 185 | template< unsigned Integer, unsigned Fraction > 186 | constexpr UFixed::operator signed int() const 187 | { 188 | return this->getInteger(); 189 | } 190 | 191 | template< unsigned Integer, unsigned Fraction > 192 | constexpr UFixed::operator unsigned long int() const 193 | { 194 | return this->getInteger(); 195 | } 196 | 197 | template< unsigned Integer, unsigned Fraction > 198 | constexpr UFixed::operator signed long int() const 199 | { 200 | return this->getInteger(); 201 | } 202 | 203 | template< unsigned Integer, unsigned Fraction > 204 | constexpr UFixed::operator unsigned long long int() const 205 | { 206 | return this->getInteger(); 207 | } 208 | 209 | template< unsigned Integer, unsigned Fraction > 210 | constexpr UFixed::operator signed long long int() const 211 | { 212 | return this->getInteger(); 213 | } 214 | 215 | 216 | 217 | template< unsigned Integer, unsigned Fraction > 218 | constexpr UFixed::operator float() const 219 | { 220 | return ((this->value & IdentityMask) * (1.0F / Scale)); 221 | } 222 | 223 | template< unsigned Integer, unsigned Fraction > 224 | constexpr UFixed::operator double() const 225 | { 226 | return ((this->value & IdentityMask) * (1.0 / Scale)); 227 | } 228 | 229 | template< unsigned Integer, unsigned Fraction > 230 | constexpr UFixed::operator long double() const 231 | { 232 | return ((this->value & IdentityMask) * (1.0L / Scale)); 233 | } 234 | 235 | template< unsigned Integer, unsigned Fraction > 236 | template< unsigned IntegerOut, unsigned FractionOut > 237 | constexpr UFixed::operator UFixed() const 238 | { 239 | using OutputType = UFixed; 240 | using OutputInternalType = typename OutputType::InternalType; 241 | using OutputShiftType = typename OutputType::ShiftType; 242 | 243 | using InputType = UFixed; 244 | using InputShiftType = typename InputType::ShiftType; 245 | 246 | return 247 | (FractionOut > FractionSize) ? 248 | OutputType::fromInternal(static_cast(static_cast(this->value) << ((FractionOut > FractionSize) ? (FractionOut - FractionSize) : 0))) : 249 | (FractionSize > FractionOut) ? 250 | OutputType::fromInternal(static_cast(static_cast(this->value) >> ((FractionSize > FractionOut) ? (FractionSize - FractionOut) : 0))) : 251 | OutputType::fromInternal(this->value); 252 | } 253 | 254 | template< unsigned Integer, unsigned Fraction > 255 | template< unsigned IntegerOut, unsigned FractionOut > 256 | constexpr UFixed::operator SFixed() const 257 | { 258 | using OutputType = SFixed; 259 | using IntermediaryType = UFixed; 260 | 261 | return static_cast(static_cast(*this)); 262 | } 263 | 264 | template< unsigned Integer, unsigned Fraction > 265 | constexpr UFixed::operator SFixed() const 266 | { 267 | using OutputType = SFixed; 268 | using OutputInternalType = typename OutputType::InternalType; 269 | 270 | return OutputType::fromInternal(static_cast(this->value)); 271 | } 272 | 273 | // 274 | // Static Functions 275 | // 276 | 277 | template< unsigned Integer, unsigned Fraction > 278 | constexpr UFixed UFixed::fromInternal(const typename UFixed::InternalType & value) 279 | { 280 | return UFixed(RawType(value)); 281 | } 282 | 283 | // 284 | // Member Operators 285 | // 286 | 287 | template< unsigned Integer, unsigned Fraction > 288 | UFixed & UFixed::operator ++() 289 | { 290 | this->value += (static_cast(1) << FractionSize); 291 | return *this; 292 | } 293 | 294 | template< unsigned Integer, unsigned Fraction > 295 | UFixed & UFixed::operator --() 296 | { 297 | this->value -= (static_cast(1) << FractionSize); 298 | return *this; 299 | } 300 | 301 | // 302 | // Compound Assignment Operators 303 | // 304 | 305 | template< unsigned Integer, unsigned Fraction > 306 | UFixed & UFixed::operator +=(const UFixed & other) 307 | { 308 | this->value += other.value; 309 | return *this; 310 | } 311 | 312 | template< unsigned Integer, unsigned Fraction > 313 | UFixed & UFixed::operator -=(const UFixed & other) 314 | { 315 | this->value -= other.value; 316 | return *this; 317 | } 318 | 319 | template< unsigned Integer, unsigned Fraction > 320 | UFixed & UFixed::operator *=(const UFixed & other) 321 | { 322 | using InternalType = typename UFixed::InternalType; 323 | using PrecisionType = typename UFixed::InternalType; 324 | const PrecisionType temp = (static_cast(this->value) * static_cast(other.value)) >> FractionSize; 325 | this->value = static_cast(temp); 326 | return *this; 327 | } 328 | 329 | template< unsigned Integer, unsigned Fraction > 330 | UFixed & UFixed::operator /=(const UFixed & other) 331 | { 332 | using InternalType = typename UFixed::InternalType; 333 | using PrecisionType = typename UFixed::InternalType; 334 | const PrecisionType temp = (static_cast(this->value) << FractionSize) / static_cast(other.value); 335 | this->value = static_cast(temp); 336 | return *this; 337 | } 338 | 339 | FIXED_POINTS_END_NAMESPACE -------------------------------------------------------------------------------- /src/FixedPoints/SFixedMemberFunctions.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | FIXED_POINTS_BEGIN_NAMESPACE 16 | 17 | // 18 | // Constructors 19 | // 20 | 21 | template< unsigned Integer, unsigned Fraction > 22 | constexpr SFixed::SFixed(const RawType & value) 23 | : value(static_cast(value)) 24 | { 25 | } 26 | 27 | template< unsigned Integer, unsigned Fraction > 28 | constexpr SFixed::SFixed() 29 | : value(0) 30 | { 31 | } 32 | 33 | template< unsigned Integer, unsigned Fraction > 34 | constexpr SFixed::SFixed(const IntegerType & integer, const FractionType & fraction) 35 | : value((static_cast(integer) << FractionSize) | fraction) 36 | { 37 | } 38 | 39 | template< unsigned Integer, unsigned Fraction > 40 | constexpr SFixed::SFixed(const char & value) 41 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 42 | { 43 | } 44 | 45 | template< unsigned Integer, unsigned Fraction > 46 | constexpr SFixed::SFixed(const unsigned char & value) 47 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 48 | { 49 | } 50 | 51 | template< unsigned Integer, unsigned Fraction > 52 | constexpr SFixed::SFixed(const signed char & value) 53 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 54 | { 55 | } 56 | 57 | template< unsigned Integer, unsigned Fraction > 58 | constexpr SFixed::SFixed(const unsigned short int & value) 59 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 60 | { 61 | } 62 | 63 | template< unsigned Integer, unsigned Fraction > 64 | constexpr SFixed::SFixed(const signed short int & value) 65 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 66 | { 67 | } 68 | 69 | template< unsigned Integer, unsigned Fraction > 70 | constexpr SFixed::SFixed(const unsigned int & value) 71 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 72 | { 73 | } 74 | 75 | template< unsigned Integer, unsigned Fraction > 76 | constexpr SFixed::SFixed(const signed int & value) 77 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 78 | { 79 | } 80 | 81 | template< unsigned Integer, unsigned Fraction > 82 | constexpr SFixed::SFixed(const unsigned long int & value) 83 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 84 | { 85 | } 86 | 87 | template< unsigned Integer, unsigned Fraction > 88 | constexpr SFixed::SFixed(const signed long int & value) 89 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 90 | { 91 | } 92 | 93 | template< unsigned Integer, unsigned Fraction > 94 | constexpr SFixed::SFixed(const unsigned long long int & value) 95 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 96 | { 97 | } 98 | 99 | template< unsigned Integer, unsigned Fraction > 100 | constexpr SFixed::SFixed(const signed long long int & value) 101 | : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) 102 | { 103 | } 104 | 105 | template< unsigned Integer, unsigned Fraction > 106 | constexpr SFixed::SFixed(const double & value) 107 | : value(static_cast(value * static_cast(Scale))) 108 | { 109 | } 110 | 111 | template< unsigned Integer, unsigned Fraction > 112 | constexpr SFixed::SFixed(const float & value) 113 | : value(static_cast(value * static_cast(Scale))) 114 | { 115 | } 116 | 117 | template< unsigned Integer, unsigned Fraction > 118 | constexpr SFixed::SFixed(const long double & value) 119 | : value(static_cast(value * static_cast(Scale))) 120 | { 121 | } 122 | 123 | // 124 | // Getters 125 | // 126 | 127 | template< unsigned Integer, unsigned Fraction > 128 | constexpr typename SFixed::InternalType SFixed::getInternal() const 129 | { 130 | return this->value; 131 | } 132 | 133 | template< unsigned Integer, unsigned Fraction > 134 | constexpr typename SFixed::IntegerType SFixed::getInteger() const 135 | { 136 | return (static_cast(this->value >> IntegerShift) & IntegerMask) | ((this->value < 0) ? ~IntegerMask : 0); 137 | } 138 | 139 | template< unsigned Integer, unsigned Fraction > 140 | constexpr typename SFixed::FractionType SFixed::getFraction() const 141 | { 142 | return static_cast(this->value >> FractionShift) & FractionMask; 143 | } 144 | 145 | // 146 | // Cast Operators 147 | // 148 | 149 | template< unsigned Integer, unsigned Fraction > 150 | constexpr SFixed::operator char() const 151 | { 152 | return this->getInteger(); 153 | } 154 | 155 | template< unsigned Integer, unsigned Fraction > 156 | constexpr SFixed::operator unsigned char() const 157 | { 158 | return this->getInteger(); 159 | } 160 | 161 | template< unsigned Integer, unsigned Fraction > 162 | constexpr SFixed::operator signed char() const 163 | { 164 | return this->getInteger(); 165 | } 166 | 167 | template< unsigned Integer, unsigned Fraction > 168 | constexpr SFixed::operator unsigned short int() const 169 | { 170 | return this->getInteger(); 171 | } 172 | 173 | template< unsigned Integer, unsigned Fraction > 174 | constexpr SFixed::operator signed short int() const 175 | { 176 | return this->getInteger(); 177 | } 178 | 179 | template< unsigned Integer, unsigned Fraction > 180 | constexpr SFixed::operator unsigned int() const 181 | { 182 | return this->getInteger(); 183 | } 184 | 185 | template< unsigned Integer, unsigned Fraction > 186 | constexpr SFixed::operator signed int() const 187 | { 188 | return this->getInteger(); 189 | } 190 | 191 | template< unsigned Integer, unsigned Fraction > 192 | constexpr SFixed::operator unsigned long int() const 193 | { 194 | return this->getInteger(); 195 | } 196 | 197 | template< unsigned Integer, unsigned Fraction > 198 | constexpr SFixed::operator signed long int() const 199 | { 200 | return this->getInteger(); 201 | } 202 | 203 | template< unsigned Integer, unsigned Fraction > 204 | constexpr SFixed::operator unsigned long long int() const 205 | { 206 | return this->getInteger(); 207 | } 208 | 209 | template< unsigned Integer, unsigned Fraction > 210 | constexpr SFixed::operator signed long long int() const 211 | { 212 | return this->getInteger(); 213 | } 214 | 215 | 216 | 217 | template< unsigned Integer, unsigned Fraction > 218 | constexpr SFixed::operator float() const 219 | { 220 | return (1.0F / Scale) * 221 | static_cast 222 | ((this->value & IdentityMask) | 223 | ((this->value < 0) ? ~IdentityMask : 0)); 224 | } 225 | 226 | template< unsigned Integer, unsigned Fraction > 227 | constexpr SFixed::operator double() const 228 | { 229 | return (1.0 / Scale) * 230 | static_cast 231 | ((this->value & IdentityMask) | 232 | ((this->value < 0) ? ~IdentityMask : 0)); 233 | } 234 | 235 | template< unsigned Integer, unsigned Fraction > 236 | constexpr SFixed::operator long double() const 237 | { 238 | return (1.0L / Scale) * 239 | static_cast 240 | ((this->value & IdentityMask) | 241 | ((this->value < 0) ? ~IdentityMask : 0)); 242 | } 243 | 244 | template< unsigned Integer, unsigned Fraction > 245 | template< unsigned IntegerOut, unsigned FractionOut > 246 | constexpr SFixed::operator SFixed() const 247 | { 248 | using OutputType = SFixed; 249 | using OutputInternalType = typename OutputType::InternalType; 250 | using OutputShiftType = typename OutputType::ShiftType; 251 | 252 | using InputType = SFixed; 253 | using InputShiftType = typename InputType::ShiftType; 254 | 255 | return 256 | (FractionOut > FractionSize) ? 257 | OutputType::fromInternal(static_cast(static_cast(this->value) << ((FractionOut > FractionSize) ? (FractionOut - FractionSize) : 0))) : 258 | (FractionSize > FractionOut) ? 259 | OutputType::fromInternal(static_cast(static_cast(this->value) >> ((FractionSize > FractionOut) ? (FractionSize - FractionOut) : 0))) : 260 | OutputType::fromInternal(this->value); 261 | } 262 | 263 | template< unsigned Integer, unsigned Fraction > 264 | template< unsigned IntegerOut, unsigned FractionOut > 265 | constexpr SFixed::operator UFixed() const 266 | { 267 | using OutputType = UFixed; 268 | using IntermediaryType = SFixed; 269 | 270 | return static_cast(static_cast(*this)); 271 | } 272 | 273 | template< unsigned Integer, unsigned Fraction > 274 | constexpr SFixed::operator UFixed() const 275 | { 276 | using OutputType = UFixed; 277 | using OutputInternalType = typename OutputType::InternalType; 278 | 279 | return OutputType::fromInternal(static_cast(this->value)); 280 | } 281 | 282 | // 283 | // Static Functions 284 | // 285 | 286 | template< unsigned Integer, unsigned Fraction > 287 | constexpr SFixed SFixed::fromInternal(const typename SFixed::InternalType & value) 288 | { 289 | return SFixed(RawType(value)); 290 | } 291 | 292 | template< unsigned Integer, unsigned Fraction > 293 | constexpr SFixed SFixed::operator -() const 294 | { 295 | return SFixed::fromInternal(-this->value); 296 | } 297 | 298 | // 299 | // Member Operators 300 | // 301 | 302 | template< unsigned Integer, unsigned Fraction > 303 | SFixed & SFixed::operator ++() 304 | { 305 | this->value += (static_cast(1) << FractionSize); 306 | return *this; 307 | } 308 | 309 | template< unsigned Integer, unsigned Fraction > 310 | SFixed & SFixed::operator --() 311 | { 312 | this->value -= (static_cast(1) << FractionSize); 313 | return *this; 314 | } 315 | 316 | // 317 | // Compound Assignment Operators 318 | // 319 | 320 | template< unsigned Integer, unsigned Fraction > 321 | SFixed & SFixed::operator +=(const SFixed & other) 322 | { 323 | this->value += other.value; 324 | return *this; 325 | } 326 | 327 | template< unsigned Integer, unsigned Fraction > 328 | SFixed & SFixed::operator -=(const SFixed & other) 329 | { 330 | this->value -= other.value; 331 | return *this; 332 | } 333 | 334 | template< unsigned Integer, unsigned Fraction > 335 | SFixed & SFixed::operator *=(const SFixed & other) 336 | { 337 | using InternalType = typename SFixed::InternalType; 338 | using PrecisionType = typename SFixed::InternalType; 339 | const PrecisionType temp = (static_cast(this->value) * static_cast(other.value)) >> Fraction; 340 | this->value = static_cast(temp); 341 | return *this; 342 | } 343 | 344 | template< unsigned Integer, unsigned Fraction > 345 | SFixed & SFixed::operator /=(const SFixed & other) 346 | { 347 | using InternalType = typename SFixed::InternalType; 348 | using PrecisionType = typename SFixed::InternalType; 349 | const PrecisionType temp = (static_cast(this->value) << Fraction) / static_cast(other.value); 350 | this->value = static_cast(temp); 351 | return *this; 352 | } 353 | 354 | FIXED_POINTS_END_NAMESPACE -------------------------------------------------------------------------------- /src/FixedPoints/SFixedFreeFunctions.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | FIXED_POINTS_BEGIN_NAMESPACE 16 | 17 | // 18 | // multiply 19 | // 20 | 21 | template< unsigned Integer, unsigned Fraction > 22 | constexpr SFixed multiply(const SFixed & left, const SFixed & right) 23 | { 24 | static_assert(((Integer + 1) * 2 + Fraction * 2) <= FIXED_POINTS_DETAILS::BitSize::Value, "Multiplication cannot be performed, the result type would be too large"); 25 | 26 | using ResultType = SFixed; 27 | using InternalType = typename ResultType::InternalType; 28 | return ResultType::fromInternal(static_cast(static_cast(left.getInternal()) * static_cast(right.getInternal()))); 29 | } 30 | 31 | // 32 | // Postincrement and Postdecrement 33 | // 34 | 35 | template< unsigned Integer, unsigned Fraction > 36 | SFixed operator ++(SFixed & value, int) 37 | { 38 | const auto oldValue = value; 39 | ++value; 40 | return oldValue; 41 | } 42 | 43 | template< unsigned Integer, unsigned Fraction > 44 | SFixed operator --(SFixed & value, int) 45 | { 46 | const auto oldValue = value; 47 | --value; 48 | return oldValue; 49 | } 50 | 51 | // 52 | // Basic Logic Operations 53 | // 54 | 55 | template< unsigned Integer, unsigned Fraction > 56 | constexpr bool operator ==(const SFixed & left, const SFixed & right) 57 | { 58 | return (left.getInternal() == right.getInternal()); 59 | } 60 | 61 | template< unsigned Integer, unsigned Fraction > 62 | constexpr bool operator !=(const SFixed & left, const SFixed & right) 63 | { 64 | return (left.getInternal() != right.getInternal()); 65 | } 66 | 67 | template< unsigned Integer, unsigned Fraction > 68 | constexpr bool operator <(const SFixed & left, const SFixed & right) 69 | { 70 | return (left.getInternal() < right.getInternal()); 71 | } 72 | 73 | template< unsigned Integer, unsigned Fraction > 74 | constexpr bool operator >(const SFixed & left, const SFixed & right) 75 | { 76 | return (left.getInternal() > right.getInternal()); 77 | } 78 | 79 | template< unsigned Integer, unsigned Fraction > 80 | constexpr bool operator <=(const SFixed & left, const SFixed & right) 81 | { 82 | return (left.getInternal() <= right.getInternal()); 83 | } 84 | 85 | template< unsigned Integer, unsigned Fraction > 86 | constexpr bool operator >=(const SFixed & left, const SFixed & right) 87 | { 88 | return (left.getInternal() >= right.getInternal()); 89 | } 90 | 91 | // 92 | // Inter-size Logic Operations 93 | // 94 | 95 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 96 | constexpr bool operator ==(const SFixed & left, const SFixed & right) 97 | { 98 | using LeftType = SFixed; 99 | using RightType = SFixed; 100 | 101 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator == has ambiguous result"); 102 | 103 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 104 | 105 | return (static_cast(left) == static_cast(right)); 106 | } 107 | 108 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 109 | constexpr bool operator !=(const SFixed & left, const SFixed & right) 110 | { 111 | using LeftType = SFixed; 112 | using RightType = SFixed; 113 | 114 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator != has ambiguous result"); 115 | 116 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 117 | 118 | return (static_cast(left) != static_cast(right)); 119 | } 120 | 121 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 122 | constexpr bool operator <(const SFixed & left, const SFixed & right) 123 | { 124 | using LeftType = SFixed; 125 | using RightType = SFixed; 126 | 127 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator < has ambiguous result"); 128 | 129 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 130 | 131 | return (static_cast(left) < static_cast(right)); 132 | } 133 | 134 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 135 | constexpr bool operator >(const SFixed & left, const SFixed & right) 136 | { 137 | using LeftType = SFixed; 138 | using RightType = SFixed; 139 | 140 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator > has ambiguous result"); 141 | 142 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 143 | 144 | return (static_cast(left) > static_cast(right)); 145 | } 146 | 147 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 148 | constexpr bool operator <=(const SFixed & left, const SFixed & right) 149 | { 150 | using LeftType = SFixed; 151 | using RightType = SFixed; 152 | 153 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator <= has ambiguous result"); 154 | 155 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 156 | 157 | return (static_cast(left) <= static_cast(right)); 158 | } 159 | 160 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 161 | constexpr bool operator >=(const SFixed & left, const SFixed & right) 162 | { 163 | using LeftType = SFixed; 164 | using RightType = SFixed; 165 | 166 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator >= has ambiguous result"); 167 | 168 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 169 | 170 | return (static_cast(left) >= static_cast(right)); 171 | } 172 | 173 | // 174 | // Basic Arithmetic Operations 175 | // 176 | 177 | template< unsigned Integer, unsigned Fraction > 178 | constexpr SFixed operator +(const SFixed & left, const SFixed & right) 179 | { 180 | using InternalType = typename SFixed::InternalType; 181 | return SFixed::fromInternal(static_cast(left.getInternal() + right.getInternal())); 182 | } 183 | 184 | template< unsigned Integer, unsigned Fraction > 185 | constexpr SFixed operator -(const SFixed & left, const SFixed & right) 186 | { 187 | using InternalType = typename SFixed::InternalType; 188 | return SFixed::fromInternal(static_cast(left.getInternal() - right.getInternal())); 189 | } 190 | 191 | template< unsigned Integer, unsigned Fraction > 192 | constexpr SFixed operator *(const SFixed & left, const SFixed & right) 193 | { 194 | static_assert(((Integer + 1) * 2 + Fraction * 2) <= FIXED_POINTS_DETAILS::BitSize::Value, "Multiplication cannot be performed, the intermediary type would be too large"); 195 | 196 | using InternalType = typename SFixed::InternalType; 197 | using PrecisionType = typename SFixed::InternalType; 198 | return SFixed::fromInternal(static_cast((static_cast(left.getInternal()) * static_cast(right.getInternal())) >> Fraction)); 199 | } 200 | 201 | template< unsigned Integer, unsigned Fraction > 202 | constexpr SFixed operator /(const SFixed & left, const SFixed & right) 203 | { 204 | using InternalType = typename SFixed::InternalType; 205 | using PrecisionType = typename SFixed::InternalType; 206 | return SFixed::fromInternal(static_cast((static_cast(left.getInternal()) << Fraction) / right.getInternal())); 207 | } 208 | 209 | // 210 | // Inter-size Arithmetic Operations 211 | // 212 | 213 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 214 | constexpr auto operator +(const SFixed & left, const SFixed & right) 215 | -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed > 216 | { 217 | using LeftType = SFixed; 218 | using RightType = SFixed; 219 | 220 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator + has ambiguous result"); 221 | 222 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 223 | 224 | return (static_cast(left) + static_cast(right)); 225 | } 226 | 227 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 228 | constexpr auto operator -(const SFixed & left, const SFixed & right) 229 | -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed > 230 | { 231 | using LeftType = SFixed; 232 | using RightType = SFixed; 233 | 234 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator - has ambiguous result"); 235 | 236 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 237 | 238 | return (static_cast(left) - static_cast(right)); 239 | } 240 | 241 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 242 | constexpr auto operator *(const SFixed & left, const SFixed & right) 243 | -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed > 244 | { 245 | using LeftType = SFixed; 246 | using RightType = SFixed; 247 | 248 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator * has ambiguous result"); 249 | 250 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 251 | 252 | return (static_cast(left) * static_cast(right)); 253 | } 254 | 255 | 256 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 257 | constexpr auto operator /(const SFixed & left, const SFixed & right) 258 | -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed > 259 | { 260 | using LeftType = SFixed; 261 | using RightType = SFixed; 262 | 263 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator / has ambiguous result"); 264 | 265 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 266 | 267 | return (static_cast(left) / static_cast(right)); 268 | } 269 | 270 | // 271 | // Literal-type Operators 272 | // Generated by macro to make maintenance easier 273 | // 274 | 275 | #define LOGIC_OPERATOR( type, op )\ 276 | template< unsigned Integer, unsigned Fraction >\ 277 | constexpr bool operator op (const SFixed & left, const type & right)\ 278 | {\ 279 | return (left op SFixed(right));\ 280 | }\ 281 | \ 282 | template< unsigned Integer, unsigned Fraction >\ 283 | constexpr bool operator op (const type & left, const SFixed & right)\ 284 | {\ 285 | return (SFixed(left) op right);\ 286 | } 287 | 288 | #define ARITHMETIC_OPERATOR( type, op )\ 289 | template< unsigned Integer, unsigned Fraction >\ 290 | constexpr SFixed operator op (const SFixed & left, const type & right)\ 291 | {\ 292 | return (left op SFixed(right));\ 293 | }\ 294 | \ 295 | template< unsigned Integer, unsigned Fraction >\ 296 | constexpr SFixed operator op (const type & left, const SFixed & right)\ 297 | {\ 298 | return (SFixed(left) op right);\ 299 | } 300 | 301 | #define DELETED_BITSHIFT_OPERATOR( type, op )\ 302 | template< unsigned Integer, unsigned Fraction >\ 303 | constexpr SFixed operator op (const SFixed & left, const type & right) = delete;\ 304 | \ 305 | template< unsigned Integer, unsigned Fraction >\ 306 | inline SFixed operator op##= (const SFixed & left, const type & right) = delete; 307 | 308 | #define BITSHIFT_OPERATOR( type, op )\ 309 | template< unsigned Integer, unsigned Fraction >\ 310 | constexpr SFixed operator op (const SFixed & left, const type & right)\ 311 | {\ 312 | using InternalType = typename SFixed::InternalType;\ 313 | return SFixed::fromInternal(static_cast(left.getInternal() op right));\ 314 | }\ 315 | \ 316 | template< unsigned Integer, unsigned Fraction >\ 317 | inline SFixed & operator op##= (SFixed & left, const type & right)\ 318 | {\ 319 | left = (left op right);\ 320 | return left;\ 321 | } 322 | 323 | #define LOGIC_OPERATORS( type )\ 324 | LOGIC_OPERATOR( type, == )\ 325 | LOGIC_OPERATOR( type, != )\ 326 | LOGIC_OPERATOR( type, < )\ 327 | LOGIC_OPERATOR( type, <= )\ 328 | LOGIC_OPERATOR( type, > )\ 329 | LOGIC_OPERATOR( type, >= ) 330 | 331 | #define ARITHMETIC_OPERATORS( type ) \ 332 | ARITHMETIC_OPERATOR( type, + )\ 333 | ARITHMETIC_OPERATOR( type, - )\ 334 | ARITHMETIC_OPERATOR( type, * )\ 335 | ARITHMETIC_OPERATOR( type, / ) 336 | 337 | #define DELETED_BITSHIFT_OPERATORS( type ) \ 338 | DELETED_BITSHIFT_OPERATOR( type, << )\ 339 | DELETED_BITSHIFT_OPERATOR( type, >> ) 340 | 341 | #define BITSHIFT_OPERATORS( type ) \ 342 | BITSHIFT_OPERATOR( type, << )\ 343 | BITSHIFT_OPERATOR( type, >> ) 344 | 345 | #define FLOAT_OPERATORS( type ) \ 346 | LOGIC_OPERATORS( type )\ 347 | ARITHMETIC_OPERATORS( type )\ 348 | DELETED_BITSHIFT_OPERATORS( type ) 349 | 350 | #define INTEGER_OPERATORS( type ) \ 351 | LOGIC_OPERATORS( type )\ 352 | ARITHMETIC_OPERATORS( type )\ 353 | BITSHIFT_OPERATORS( type ) 354 | 355 | FLOAT_OPERATORS( float ) 356 | FLOAT_OPERATORS( double ) 357 | FLOAT_OPERATORS( long double ) 358 | 359 | INTEGER_OPERATORS( char ) 360 | INTEGER_OPERATORS( unsigned char ) 361 | INTEGER_OPERATORS( signed char ) 362 | INTEGER_OPERATORS( unsigned short int ) 363 | INTEGER_OPERATORS( signed short int ) 364 | INTEGER_OPERATORS( unsigned int ) 365 | INTEGER_OPERATORS( signed int ) 366 | INTEGER_OPERATORS( unsigned long int ) 367 | INTEGER_OPERATORS( signed long int ) 368 | INTEGER_OPERATORS( unsigned long long int ) 369 | INTEGER_OPERATORS( signed long long int ) 370 | 371 | // Prevent Macro-bleed: 372 | 373 | #undef INTEGER_OPERATORS 374 | #undef FLOAT_OPERATORS 375 | 376 | #undef ARITHMETIC_OPERATORS 377 | #undef LOGIC_OPERATORS 378 | #undef BITSHIFT_OPERATORS 379 | #undef DELETED_BITSHIFT_OPERATORS 380 | 381 | #undef ARITHMETIC_OPERATOR 382 | #undef LOGIC_OPERATOR 383 | #undef BITSHIFT_OPERATOR 384 | #undef DELETED_BITSHIFT_OPERATOR 385 | 386 | FIXED_POINTS_END_NAMESPACE -------------------------------------------------------------------------------- /src/FixedPoints/UFixedFreeFunctions.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2021 Pharap 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | FIXED_POINTS_BEGIN_NAMESPACE 16 | 17 | // 18 | // multiply 19 | // 20 | 21 | template< unsigned Integer, unsigned Fraction > 22 | constexpr UFixed multiply(const UFixed & left, const UFixed & right) 23 | { 24 | static_assert((Integer * 2 + Fraction * 2) <= FIXED_POINTS_DETAILS::BitSize::Value, "Multiplication cannot be performed, the result type would be too large"); 25 | 26 | using ResultType = UFixed; 27 | using InternalType = typename ResultType::InternalType; 28 | return ResultType::fromInternal(static_cast(static_cast(left.getInternal()) * static_cast(right.getInternal()))); 29 | } 30 | 31 | // 32 | // Postincrement and Postdecrement 33 | // 34 | 35 | template< unsigned Integer, unsigned Fraction > 36 | UFixed operator ++(UFixed & value, int) 37 | { 38 | const auto oldValue = value; 39 | ++value; 40 | return oldValue; 41 | } 42 | 43 | template< unsigned Integer, unsigned Fraction > 44 | UFixed operator --(UFixed & value, int) 45 | { 46 | const auto oldValue = value; 47 | --value; 48 | return oldValue; 49 | } 50 | 51 | // 52 | // Basic Logic Operations 53 | // 54 | 55 | template< unsigned Integer, unsigned Fraction > 56 | constexpr bool operator ==(const UFixed & left, const UFixed & right) 57 | { 58 | return (left.getInternal() == right.getInternal()); 59 | } 60 | 61 | template< unsigned Integer, unsigned Fraction > 62 | constexpr bool operator !=(const UFixed & left, const UFixed & right) 63 | { 64 | return (left.getInternal() != right.getInternal()); 65 | } 66 | 67 | template< unsigned Integer, unsigned Fraction > 68 | constexpr bool operator <(const UFixed & left, const UFixed & right) 69 | { 70 | return (left.getInternal() < right.getInternal()); 71 | } 72 | 73 | template< unsigned Integer, unsigned Fraction > 74 | constexpr bool operator >(const UFixed & left, const UFixed & right) 75 | { 76 | return (left.getInternal() > right.getInternal()); 77 | } 78 | 79 | template< unsigned Integer, unsigned Fraction > 80 | constexpr bool operator <=(const UFixed & left, const UFixed & right) 81 | { 82 | return (left.getInternal() <= right.getInternal()); 83 | } 84 | 85 | template< unsigned Integer, unsigned Fraction > 86 | constexpr bool operator >=(const UFixed & left, const UFixed & right) 87 | { 88 | return (left.getInternal() >= right.getInternal()); 89 | } 90 | 91 | // 92 | // Inter-size Logic Operations 93 | // 94 | 95 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 96 | constexpr bool operator ==(const UFixed & left, const UFixed & right) 97 | { 98 | using LeftType = UFixed; 99 | using RightType = UFixed; 100 | 101 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator == has ambiguous result"); 102 | 103 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 104 | 105 | return (static_cast(left) == static_cast(right)); 106 | } 107 | 108 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 109 | constexpr bool operator !=(const UFixed & left, const UFixed & right) 110 | { 111 | using LeftType = UFixed; 112 | using RightType = UFixed; 113 | 114 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator != has ambiguous result"); 115 | 116 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 117 | 118 | return (static_cast(left) != static_cast(right)); 119 | } 120 | 121 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 122 | constexpr bool operator <(const UFixed & left, const UFixed & right) 123 | { 124 | using LeftType = UFixed; 125 | using RightType = UFixed; 126 | 127 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator < has ambiguous result"); 128 | 129 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 130 | 131 | return (static_cast(left) < static_cast(right)); 132 | } 133 | 134 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 135 | constexpr bool operator >(const UFixed & left, const UFixed & right) 136 | { 137 | using LeftType = UFixed; 138 | using RightType = UFixed; 139 | 140 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator > has ambiguous result"); 141 | 142 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 143 | 144 | return (static_cast(left) > static_cast(right)); 145 | } 146 | 147 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 148 | constexpr bool operator <=(const UFixed & left, const UFixed & right) 149 | { 150 | using LeftType = UFixed; 151 | using RightType = UFixed; 152 | 153 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator <= has ambiguous result"); 154 | 155 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 156 | 157 | return (static_cast(left) <= static_cast(right)); 158 | } 159 | 160 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 161 | constexpr bool operator >=(const UFixed & left, const UFixed & right) 162 | { 163 | using LeftType = UFixed; 164 | using RightType = UFixed; 165 | 166 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator >= has ambiguous result"); 167 | 168 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 169 | 170 | return (static_cast(left) >= static_cast(right)); 171 | } 172 | 173 | // 174 | // Basic Arithmetic Operations 175 | // 176 | 177 | template< unsigned Integer, unsigned Fraction > 178 | constexpr UFixed operator +(const UFixed & left, const UFixed & right) 179 | { 180 | using InternalType = typename UFixed::InternalType; 181 | return UFixed::fromInternal(static_cast(left.getInternal() + right.getInternal())); 182 | } 183 | 184 | template< unsigned Integer, unsigned Fraction > 185 | constexpr UFixed operator -(const UFixed & left, const UFixed & right) 186 | { 187 | using InternalType = typename UFixed::InternalType; 188 | return UFixed::fromInternal(static_cast(left.getInternal() - right.getInternal())); 189 | } 190 | 191 | template< unsigned Integer, unsigned Fraction > 192 | constexpr UFixed operator *(const UFixed & left, const UFixed & right) 193 | { 194 | static_assert((Integer * 2 + Fraction * 2) <= FIXED_POINTS_DETAILS::BitSize::Value, "Multiplication cannot be performed, the intermediary type would be too large"); 195 | 196 | using InternalType = typename UFixed::InternalType; 197 | using PrecisionType = typename UFixed::InternalType; 198 | return UFixed::fromInternal(static_cast((static_cast(left.getInternal()) * static_cast(right.getInternal())) >> Fraction)); 199 | } 200 | 201 | template< unsigned Integer, unsigned Fraction > 202 | constexpr UFixed operator /(const UFixed & left, const UFixed & right) 203 | { 204 | using InternalType = typename UFixed::InternalType; 205 | using PrecisionType = typename UFixed::InternalType; 206 | return UFixed::fromInternal(static_cast((static_cast(left.getInternal()) << Fraction) / static_cast(right.getInternal()))); 207 | } 208 | 209 | // 210 | // Inter-size Arithmetic Operations 211 | // 212 | 213 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 214 | constexpr auto operator +(const UFixed & left, const UFixed & right) 215 | -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed > 216 | { 217 | using LeftType = UFixed; 218 | using RightType = UFixed; 219 | 220 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator + has ambiguous result"); 221 | 222 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 223 | 224 | return (static_cast(left) + static_cast(right)); 225 | } 226 | 227 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 228 | constexpr auto operator -(const UFixed & left, const UFixed & right) 229 | -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed > 230 | { 231 | using LeftType = UFixed; 232 | using RightType = UFixed; 233 | 234 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator - has ambiguous result"); 235 | 236 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 237 | 238 | return (static_cast(left) - static_cast(right)); 239 | } 240 | 241 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 242 | constexpr auto operator *(const UFixed & left, const UFixed & right) 243 | -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed > 244 | { 245 | using LeftType = UFixed; 246 | using RightType = UFixed; 247 | 248 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator * has ambiguous result"); 249 | 250 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 251 | 252 | return (static_cast(left) * static_cast(right)); 253 | } 254 | 255 | 256 | template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > 257 | constexpr auto operator /(const UFixed & left, const UFixed & right) 258 | -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed > 259 | { 260 | using LeftType = UFixed; 261 | using RightType = UFixed; 262 | 263 | static_assert(LeftType::InternalSize != RightType::InternalSize, "operator / has ambiguous result"); 264 | 265 | using CompareType = FIXED_POINTS_DETAILS::LargerType; 266 | 267 | return (static_cast(left) / static_cast(right)); 268 | } 269 | 270 | // 271 | // Literal-type Operators 272 | // Generated by macro to make maintenance easier 273 | // 274 | 275 | #define LOGIC_OPERATOR( type, op )\ 276 | template< unsigned Integer, unsigned Fraction >\ 277 | constexpr bool operator op (const UFixed & left, const type & right)\ 278 | {\ 279 | return (left op UFixed(right));\ 280 | }\ 281 | \ 282 | template< unsigned Integer, unsigned Fraction >\ 283 | constexpr bool operator op (const type & left, const UFixed & right)\ 284 | {\ 285 | return (UFixed(left) op right);\ 286 | } 287 | 288 | #define ARITHMETIC_OPERATOR( type, op )\ 289 | template< unsigned Integer, unsigned Fraction >\ 290 | constexpr UFixed operator op (const UFixed & left, const type & right)\ 291 | {\ 292 | return (left op UFixed(right));\ 293 | }\ 294 | \ 295 | template< unsigned Integer, unsigned Fraction >\ 296 | constexpr UFixed operator op (const type & left, const UFixed & right)\ 297 | {\ 298 | return (UFixed(left) op right);\ 299 | } 300 | 301 | #define DELETED_BITSHIFT_OPERATOR( type, op )\ 302 | template< unsigned Integer, unsigned Fraction >\ 303 | constexpr UFixed operator op (const UFixed & left, const type & right) = delete;\ 304 | \ 305 | template< unsigned Integer, unsigned Fraction >\ 306 | inline UFixed operator op##= (const UFixed & left, const type & right) = delete; 307 | 308 | #define BITSHIFT_OPERATOR( type, op )\ 309 | template< unsigned Integer, unsigned Fraction >\ 310 | constexpr UFixed operator op (const UFixed & left, const type & right)\ 311 | {\ 312 | using InternalType = typename UFixed::InternalType;\ 313 | return UFixed::fromInternal(static_cast(left.getInternal() op right));\ 314 | }\ 315 | \ 316 | template< unsigned Integer, unsigned Fraction >\ 317 | inline UFixed & operator op##= (UFixed & left, const type & right)\ 318 | {\ 319 | left = (left op right);\ 320 | return left;\ 321 | } 322 | 323 | #define LOGIC_OPERATORS( type )\ 324 | LOGIC_OPERATOR( type, == )\ 325 | LOGIC_OPERATOR( type, != )\ 326 | LOGIC_OPERATOR( type, < )\ 327 | LOGIC_OPERATOR( type, <= )\ 328 | LOGIC_OPERATOR( type, > )\ 329 | LOGIC_OPERATOR( type, >= ) 330 | 331 | #define ARITHMETIC_OPERATORS( type ) \ 332 | ARITHMETIC_OPERATOR( type, + )\ 333 | ARITHMETIC_OPERATOR( type, - )\ 334 | ARITHMETIC_OPERATOR( type, * )\ 335 | ARITHMETIC_OPERATOR( type, / ) 336 | 337 | #define DELETED_BITSHIFT_OPERATORS( type ) \ 338 | DELETED_BITSHIFT_OPERATOR( type, << )\ 339 | DELETED_BITSHIFT_OPERATOR( type, >> ) 340 | 341 | #define BITSHIFT_OPERATORS( type ) \ 342 | BITSHIFT_OPERATOR( type, << )\ 343 | BITSHIFT_OPERATOR( type, >> ) 344 | 345 | #define FLOAT_OPERATORS( type ) \ 346 | LOGIC_OPERATORS( type )\ 347 | ARITHMETIC_OPERATORS( type )\ 348 | DELETED_BITSHIFT_OPERATORS( type ) 349 | 350 | #define INTEGER_OPERATORS( type ) \ 351 | LOGIC_OPERATORS( type )\ 352 | ARITHMETIC_OPERATORS( type )\ 353 | BITSHIFT_OPERATORS( type ) 354 | 355 | FLOAT_OPERATORS( float ) 356 | FLOAT_OPERATORS( double ) 357 | FLOAT_OPERATORS( long double ) 358 | 359 | INTEGER_OPERATORS( char ) 360 | INTEGER_OPERATORS( unsigned char ) 361 | INTEGER_OPERATORS( signed char ) 362 | INTEGER_OPERATORS( unsigned short int ) 363 | INTEGER_OPERATORS( signed short int ) 364 | INTEGER_OPERATORS( unsigned int ) 365 | INTEGER_OPERATORS( signed int ) 366 | INTEGER_OPERATORS( unsigned long int ) 367 | INTEGER_OPERATORS( signed long int ) 368 | INTEGER_OPERATORS( unsigned long long int ) 369 | INTEGER_OPERATORS( signed long long int ) 370 | 371 | // Prevent Macro-bleed: 372 | 373 | #undef INTEGER_OPERATORS 374 | #undef FLOAT_OPERATORS 375 | 376 | #undef ARITHMETIC_OPERATORS 377 | #undef LOGIC_OPERATORS 378 | #undef BITSHIFT_OPERATORS 379 | #undef DELETED_BITSHIFT_OPERATORS 380 | 381 | #undef ARITHMETIC_OPERATOR 382 | #undef LOGIC_OPERATOR 383 | #undef BITSHIFT_OPERATOR 384 | #undef DELETED_BITSHIFT_OPERATOR 385 | 386 | FIXED_POINTS_END_NAMESPACE --------------------------------------------------------------------------------