Add files via upload

pull/3/head v1.0.0
Pharap 7 years ago committed by GitHub
parent 34915f6186
commit 393acd2f49
  1. 201
      LICENCE
  2. 149
      README.md
  3. 170
      examples/FixedPointCalculations/FixedPointCalculations.ino
  4. 69
      extras/AFixedPointPrimer.md
  5. 14
      extras/Credits.md
  6. 8
      extras/Hello.txt
  7. 6
      extras/Important.txt
  8. 47
      keywords.txt
  9. 19
      library.json
  10. 10
      library.properties
  11. 1
      src/FixedPoints.h
  12. 219
      src/FixedPoints/Details.h
  13. 9
      src/FixedPoints/FixedPoints.h
  14. 205
      src/FixedPoints/SFixed.h
  15. 64
      src/FixedPoints/SFixedBase.h
  16. 297
      src/FixedPoints/SFixedFreeFunctions.h
  17. 175
      src/FixedPoints/SFixedMemberFunctions.h
  18. 205
      src/FixedPoints/UFixed.h
  19. 64
      src/FixedPoints/UFixedBase.h
  20. 297
      src/FixedPoints/UFixedFreeFunctions.h
  21. 155
      src/FixedPoints/UFixedMemberFunctions.h
  22. 233
      src/FixedPoints/Utils.h
  23. 1
      src/FixedPointsCommon.h
  24. 4
      src/FixedPointsCommon/FixedPointsCommon.h
  25. 15
      src/FixedPointsCommon/SFixedCommon.h
  26. 15
      src/FixedPointsCommon/UFixedCommon.h

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -1,2 +1,147 @@
# FixedPointsArduino
A Fixed Points Library For Arduino
# FixedPoints
A portable fixed point arithmetic library.
Some knowledge of how fixed point types are formatted is required to used this library to full effect.
No knowledge of how these operations are implemented is required to use them.
This library was written with Arduino in mind, as well as CPUs with limited floating point support.
However, given the templated nature of the library, it should still function on a wide variety of CPUs.
## Requirements:
- The Compiler must be C++11 compliant.
- The user should ideally be familar with the [Q number format](https://en.wikipedia.org/wiki/Q_(number_format)) for fixed points.
## Licence
This code uses the Apache 2.0 Licence.
This means:
- This code comes with no warranty.
- The licensor and any contributors cannot be held liable for damages.
- If you use this code, edited or unedited, you must:
- Package a copy of LICENCE with your code.
- Package a copy of NOTICE with your code.
- You may modify the source code.
- If you modify a file, you must state this prominently in the file (i.e. in a comment at the top).
- Any modified code may use a different licence.
- Any unmodified code must carry the same Apache 2.0 licence.
- You may not use any trademarks owned by the licensor.
## Contents
This library supplies two core types and sixteen type aliases.
### Core Types:
The core types are provided by `FixedPoints.h`.
- `UFixed<I, F>`: 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.
- `SFixed<I, F>`: 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.
### Aliases:
The common aliases are provided by `FixedPointsCommon.h`.
- `UQ4x4`: An alias for `UFixed<4, 4>`, an 8-bit unsigned fixed point in the Q4.4 format.
- `UQ8x8`: An alias for `UFixed<8, 8>`, a 16-bit unsigned fixed point in the Q8.8 format.
- `UQ16x16`: An alias for `UFixed<16, 16>`, a 32-bit unsigned fixed point in the Q16.16 format.
- `UQ32x32`: An alias for `UFixed<32, 32>`, a 64-bit unsigned fixed point in the Q32.32 format.
- `UQ1x7`: An alias for `UFixed<1, 7>`, an 8-bit unsigned fixed point in the Q1.7 format.
- `UQ1x15`: An alias for `UFixed<1, 15>`, a 16-bit unsigned fixed point in the Q1.15 format.
- `UQ1x31`: An alias for `UFixed<1, 31>`, a 32-bit unsigned fixed point in the Q1.31 format.
- `UQ1x63`: An alias for `UFixed<1, 63>`, a 64-bit unsigned fixed point in the Q1.63 format.
- `SQ3x4`: An alias for `SFixed<3, 4>`, an 8-bit signed fixed point in the Q3.4 format with implicit sign bit.
- `SQ7x8`: An alias for `SFixed<7, 8>`, a 16-bit signed fixed point in the Q7.8 format with implicit sign bit.
- `SQ15x16`: An alias for `SFixed<15, 16>`, a 32-bit signed fixed point in the Q15.16 format with implicit sign bit.
- `SQ31x32`: An alias for `SFixed<31, 32>`, a 64-bit signed fixed point in the Q31.32 format with implicit sign bit.
- `SQ1x6`: An alias for `SFixed<1, 6>`, an 8-bit signed fixed point in the Q1.6 format with implicit sign bit.
- `SQ1x14`: An alias for `SFixed<1, 14>`, a 16-bit signed fixed point in the Q1.14 format with implicit sign bit.
- `SQ1x30`: An alias for `SFixed<1, 30>`, a 32-bit signed fixed point in the Q1.30 format with implicit sign bit.
- `SQ1x62`: An alias for `SFixed<1, 62>`, a 64-bit signed fixed point in the Q1.62 format with implicit sign bit.
([About Q Format](https://en.wikipedia.org/wiki/Q_(number_format)).)
### Operators:
- `+`: Adds two `UFixed`s or two `SFixed`s
- `-`: Subtracts two `UFixed`s or two `SFixed`s
- `*`: Multiplies two `UFixed`s or two `SFixed`s
- `/`: Divides two `UFixed`s or two `SFixed`s
- `==`: Compares two `UFixed`s or two `SFixed`s
- `!=`: Compares two `UFixed`s or two `SFixed`s
- `<`: Compares two `UFixed`s or two `SFixed`s
- `<=`: Compares two `UFixed`s or two `SFixed`s
- `>`: Compares two `UFixed`s or two `SFixed`s
- `>=`: Compares two `UFixed`s or two `SFixed`s
### Free Functions:
- `floorFixed`: The floor operation.
- `ceilFixed`: The Ceiling operation
- `roundFixed`: Rounding operation.
- `truncFixed`: Truncation operation.
- `signbitFixed`: Returns `true` for signed numbers and `false` for unsigned numbers.
- `copysignFixed`: Returns a value with the magnitude of the first argument and the sign of the second argument.
- `multiply`: Multiplies two `UFixed`s or two `SFixed`s, returns a result that is twice the resolution of the input.
### Member Functions:
- `UFixed<I, F>::getInteger`: Gets the integer part of an unsigned fixed point.
- `UFixed<I, F>::getFraction`: Gets the fractional part of an unsigned fixed point.
- `UFixed<I, F>::getInternal`: Gets the internal representation of an unsigned fixed point.
- `SFixed<I, F>::getInteger`: Gets the integer part of a signed fixed point.
- `SFixed<I, F>::getFraction`: Gets the fractional part of a signed fixed point.
- `SFixed<I, F>::getInternal`: Gets the internal representation of a signed fixed point.
### Static Functions:
- `UFixed<I, F>::fromInternal`: Produces an unsigned fixed point number from its internal representation.
- `SFixed<I, F>::fromInternal`: Produces a signed fixed point number from its internal representation.
## Construction:
Note that both `UFixed<I, F>` and `SFixed<I, F>` are implicitly compile-time constructable from all integer and decimal literals.
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`.
`UFixed<I, F>` is constructable from:
- Any integer literal type, regardless of sign.
-- This constructs the fixed point as an integer with no fractional part.
-- A value that does not fit shall be truncated without warning.
-- If a constant value is used, the fixed point shall be constructed at compile time.
- An unsigned integer part and an unsigned fractional part.
-- The integer part is of the smallest type capable of representing `I` bits.
-- The fractional part is of the smallest type capable of representing `F` bits.
-- If constant values are used, the fixed point shall be constructed at compile time.
- Any decimal literal type, regardless of sign.
-- This constructs the fixed point as a best approximation of the provided value.
-- A value that does not fit shall be truncated without warning.
-- If a constant value is used, the fixed point shall be constructed at compile time.
`SFixed<I, F>` is constructable from:
- Any integer literal type, regardless of sign.
-- This constructs the fixed point as an integer with no fractional part.
-- A value that does not fit shall be truncated without warning.
-- If a constant value is used, the fixed point shall be constructed at compile time.
- A signed integer part and an unsigned fractional part.
-- The integer part is of the smallest type capable of representing `I + 1` bits.
-- The fractional part is of the smallest type capable of representing `F` bits.
-- If constant values are used, the fixed point shall be constructed at compile time.
- Any decimal literal type, regardless of sign.
-- This constructs the fixed point as a best approximation of the provided value.
-- A value that does not fit shall be truncated without warning.
-- If a constant value is used, the fixed point shall be constructed at compile time.
### Casts:
`UFixed<I, F>` is explicitly convertible to:
- `float`.
- `double`.
- The smallest unsigned type capable of holding its integer part. I.e. a type of at least `I` bits.
- Another `UFixed` type of a different scale. E.g. `UFixed<4, 4>` may be converted to `UFixed<8, 8>` and vice versa.
`SFixed<I, F>` is explicitly convertible to:
- `float`.
- `double`.
- The smallest signed type capable of holding its integer part. I.e. a type of at least `I + 1` bits.
- Another `SFixed` type of a different scale. E.g. `SFixed<3, 4>` may be converted to `SFixed<7, 8>` and vice versa.

@ -0,0 +1,170 @@
#include <FixedPoints.h>
#include <FixedPointsCommon.h>
void TestUQ8x8(void)
{
Serial.println(F("The size of UQ8x8 on your system is:"));
Serial.println(sizeof(UQ8x8));
Serial.println();
UQ8x8 a = 1.5;
Serial.println(F("Displaying a as float:"));
Serial.println(static_cast<float>(a));
Serial.println();
Serial.println(F("Displaying the integer part of a"));
Serial.println(a.getInteger());
Serial.println();
Serial.println(F("Displaying floorFixed(a):"));
Serial.println(static_cast<float>(floorFixed(a)));
Serial.println();
Serial.println(F("Displaying ceilFixed(a):"));
Serial.println(static_cast<float>(ceilFixed(a)));
Serial.println();
Serial.println(F("Displaying roundFixed(a):"));
Serial.println(static_cast<float>(roundFixed(a)));
Serial.println();
Serial.println(F("Displaying truncFixed(a):"));
Serial.println(static_cast<float>(truncFixed(a)));
Serial.println();
UQ8x8 b = 5.25;
Serial.println(F("Displaying b as float:"));
Serial.println(static_cast<float>(b));
Serial.println();
Serial.println(F("Displaying the integer part of b"));
Serial.println(b.getInteger());
Serial.println();
Serial.println(F("Displaying floorFixed(b):"));
Serial.println(static_cast<float>(floorFixed(b)));
Serial.println();
Serial.println(F("Displaying ceilFixed(b):"));
Serial.println(static_cast<float>(ceilFixed(b)));
Serial.println();
Serial.println(F("Displaying roundFixed(b):"));
Serial.println(static_cast<float>(roundFixed(b)));
Serial.println();
Serial.println(F("Displaying truncFixed(b):"));
Serial.println(static_cast<float>(truncFixed(b)));
Serial.println();
Serial.println(F("Displaying a + b as float:"));
Serial.println(static_cast<float>(a + b));
Serial.println();
Serial.println(F("Displaying a - b as float:"));
Serial.println(F("(Note the underflow due lack of sign bit)"));
Serial.println(static_cast<float>(a - b));
Serial.println();
Serial.println(F("Displaying b - a as float:"));
Serial.println(static_cast<float>(b - a));
Serial.println();
Serial.println(F("Displaying a * b as float:"));
Serial.println(static_cast<float>(a * b));
Serial.println();
Serial.println(F("Displaying a / b as float:"));
Serial.println(static_cast<float>(a / b));
Serial.println();
}
void TestSQ7x8(void)
{
Serial.println(F("The size of SQ7x8 on your system is:"));
Serial.println(sizeof(SQ7x8));
Serial.println();
SQ7x8 a = 1.5;
Serial.println(F("Displaying a as float:"));
Serial.println(static_cast<float>(a));
Serial.println();
Serial.println(F("Displaying the integer part of a"));
Serial.println(a.getInteger());
Serial.println();
Serial.println(F("Displaying floorFixed(a):"));
Serial.println(static_cast<float>(floorFixed(a)));
Serial.println();
Serial.println(F("Displaying ceilFixed(a):"));
Serial.println(static_cast<float>(ceilFixed(a)));
Serial.println();
Serial.println(F("Displaying roundFixed(a):"));
Serial.println(static_cast<float>(roundFixed(a)));
Serial.println();
Serial.println(F("Displaying truncFixed(a):"));
Serial.println(static_cast<float>(truncFixed(a)));
Serial.println();
SQ7x8 b = 5.25;
Serial.println(F("Displaying b as float:"));
Serial.println(static_cast<float>(b));
Serial.println();
Serial.println(F("Displaying the integer part of b"));
Serial.println(b.getInteger());
Serial.println();
Serial.println(F("Displaying floorFixed(b):"));
Serial.println(static_cast<float>(floorFixed(b)));
Serial.println();
Serial.println(F("Displaying ceilFixed(b):"));
Serial.println(static_cast<float>(ceilFixed(b)));
Serial.println();
Serial.println(F("Displaying roundFixed(b):"));
Serial.println(static_cast<float>(roundFixed(b)));
Serial.println();
Serial.println(F("Displaying truncFixed(b):"));
Serial.println(static_cast<float>(truncFixed(b)));
Serial.println();
Serial.println(F("Displaying a + b as float:"));
Serial.println(static_cast<float>(a + b));
Serial.println();
Serial.println(F("Displaying a - b as float:"));
Serial.println(F("(Note this is correct due to sign bit)"));
Serial.println(static_cast<float>(a - b));
Serial.println();
Serial.println(F("Displaying b - a as float:"));
Serial.println(static_cast<float>(b - a));
Serial.println();
Serial.println(F("Displaying a * b as float:"));
Serial.println(static_cast<float>(a * b));
Serial.println();
Serial.println(F("Displaying a / b as float:"));
Serial.println(static_cast<float>(a / b));
Serial.println();
}
void setup()
{
while(!Serial);
TestUQ8x8();
TestSQ7x8();
}
void loop()
{
}

@ -0,0 +1,69 @@
# A Fixed Point Primer
## What Are Fixed Point Numbers?
Normally computers operate on what are called 'integers'.
Integers are numbers that do not have a fractional component in them.
For example 0, 1, 42, 128, 10000 are all integers
Numbers that do have a fractional component are called 'rational' numbers.
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)
For example 0.5, 1.75, 42.42, 128.367 and 10000.00001 are all rational numbers.
Normally computers represent these in what is called a 'floating point' format.
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.
Another way to represent real numbers is what is called a 'fixed point' format.
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.
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).
## Why Use Fixed Point Numbers?
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.
Almost all modern CPUs have floating point capabilities built into them.
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.
This is where fixed points come in.
By limiting the format so that the radix point is fixed in place, the implementation of fixed point numbers becomes a lot simpler.
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.
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.
## Why Aren't Fixed Point Numbers Used More Often?
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.
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.
Indeed, finding information about fixed point numbers can be quite a struggle.
## How Do Fixed Points Work?
Fixed point numbers are comprised of two parts, the integer part and the fractional part.
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.
The integer part stores the digits to the left of the radix point.
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.
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.
The fractional part stores the digits to the right of the radix point.
This part has special behaviour that can be a bit tricky to comprehend at first.
The simplest way to think of it is as a fraction.
For example in the `Q8.8` format, there are `8` bits for the fractional part, which means it is capable of holding `256` values.
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`.
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`.
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`.
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`.
## Further Reading
- Wikipedia's article about [Radix Points](https://en.wikipedia.org/wiki/Radix_point)
- Wikipedia's article about [Integers](https://en.wikipedia.org/wiki/Integer)
- Wikipedia's article about [Rational Numbers](https://en.wikipedia.org/wiki/Rational_number)

@ -0,0 +1,14 @@
## Main Credits:
- [Pharap](https://github.com/Pharap) - main programmer
## Extra special thanks to:
- [bakagamedev](https://github.com/bakagamedev) - extra-handy duck
- [filmote](https://github.com/filmote) - testing and debugging
- [eried](https://github.com/eried) - testing and debugging
## Special mentions:
- crait
- Bergasms

@ -0,0 +1,8 @@
/\___/\ ~
( O . O ) \\
> ^ < //
( \ / )//
u U U u
ヘロー エブリニャン!

@ -0,0 +1,6 @@
Do not attempt to use anything from the Details namespace.
Everything in the Details namespace is merely an implementation detail which may be changed without notice,
thus any attempt to use anything from the Details namespace may result in your own code breaking in future updates.
To wrap the fixed point types in the FixedPoints namespace (e.g. in case of name conflicts):
#define FIXED_POINTS_USE_NAMESPACE

@ -0,0 +1,47 @@
####################################
# Syntax Colouring For FixedPoints #
####################################
####################################
# Datatypes (KEYWORD1) #
####################################
SFixed KEYWORD1
UFixed KEYWORD1
UQ4x4 KEYWORD1
UQ8x8 KEYWORD1
UQ16x16 KEYWORD1
UQ32x32 KEYWORD1
UQ1x7 KEYWORD1
UQ1x15 KEYWORD1
UQ1x31 KEYWORD1
UQ1x63 KEYWORD1
SQ3x4 KEYWORD1
SQ7x8 KEYWORD1
SQ15x16 KEYWORD1
SQ31x32 KEYWORD1
SQ1x6 KEYWORD1
SQ1x14 KEYWORD1
SQ1x30 KEYWORD1
SQ1x62 KEYWORD1
####################################
# Methods and Functions (KEYWORD2) #
####################################
getInternal KEYWORD2
getInteger KEYWORD2
getFraction KEYWORD2
fromInternal KEYWORD2
multiply KEYWORD2
floorFixed KEYWORD2
ceilFixed KEYWORD2
roundFixed KEYWORD2
truncFixed KEYWORD2
signbitFixed KEYWORD2
absFixed KEYWORD2
copysignFixed KEYWORD2
nextafterFixed KEYWORD2
randomUFixed KEYWORD2
randomSFixed KEYWORD2

@ -0,0 +1,19 @@
{
"name": "FixedPoints",
"keywords": "maths, fixed, point, fixed point, arithmetic",
"description": "A portable templated header-only fixed point arithmetic library",
"repository": {
"type": "git",
"url": "https://github.com/Pharap/FixedPointsArduino.git"
},
"version": "1.0.0",
"authors": {
"name": "Pharap",
"url": "https://github.com/Pharap"
},
"exclude": [
"tests",
],
"frameworks": "arduino",
"platforms": "*"
}

@ -0,0 +1,10 @@
name=FixedPoints
version=1.0.0
author=Pharap
maintainer=Pharap
sentence=A template library for defining fixed point types of varying sizes.
paragraph=The library is designed to be generic so it should be applicable to almost all size requirements and processor architectures.
category=Data Processing
url=https://github.com/Pharap/FixedPointsArduino
architectures=*
includes=FixedPoints.h, FixedPointsCommon.h

@ -0,0 +1 @@
#include "FixedPoints/FixedPoints.h"

@ -0,0 +1,219 @@
#pragma once
#include <limits.h>
#include <stdint.h>
#if defined(FIXED_POINTS_USE_NAMESPACE)
#define FIXED_POINTS_NAMESPACE FixedPoints
#define FIXED_POINTS_BEGIN_NAMESPACE namespace FIXED_POINTS_NAMESPACE\
{
#define FIXED_POINTS_END_NAMESPACE }
#define FIXED_POINTS_DETAILS Details
#else
#define FIXED_POINTS_NAMESPACE
#define FIXED_POINTS_BEGIN_NAMESPACE
#define FIXED_POINTS_END_NAMESPACE
#define FIXED_POINTS_DETAILS FixedPointsDetails
#endif
// Pay no attention to the man behind the curtains
FIXED_POINTS_BEGIN_NAMESPACE
namespace FIXED_POINTS_DETAILS
{
template< typename T >
struct BitSize
{
BitSize(void) = delete;
constexpr static const auto Value = sizeof(T) * CHAR_BIT;
};
template< typename T, typename U = T >
constexpr auto Max(const T & left, const U & right) noexcept -> decltype((left > right) ? left : right)
{
return (left > right) ? left : right;
}
template< typename T, T Left, T Right >
constexpr auto Max(void) noexcept -> decltype((Left > Right) ? Left : Right)
{
return (Left > Right) ? Left : Right;
}
template< typename T, typename U = T >
constexpr auto Min(const T & left, const U & right) noexcept -> decltype((left < right) ? left : right)
{
return (left < right) ? left : right;
}
template< typename T, T Left, T Right >
constexpr auto Min(void) noexcept -> decltype((Left < Right) ? Left : Right)
{
return (Left < Right) ? Left : Right;
}
template< bool Condition, typename TTrue, typename TFalse >
struct Conditional;
template< typename TTrue, typename TFalse >
struct Conditional< true, TTrue, TFalse > { using Type = TTrue; };
template< typename TTrue, typename TFalse >
struct Conditional< false, TTrue, TFalse > { using Type = TFalse; };
template< bool Condition, typename TTrue, typename TFalse >
using ConditionalT = typename Conditional<Condition, TTrue, TFalse >::Type;
template< typename T, typename U >
using LargerType = ConditionalT<(BitSize<T>::Value > BitSize<U>::Value), T, U>;
template< typename T, typename U >
using StrictLargerType = ConditionalT< (BitSize<T>::Value > BitSize<U>::Value), T, ConditionalT< (BitSize<U>::Value > BitSize<T>::Value), U, void > >;
template< typename T, typename U >
using SmallerType = ConditionalT<(BitSize<T>::Value < BitSize<U>::Value), T, U>;
template< typename T, typename U >
using StrictSmallerType = ConditionalT< (BitSize<T>::Value < BitSize<U>::Value), T, ConditionalT< (BitSize<U>::Value < BitSize<T>::Value), U, void > >;
template< unsigned Bits, typename... Ts >
struct LeastTypeHelper;
template< unsigned Bits, typename T, typename... Ts >
struct LeastTypeHelper<Bits, T, Ts... >
{
LeastTypeHelper(void) = delete;
using Type = ConditionalT<(Bits <= BitSize<T>::Value), T, typename LeastTypeHelper<Bits, Ts...>::Type>;
};
template< unsigned Bits >
struct LeastTypeHelper<Bits>
{
LeastTypeHelper(void) = delete;
using Type = void;
};
template< unsigned Bits, typename... Ts >
using LeastType = typename LeastTypeHelper<Bits, Ts...>::Type;
template< unsigned Bits >
struct LeastUIntDef
{
static_assert(Bits <= BitSize<uintmax_t>::Value, "No type large enough");
LeastUIntDef(void) = delete;
using Type = LeastType<Bits, uint_least8_t, uint_least16_t, uint_least32_t, uint_least64_t, uintmax_t>;
};
template< unsigned Bits >
using LeastUInt = typename LeastUIntDef<Bits>::Type;
template< unsigned Bits >
struct LeastIntDef
{
static_assert(Bits <= BitSize<intmax_t>::Value, "No type large enough");
LeastIntDef(void) = delete;
using Type = LeastType<Bits, int_least8_t, int_least16_t, int_least32_t, int_least64_t, intmax_t>;
};
template< unsigned Bits >
using LeastInt = typename LeastIntDef<Bits>::Type;
template< unsigned Bits >
struct MsbMask
{
MsbMask(void) = delete;
constexpr const static LeastUInt<Bits> Value = (1ull << (Bits - 1));
};
template< unsigned Bits >
struct IdentityMask
{
IdentityMask(void) = delete;
constexpr const static LeastUInt<Bits> Value = 1 | (IdentityMask<Bits - 1>::Value << 1);
};
template<>
struct IdentityMask<0>
{
IdentityMask(void) = delete;
constexpr const static LeastUInt<0> Value = 0;
};
using IntegerLiteral = decltype(0);
using IntegerLiteralU = decltype(0U);
using IntegerLiteralL = decltype(0L);
using IntegerLiteralUL = decltype(0UL);
using IntegerLiteralLL = decltype(0LL);
using IntegerLiteralULL = decltype(0ULL);
using DecimalLiteral = decltype(0.0);
using DecimalLiteralF = decltype(0.0F);
using DecimalLiteralL = decltype(0.0L);
template< typename T >
struct RandomHelper;
template<>
struct RandomHelper<uint8_t>
{
static inline uint8_t Random() { return static_cast<uint8_t>(random()); }
};
template<>
struct RandomHelper<uint16_t>
{
static inline uint16_t Random() { return static_cast<uint16_t>(random()); }
};
template<>
struct RandomHelper<uint32_t>
{
static inline uint32_t Random() { return static_cast<uint32_t>(random()); }
};
template<>
struct RandomHelper<uint64_t>
{
static inline uint64_t Random() { return (static_cast<uint64_t>(random()) << 32) | static_cast<uint64_t>(random()); }
};
template<>
struct RandomHelper<int8_t>
{
static inline int8_t Random() { return static_cast<int8_t>(random()); }
};
template<>
struct RandomHelper<int16_t>
{
static inline int16_t Random() { return static_cast<int16_t>(random()); }
};
template<>
struct RandomHelper<int32_t>
{
static inline int32_t Random() { return static_cast<int32_t>(random()); }
};
template<>
struct RandomHelper<int64_t>
{
static inline int64_t Random() { return (static_cast<int64_t>(random()) << 32) | static_cast<int64_t>(random()); }
};
// Here be dragons!!
//
//
//
// /\___/\ ~
// ( O . O ) \\
// > ^ < //
// ( \ / )//
// u U U u
//
// Or cats?
// ~Mwrow~
}
FIXED_POINTS_END_NAMESPACE

@ -0,0 +1,9 @@
#include "Details.h"
#include "UFixedBase.h"
#include "SFixedBase.h"
#include "UFixed.h"
#include "SFixed.h"
#include "Utils.h"

@ -0,0 +1,205 @@
#pragma once
#include "Details.h"
#include "SFixedBase.h"
FIXED_POINTS_BEGIN_NAMESPACE
//
// Declaration
//
template< unsigned Integer, unsigned Fraction >
class SFixed : FIXED_POINTS_DETAILS::SFixedBase< Integer, Fraction >
{
public:
static_assert(((Integer + 1) + Fraction) <= FIXED_POINTS_DETAILS::BitSize<intmax_t>::Value, "Platform does not have a native type large enough for SFixed.");
public:
using IntegerType = FIXED_POINTS_DETAILS::LeastInt<Integer + 1>;
using FractionType = FIXED_POINTS_DETAILS::LeastUInt<Fraction>;
using InternalType = FIXED_POINTS_DETAILS::LeastInt<(Integer + 1) + Fraction>;
using ShiftType = FIXED_POINTS_DETAILS::LeastUInt<(Integer + 1) + Fraction>;
using MaskType = FIXED_POINTS_DETAILS::LeastUInt<(Integer + 1) + Fraction>;
constexpr const static unsigned IntegerSize = Integer + 1;
constexpr const static unsigned FractionSize = Fraction;
constexpr const static unsigned LogicalSize = IntegerSize + FractionSize;
constexpr const static unsigned InternalSize = FIXED_POINTS_DETAILS::BitSize<InternalType>::Value;
constexpr const static unsigned long long Scale = 1ULL << FractionSize;
public:
constexpr const static ShiftType IntegerShift = FractionSize;
constexpr const static ShiftType FractionShift = 0;
constexpr const static MaskType IntegerMask = FIXED_POINTS_DETAILS::IdentityMask<IntegerSize>::Value;
constexpr const static MaskType FractionMask = FIXED_POINTS_DETAILS::IdentityMask<FractionSize>::Value;
constexpr const static MaskType IdentityMask = (IntegerMask << IntegerShift) | (FractionMask << FractionShift);
constexpr const static MaskType MidpointMask = FIXED_POINTS_DETAILS::MsbMask<FractionSize>::Value;
constexpr const static MaskType LesserMidpointMask = MidpointMask - 1;
private:
using Base = FIXED_POINTS_DETAILS::SFixedBase<Integer, Fraction>;
using RawType = typename Base::RawType;
public:
using Base::Base;
constexpr SFixed(void);
constexpr SFixed(const IntegerType & integer);
constexpr SFixed(const IntegerType & integer, const FractionType & fraction);
constexpr InternalType getInternal(void) const;
constexpr IntegerType getInteger(void) const;
constexpr FractionType getFraction(void) const;
constexpr explicit operator IntegerType(void) const;
constexpr explicit operator float(void) const;
constexpr explicit operator double(void) const;
template< unsigned IntegerOut, unsigned FractionOut >
constexpr explicit operator SFixed<IntegerOut, FractionOut>(void) const;
constexpr static SFixed fromInternal(const InternalType & value);
constexpr SFixed operator -(void) const;
SFixed & operator ++(void);
SFixed & operator --(void);
SFixed & operator +=(const SFixed & other);
SFixed & operator -=(const SFixed & other);
SFixed & operator *=(const SFixed & other);
SFixed & operator /=(const SFixed & other);
public:
const static SFixed Epsilon;
const static SFixed MinValue;
const static SFixed MaxValue;
const static SFixed Pi;
const static SFixed E;
const static SFixed Phi;
const static SFixed Tau;
};
//
// Variables
//
template< unsigned Integer, unsigned Fraction >
constexpr const SFixed<Integer, Fraction> SFixed<Integer, Fraction>::Epsilon = SFixed<Integer, Fraction>::fromInternal(1);
template< unsigned Integer, unsigned Fraction >
constexpr const SFixed<Integer, Fraction> SFixed<Integer, Fraction>::MinValue = SFixed::fromInternal(FIXED_POINTS_DETAILS::MsbMask<InternalSize>::Value);
template< unsigned Integer, unsigned Fraction >
constexpr const SFixed<Integer, Fraction> SFixed<Integer, Fraction>::MaxValue = SFixed::fromInternal(~FIXED_POINTS_DETAILS::MsbMask<InternalSize>::Value);
// 40 digits is probably enough for these
template< unsigned Integer, unsigned Fraction >
constexpr const SFixed<Integer, Fraction> SFixed<Integer, Fraction>::Pi = 3.1415926535897932384626433832795028841971;
template< unsigned Integer, unsigned Fraction >
constexpr const SFixed<Integer, Fraction> SFixed<Integer, Fraction>::E = 2.718281828459045235360287471352662497757;
template< unsigned Integer, unsigned Fraction >
constexpr const SFixed<Integer, Fraction> SFixed<Integer, Fraction>::Phi = 1.6180339887498948482045868343656381177203;
template< unsigned Integer, unsigned Fraction >
constexpr const SFixed<Integer, Fraction> SFixed<Integer, Fraction>::Tau = 6.2831853071795864769252867665590057683943;
//
// Free functions
//
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer * 2, Fraction * 2> multiply(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right);
//
// Basic Logic Operations
//
template< unsigned Integer, unsigned Fraction >
constexpr bool operator ==(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr bool operator !=(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr bool operator <(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr bool operator >(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr bool operator <=(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr bool operator >=(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right);
//
// Inter-size Logic Operations
//
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator ==(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right);
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator !=(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right);
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator <(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right);
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator >(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right);
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator <=(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right);
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator >=(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right);
//
// Basic Arithmetic Operations
//
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> operator +(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> operator -(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> operator *(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> operator /(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right);
//
// Inter-size Arithmetic Operations
//
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator +(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< SFixed<IntegerLeft, FractionLeft>, SFixed<IntegerRight, FractionRight> >;
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator -(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< SFixed<IntegerLeft, FractionLeft>, SFixed<IntegerRight, FractionRight> >;
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator *(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< SFixed<IntegerLeft, FractionLeft>, SFixed<IntegerRight, FractionRight> >;
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
inline constexpr auto operator /(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< SFixed<IntegerLeft, FractionLeft>, SFixed<IntegerRight, FractionRight> >;
FIXED_POINTS_END_NAMESPACE
#include "SFixedMemberFunctions.h"
#include "SFixedFreeFunctions.h"

@ -0,0 +1,64 @@
#pragma once
#include "Details.h"
FIXED_POINTS_BEGIN_NAMESPACE
namespace FIXED_POINTS_DETAILS
{
template< unsigned Integer, unsigned Fraction >
class SFixedBase
{
public:
using IntegerType = FIXED_POINTS_DETAILS::LeastInt<Integer + 1>;
using FractionType = FIXED_POINTS_DETAILS::LeastUInt<Fraction>;
using InternalType = FIXED_POINTS_DETAILS::LeastInt<(Integer + 1) + Fraction>;
constexpr const static unsigned long long Scale = 1ULL << Fraction;
protected:
class RawType
{
private:
const InternalType value;
public:
constexpr inline explicit RawType(const InternalType & value) : value(value) {}
constexpr inline explicit operator InternalType(void) const { return this->value; }
};
protected:
InternalType value;
constexpr SFixedBase(void) : value(0) {}
constexpr SFixedBase(const RawType & value) : value(static_cast<InternalType>(value)) {}
public:
constexpr SFixedBase(const IntegerLiteral & value)
: value(static_cast<InternalType>(static_cast<LargerType<IntegerLiteral, InternalType> >(value) << Fraction)) {}
constexpr SFixedBase(const IntegerLiteralU & value)
: value(static_cast<InternalType>(static_cast<LargerType<IntegerLiteralU, InternalType> >(value) << Fraction)) {}
constexpr SFixedBase(const IntegerLiteralL & value)
: value(static_cast<InternalType>(static_cast<LargerType<IntegerLiteralL, InternalType> >(value) << Fraction)) {}
constexpr SFixedBase(const IntegerLiteralUL & value)
: value(static_cast<InternalType>(static_cast<LargerType<IntegerLiteralUL, InternalType>>(value) << Fraction)) {}
constexpr SFixedBase(const IntegerLiteralLL & value)
: value(static_cast<InternalType>(static_cast<LargerType<IntegerLiteralLL, InternalType>>(value) << Fraction)) {}
constexpr SFixedBase(const IntegerLiteralULL & value)
: value(static_cast<InternalType>(static_cast<LargerType<IntegerLiteralULL, InternalType> >(value) << Fraction)) {}
constexpr SFixedBase(const DecimalLiteral & value)
: value(static_cast<InternalType>(value * Scale)) {}
constexpr SFixedBase(const DecimalLiteralF & value)
: value(static_cast<InternalType>(value * Scale)) {}
constexpr SFixedBase(const DecimalLiteralL & value)
: value(static_cast<InternalType>(value * Scale)) {}
};
}
FIXED_POINTS_END_NAMESPACE

@ -0,0 +1,297 @@
FIXED_POINTS_BEGIN_NAMESPACE
//
// multiply
//
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer * 2, Fraction * 2> multiply(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
{
using ResultType = SFixed<Integer * 2, Fraction * 2>;
using InternalType = typename ResultType::InternalType;
return ResultType::fromInternal(static_cast<InternalType>(static_cast<InternalType>(left.getInternal()) * static_cast<InternalType>(right.getInternal())));
}
//
// Basic Logic Operations
//
template< unsigned Integer, unsigned Fraction >
constexpr bool operator ==(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
{
return (left.getInternal() == right.getInternal());
}
template< unsigned Integer, unsigned Fraction >
constexpr bool operator !=(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
{
return (left.getInternal() != right.getInternal());
}
template< unsigned Integer, unsigned Fraction >
constexpr bool operator <(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
{
return (left.getInternal() < right.getInternal());
}
template< unsigned Integer, unsigned Fraction >
constexpr bool operator >(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
{
return (left.getInternal() > right.getInternal());
}
template< unsigned Integer, unsigned Fraction >
constexpr bool operator <=(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
{
return (left.getInternal() <= right.getInternal());
}
template< unsigned Integer, unsigned Fraction >
constexpr bool operator >=(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
{
return (left.getInternal() >= right.getInternal());
}
//
// Inter-size Logic Operations
//
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator ==(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
{
using LeftType = SFixed<IntegerLeft, FractionLeft>;
using RightType = SFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator == has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) == static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator !=(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
{
using LeftType = SFixed<IntegerLeft, FractionLeft>;
using RightType = SFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator != has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) != static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator <(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
{
using LeftType = SFixed<IntegerLeft, FractionLeft>;
using RightType = SFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator < has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) < static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator >(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
{
using LeftType = SFixed<IntegerLeft, FractionLeft>;
using RightType = SFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator > has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) > static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator <=(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
{
using LeftType = SFixed<IntegerLeft, FractionLeft>;
using RightType = SFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator <= has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) <= static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator >=(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
{
using LeftType = SFixed<IntegerLeft, FractionLeft>;
using RightType = SFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator >= has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) >= static_cast<CompareType>(right));
}
//
// Basic Arithmetic Operations
//
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> operator +(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
{
using InternalType = typename SFixed<Integer, Fraction>::InternalType;
return SFixed<Integer, Fraction>::fromInternal(static_cast<InternalType>(left.getInternal() + right.getInternal()));
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> operator -(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
{
using InternalType = typename SFixed<Integer, Fraction>::InternalType;
return SFixed<Integer, Fraction>::fromInternal(static_cast<InternalType>(left.getInternal() - right.getInternal()));
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> operator *(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
{
using InternalType = typename SFixed<Integer, Fraction>::InternalType;
using PrecisionType = typename SFixed<Integer * 2, Fraction * 2>::InternalType;
return SFixed<Integer, Fraction>::fromInternal(static_cast<InternalType>((static_cast<PrecisionType>(left.getInternal()) * static_cast<PrecisionType>(right.getInternal())) >> Fraction));
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> operator /(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
{
using InternalType = typename SFixed<Integer, Fraction>::InternalType;
using PrecisionType = typename SFixed<Integer * 2, Fraction * 2>::InternalType;
return SFixed<Integer, Fraction>::fromInternal(static_cast<InternalType>((static_cast<PrecisionType>(left.getInternal()) << Fraction) / right.getInternal()));
}
//
// Inter-size Arithmetic Operations
//
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator +(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< SFixed<IntegerLeft, FractionLeft>, SFixed<IntegerRight, FractionRight> >
{
using LeftType = SFixed<IntegerLeft, FractionLeft>;
using RightType = SFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator + has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) + static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator -(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< SFixed<IntegerLeft, FractionLeft>, SFixed<IntegerRight, FractionRight> >
{
using LeftType = SFixed<IntegerLeft, FractionLeft>;
using RightType = SFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator - has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) - static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator *(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< SFixed<IntegerLeft, FractionLeft>, SFixed<IntegerRight, FractionRight> >
{
using LeftType = SFixed<IntegerLeft, FractionLeft>;
using RightType = SFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator * has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) * static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator /(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< SFixed<IntegerLeft, FractionLeft>, SFixed<IntegerRight, FractionRight> >
{
using LeftType = SFixed<IntegerLeft, FractionLeft>;
using RightType = SFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator / has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) / static_cast<CompareType>(right));
}
//
// Literal-type Operators
// Generated by macro to make maintenance easier
//
#define LOGIC_OPERATOR( type, op )\
template< unsigned Integer, unsigned Fraction >\
constexpr bool operator op (const SFixed<Integer, Fraction> & left, const type & right)\
{\
return (left op SFixed<Integer, Fraction>(right));\
}\
\
template< unsigned Integer, unsigned Fraction >\
constexpr bool operator op (const type & left, const SFixed<Integer, Fraction> & right)\
{\
return (SFixed<Integer, Fraction>(left) op right);\
}
#define ARITHMETIC_OPERATOR( type, op )\
template< unsigned Integer, unsigned Fraction >\
constexpr SFixed<Integer, Fraction> operator op (const SFixed<Integer, Fraction> & left, const type & right)\
{\
return (left op SFixed<Integer, Fraction>(right));\
}\
\
template< unsigned Integer, unsigned Fraction >\
constexpr SFixed<Integer, Fraction> operator op (const type & left, const SFixed<Integer, Fraction> & right)\
{\
return (SFixed<Integer, Fraction>(left) op right);\
}
#define OPERATORS( opType, op ) \
opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteral, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralU, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralL, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralUL, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralLL, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralULL, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::DecimalLiteral, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::DecimalLiteralF, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::DecimalLiteralL, op )
#define LOGIC_OPERATORS( op ) OPERATORS( LOGIC, op )
#define ARITHMETIC_OPERATORS( op ) OPERATORS( ARITHMETIC, op )
LOGIC_OPERATORS( == )
LOGIC_OPERATORS( != )
LOGIC_OPERATORS( < )
LOGIC_OPERATORS( > )
LOGIC_OPERATORS( <= )
LOGIC_OPERATORS( >= )
ARITHMETIC_OPERATORS( + )
ARITHMETIC_OPERATORS( - )
ARITHMETIC_OPERATORS( * )
ARITHMETIC_OPERATORS( / )
// Prevent Macro-bleed:
#undef LOGIC_OPERATOR
#undef ARITHMETIC_OPERATOR
#undef OPERATORS
#undef LOGIC_OPERATORS
#undef ARITHMETIC_OPERATORS
FIXED_POINTS_END_NAMESPACE

@ -0,0 +1,175 @@
FIXED_POINTS_BEGIN_NAMESPACE
//
// Constructors
//
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction>::SFixed(void)
: Base()
{
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction>::SFixed(const IntegerType & integer)
: Base(RawType(static_cast<InternalType>(integer) << FractionSize))
{
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction>::SFixed(const IntegerType & integer, const FractionType & fraction)
: Base(RawType((static_cast<InternalType>(integer) << FractionSize) | fraction))
{
}
//
// Getters
//
template< unsigned Integer, unsigned Fraction >
constexpr typename SFixed<Integer, Fraction>::InternalType SFixed<Integer, Fraction>::getInternal(void) const
{
return this->value;
}
template< unsigned Integer, unsigned Fraction >
constexpr typename SFixed<Integer, Fraction>::IntegerType SFixed<Integer, Fraction>::getInteger(void) const
{
return static_cast<IntegerType>(this->value >> IntegerShift) & IntegerMask | ((this->value < 0) ? ~IntegerMask : 0);
}
template< unsigned Integer, unsigned Fraction >
constexpr typename SFixed<Integer, Fraction>::FractionType SFixed<Integer, Fraction>::getFraction(void) const
{
return static_cast<FractionType>(this->value >> FractionShift) & FractionMask;
}
//
// Cast Operators
//
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction>::operator IntegerType(void) const
{
return this->getInteger();
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction>::operator float(void) const
{
/*return (1.0f / Scale) *
(this->value < 0) ?
-((-this->value) & IdentityMask) :
this->value & IdentityMask; */
return (1.0f / Scale) *
static_cast<InternalType>
((this->value & IdentityMask) |
((this->value < 0) ? ~IdentityMask : 0));
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction>::operator double(void) const
{
/*return (1.0 / Scale) *
(this->value < 0) ?
-((-this->value) & IdentityMask) :
this->value & IdentityMask; */
return (1.0 / Scale) *
static_cast<InternalType>
((this->value & IdentityMask) |
((this->value < 0) ? ~IdentityMask : 0));
}
template< unsigned Integer, unsigned Fraction >
template< unsigned IntegerOut, unsigned FractionOut >
constexpr SFixed<Integer, Fraction>::operator SFixed<IntegerOut, FractionOut>(void) const
{
using OutputType = UFixed<IntegerOut, FractionOut>;
using OutputInternalType = typename OutputType::InternalType;
using OutputShiftType = typename OutputType::ShiftType;
using InputType = UFixed<Integer, Fraction>;
using InputInternalType = typename InputType::InternalType;
using InputShiftType = typename InputType::ShiftType;
return
(FractionOut > FractionSize) ?
OutputType::fromInternal(static_cast<OutputInternalType>(static_cast<OutputShiftType>(this->value) << ((FractionOut > FractionSize) ? (FractionOut - FractionSize) : 0))) :
(FractionSize > FractionOut) ?
OutputType::fromInternal(static_cast<OutputInternalType>(static_cast<InputShiftType>(this->value) >> ((FractionSize > FractionOut) ? (FractionSize - FractionOut) : 0))) :
OutputType::fromInternal(this->value);
}
//
// Static Functions
//
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> SFixed<Integer, Fraction>::fromInternal(const typename SFixed<Integer, Fraction>::InternalType & value)
{
return SFixed<Integer, Fraction>(RawType(value));
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> SFixed<Integer, Fraction>::operator -(void) const
{
return SFixed<Integer, Fraction>::fromInternal(-this->value);
}
//
// Member Operators
//
template< unsigned Integer, unsigned Fraction >
SFixed<Integer, Fraction> & SFixed<Integer, Fraction>::operator ++(void)
{
this->value += (1 << FractionSize);
return *this;
}
template< unsigned Integer, unsigned Fraction >
SFixed<Integer, Fraction> & SFixed<Integer, Fraction>::operator --(void)
{
this->value -= (1 << FractionSize);
return *this;
}
//
// Compound Assignment Operators
//
template< unsigned Integer, unsigned Fraction >
SFixed<Integer, Fraction> & SFixed<Integer, Fraction>::operator +=(const SFixed<Integer, Fraction> & other)
{
this->value += other.value;
return *this;
}
template< unsigned Integer, unsigned Fraction >
SFixed<Integer, Fraction> & SFixed<Integer, Fraction>::operator -=(const SFixed<Integer, Fraction> & other)
{
this->value -= other.value;
return *this;
}
template< unsigned Integer, unsigned Fraction >
SFixed<Integer, Fraction> & SFixed<Integer, Fraction>::operator *=(const SFixed<Integer, Fraction> & other)
{
using InternalType = typename SFixed<Integer, Fraction>::InternalType;
using PrecisionType = typename SFixed<Integer * 2, Fraction * 2>::InternalType;
const PrecisionType temp = (static_cast<PrecisionType>(this->value) * static_cast<PrecisionType>(other.value)) >> Fraction;
this->value = static_cast<InternalType>(temp);
return *this;
}
template< unsigned Integer, unsigned Fraction >
SFixed<Integer, Fraction> & SFixed<Integer, Fraction>::operator /=(const SFixed<Integer, Fraction> & other)
{
using InternalType = typename SFixed<Integer, Fraction>::InternalType;
using PrecisionType = typename SFixed<Integer * 2, Fraction * 2>::InternalType;
const PrecisionType temp = (static_cast<PrecisionType>(this->value) << Fraction) / static_cast<PrecisionType>(other.value);
this->value = static_cast<InternalType>(temp);
return *this;
}
FIXED_POINTS_END_NAMESPACE

@ -0,0 +1,205 @@
#pragma once
#include "Details.h"
#include "UFixedBase.h"
FIXED_POINTS_BEGIN_NAMESPACE
//
// Declaration
//
template< unsigned Integer, unsigned Fraction >
class UFixed : FIXED_POINTS_DETAILS::UFixedBase< Integer, Fraction >
{
public:
static_assert((Integer + Fraction) <= FIXED_POINTS_DETAILS::BitSize<uintmax_t>::Value, "Platform does not have a native type large enough for UFixed.");
public:
using IntegerType = FIXED_POINTS_DETAILS::LeastUInt<Integer>;
using FractionType = FIXED_POINTS_DETAILS::LeastUInt<Fraction>;
using InternalType = FIXED_POINTS_DETAILS::LeastUInt<Integer + Fraction>;
using ShiftType = FIXED_POINTS_DETAILS::LeastUInt<Integer + Fraction>;
using MaskType = FIXED_POINTS_DETAILS::LeastUInt<Integer + Fraction>;
constexpr const static uintmax_t IntegerSize = Integer;
constexpr const static uintmax_t FractionSize = Fraction;
constexpr const static uintmax_t LogicalSize = IntegerSize + FractionSize;
constexpr const static uintmax_t InternalSize = FIXED_POINTS_DETAILS::BitSize<InternalType>::Value;
constexpr const static uintmax_t Scale = 1ULL << FractionSize;
public:
constexpr const static ShiftType IntegerShift = FractionSize;
constexpr const static ShiftType FractionShift = 0;
constexpr const static MaskType IntegerMask = FIXED_POINTS_DETAILS::IdentityMask<IntegerSize>::Value;
constexpr const static MaskType FractionMask = FIXED_POINTS_DETAILS::IdentityMask<FractionSize>::Value;
constexpr const static MaskType IdentityMask = (IntegerMask << IntegerShift) | (FractionMask << FractionShift);
constexpr const static MaskType MidpointMask = FIXED_POINTS_DETAILS::MsbMask<FractionSize>::Value;
constexpr const static MaskType LesserMidpointMask = MidpointMask - 1;
private:
using Base = FIXED_POINTS_DETAILS::UFixedBase<Integer, Fraction>;
using RawType = typename Base::RawType;
public:
using Base::Base;
constexpr UFixed(void);
constexpr UFixed(const IntegerType & integer);
constexpr UFixed(const IntegerType & integer, const FractionType & fraction);
constexpr InternalType getInternal(void) const;
constexpr IntegerType getInteger(void) const;
constexpr FractionType getFraction(void) const;
constexpr explicit operator IntegerType(void) const;
constexpr explicit operator float(void) const;
constexpr explicit operator double(void) const;
template< unsigned IntegerOut, unsigned FractionOut >
constexpr explicit operator UFixed<IntegerOut, FractionOut>(void) const;
constexpr static UFixed fromInternal(const InternalType & value);
UFixed & operator ++(void);
UFixed & operator --(void);
UFixed & operator +=(const UFixed & other);
UFixed & operator -=(const UFixed & other);
UFixed & operator *=(const UFixed & other);
UFixed & operator /=(const UFixed & other);
public:
const static UFixed Epsilon;
const static UFixed MinValue;
const static UFixed MaxValue;
const static UFixed Pi;
const static UFixed E;
const static UFixed Phi;
const static UFixed Tau;
};
//
// Variables
//
template< unsigned Integer, unsigned Fraction >
constexpr const UFixed<Integer, Fraction> UFixed<Integer, Fraction>::Epsilon = UFixed<Integer, Fraction>::fromInternal(1);
template< unsigned Integer, unsigned Fraction >
constexpr const UFixed<Integer, Fraction> UFixed<Integer, Fraction>::MinValue = UFixed::fromInternal(0);
template< unsigned Integer, unsigned Fraction >
constexpr const UFixed<Integer, Fraction> UFixed<Integer, Fraction>::MaxValue = UFixed::fromInternal(~0);
// 40 digits is probably enough for these
template< unsigned Integer, unsigned Fraction >
constexpr const UFixed<Integer, Fraction> UFixed<Integer, Fraction>::Pi = 3.1415926535897932384626433832795028841971;
template< unsigned Integer, unsigned Fraction >
constexpr const UFixed<Integer, Fraction> UFixed<Integer, Fraction>::E = 2.718281828459045235360287471352662497757;
template< unsigned Integer, unsigned Fraction >
constexpr const UFixed<Integer, Fraction> UFixed<Integer, Fraction>::Phi = 1.6180339887498948482045868343656381177203;
template< unsigned Integer, unsigned Fraction >
constexpr const UFixed<Integer, Fraction> UFixed<Integer, Fraction>::Tau = 6.2831853071795864769252867665590057683943;
//
// Free functions
//
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer * 2, Fraction * 2> multiply(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right);
//
// Basic Logic Operations
//
template< unsigned Integer, unsigned Fraction >
constexpr bool operator ==(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr bool operator !=(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr bool operator <(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr bool operator >(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr bool operator <=(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr bool operator >=(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right);
//
// Inter-size Logic Operations
//
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator ==(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right);
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator !=(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right);
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator <(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right);
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator >(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right);
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator <=(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right);
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator >=(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right);
//
// Basic Arithmetic Operations
//
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> operator +(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> operator -(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> operator *(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right);
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> operator /(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right);
//
// Inter-size Arithmetic Operations
//
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator +(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< UFixed<IntegerLeft, FractionLeft>, UFixed<IntegerRight, FractionRight> >;
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator -(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< UFixed<IntegerLeft, FractionLeft>, UFixed<IntegerRight, FractionRight> >;
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator *(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< UFixed<IntegerLeft, FractionLeft>, UFixed<IntegerRight, FractionRight> >;
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
inline constexpr auto operator /(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< UFixed<IntegerLeft, FractionLeft>, UFixed<IntegerRight, FractionRight> >;
FIXED_POINTS_END_NAMESPACE
#include "UFixedMemberFunctions.h"
#include "UFixedFreeFunctions.h"

@ -0,0 +1,64 @@
#pragma once
#include "Details.h"
FIXED_POINTS_BEGIN_NAMESPACE
namespace FIXED_POINTS_DETAILS
{
template< unsigned Integer, unsigned Fraction >
class UFixedBase
{
public:
using IntegerType = FIXED_POINTS_DETAILS::LeastInt<Integer + 1>;
using FractionType = FIXED_POINTS_DETAILS::LeastUInt<Fraction>;
using InternalType = FIXED_POINTS_DETAILS::LeastUInt<Integer + Fraction>;
constexpr const static unsigned long long Scale = 1ULL << Fraction;
protected:
class RawType
{
private:
const InternalType value;
public:
constexpr inline explicit RawType(const InternalType & value) : value(value) {}
constexpr inline explicit operator InternalType(void) const { return this->value; }
};
protected:
InternalType value;
constexpr UFixedBase(void) : value(0) {}
constexpr UFixedBase(const RawType & value) : value(static_cast<InternalType>(value)) {}
public:
constexpr UFixedBase(const IntegerLiteral & value)
: value(static_cast<InternalType>(static_cast< LargerType<IntegerLiteral, InternalType> >(value) << Fraction)) {}
constexpr UFixedBase(const IntegerLiteralU & value)
: value(static_cast<InternalType>(static_cast< LargerType<IntegerLiteralU, InternalType> >(value) << Fraction)) {}
constexpr UFixedBase(const IntegerLiteralL & value)
: value(static_cast<InternalType>(static_cast< LargerType<IntegerLiteralL, InternalType> >(value) << Fraction)) {}
constexpr UFixedBase(const IntegerLiteralUL & value)
: value(static_cast<InternalType>(static_cast< LargerType<IntegerLiteralUL, InternalType>>(value) << Fraction)) {}
constexpr UFixedBase(const IntegerLiteralLL & value)
: value(static_cast<InternalType>(static_cast< LargerType<IntegerLiteralLL, InternalType>>(value) << Fraction)) {}
constexpr UFixedBase(const IntegerLiteralULL & value)
: value(static_cast<InternalType>(static_cast< LargerType<IntegerLiteralULL, InternalType> >(value) << Fraction)) {}
constexpr UFixedBase(const DecimalLiteral & value)
: value(static_cast<InternalType>(value * Scale)) {}
constexpr UFixedBase(const DecimalLiteralF & value)
: value(static_cast<InternalType>(value * Scale)) {}
constexpr UFixedBase(const DecimalLiteralL & value)
: value(static_cast<InternalType>(value * Scale)) {}
};
}
FIXED_POINTS_END_NAMESPACE

@ -0,0 +1,297 @@
FIXED_POINTS_BEGIN_NAMESPACE
//
// multiply
//
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer * 2, Fraction * 2> multiply(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right)
{
using ResultType = UFixed<Integer * 2, Fraction * 2>;
using InternalType = typename ResultType::InternalType;
return ResultType::fromInternal(static_cast<InternalType>(static_cast<InternalType>(left.getInternal()) * static_cast<InternalType>(right.getInternal())));
}
//
// Basic Logic Operations
//
template< unsigned Integer, unsigned Fraction >
constexpr bool operator ==(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right)
{
return (left.getInternal() == right.getInternal());
}
template< unsigned Integer, unsigned Fraction >
constexpr bool operator !=(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right)
{
return (left.getInternal() != right.getInternal());
}
template< unsigned Integer, unsigned Fraction >
constexpr bool operator <(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right)
{
return (left.getInternal() < right.getInternal());
}
template< unsigned Integer, unsigned Fraction >
constexpr bool operator >(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right)
{
return (left.getInternal() > right.getInternal());
}
template< unsigned Integer, unsigned Fraction >
constexpr bool operator <=(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right)
{
return (left.getInternal() <= right.getInternal());
}
template< unsigned Integer, unsigned Fraction >
constexpr bool operator >=(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right)
{
return (left.getInternal() >= right.getInternal());
}
//
// Inter-size Logic Operations
//
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator ==(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
{
using LeftType = UFixed<IntegerLeft, FractionLeft>;
using RightType = UFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator == has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) == static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator !=(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
{
using LeftType = UFixed<IntegerLeft, FractionLeft>;
using RightType = UFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator != has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) != static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator <(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
{
using LeftType = UFixed<IntegerLeft, FractionLeft>;
using RightType = UFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator < has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) < static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator >(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
{
using LeftType = UFixed<IntegerLeft, FractionLeft>;
using RightType = UFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator > has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) > static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator <=(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
{
using LeftType = UFixed<IntegerLeft, FractionLeft>;
using RightType = UFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator <= has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) <= static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr bool operator >=(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
{
using LeftType = UFixed<IntegerLeft, FractionLeft>;
using RightType = UFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator >= has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) >= static_cast<CompareType>(right));
}
//
// Basic Arithmetic Operations
//
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> operator +(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right)
{
using InternalType = typename UFixed<Integer, Fraction>::InternalType;
return UFixed<Integer, Fraction>::fromInternal(static_cast<InternalType>(left.getInternal() + right.getInternal()));
}
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> operator -(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right)
{
using InternalType = typename UFixed<Integer, Fraction>::InternalType;
return UFixed<Integer, Fraction>::fromInternal(static_cast<InternalType>(left.getInternal() - right.getInternal()));
}
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> operator *(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right)
{
using InternalType = typename UFixed<Integer, Fraction>::InternalType;
using PrecisionType = typename UFixed<Integer * 2, Fraction * 2>::InternalType;
return UFixed<Integer, Fraction>::fromInternal(static_cast<InternalType>((static_cast<PrecisionType>(left.getInternal()) * static_cast<PrecisionType>(right.getInternal())) >> Fraction));
}
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> operator /(const UFixed<Integer, Fraction> & left, const UFixed<Integer, Fraction> & right)
{
using InternalType = typename UFixed<Integer, Fraction>::InternalType;
using PrecisionType = typename UFixed<Integer * 2, Fraction * 2>::InternalType;
return UFixed<Integer, Fraction>::fromInternal(static_cast<InternalType>((static_cast<PrecisionType>(left.getInternal()) << Fraction) / static_cast<PrecisionType>(right.getInternal())));
}
//
// Inter-size Arithmetic Operations
//
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator +(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< UFixed<IntegerLeft, FractionLeft>, UFixed<IntegerRight, FractionRight> >
{
using LeftType = UFixed<IntegerLeft, FractionLeft>;
using RightType = UFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator + has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) + static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator -(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< UFixed<IntegerLeft, FractionLeft>, UFixed<IntegerRight, FractionRight> >
{
using LeftType = UFixed<IntegerLeft, FractionLeft>;
using RightType = UFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator - has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) - static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator *(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< UFixed<IntegerLeft, FractionLeft>, UFixed<IntegerRight, FractionRight> >
{
using LeftType = UFixed<IntegerLeft, FractionLeft>;
using RightType = UFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator * has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) * static_cast<CompareType>(right));
}
template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
constexpr auto operator /(const UFixed<IntegerLeft, FractionLeft> & left, const UFixed<IntegerRight, FractionRight> & right)
-> FIXED_POINTS_DETAILS::LargerType< UFixed<IntegerLeft, FractionLeft>, UFixed<IntegerRight, FractionRight> >
{
using LeftType = UFixed<IntegerLeft, FractionLeft>;
using RightType = UFixed<IntegerRight, FractionRight>;
static_assert(LeftType::InternalSize != RightType::InternalSize, "operator / has ambiguous result");
using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
return (static_cast<CompareType>(left) / static_cast<CompareType>(right));
}
//
// Literal-type Operators
// Generated by macro to make maintenance easier
//
#define LOGIC_OPERATOR( type, op )\
template< unsigned Integer, unsigned Fraction >\
constexpr bool operator op (const UFixed<Integer, Fraction> & left, const type & right)\
{\
return (left op UFixed<Integer, Fraction>(right));\
}\
\
template< unsigned Integer, unsigned Fraction >\
constexpr bool operator op (const type & left, const UFixed<Integer, Fraction> & right)\
{\
return (UFixed<Integer, Fraction>(left) op right);\
}
#define ARITHMETIC_OPERATOR( type, op )\
template< unsigned Integer, unsigned Fraction >\
constexpr UFixed<Integer, Fraction> operator op (const UFixed<Integer, Fraction> & left, const type & right)\
{\
return (left op UFixed<Integer, Fraction>(right));\
}\
\
template< unsigned Integer, unsigned Fraction >\
constexpr UFixed<Integer, Fraction> operator op (const type & left, const UFixed<Integer, Fraction> & right)\
{\
return (UFixed<Integer, Fraction>(left) op right);\
}
#define OPERATORS( opType, op ) \
opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteral, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralU, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralL, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralUL, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralLL, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralULL, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::DecimalLiteral, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::DecimalLiteralF, op )\
opType##_OPERATOR( FIXED_POINTS_DETAILS::DecimalLiteralL, op )
#define LOGIC_OPERATORS( op ) OPERATORS( LOGIC, op )
#define ARITHMETIC_OPERATORS( op ) OPERATORS( ARITHMETIC, op )
LOGIC_OPERATORS( == )
LOGIC_OPERATORS( != )
LOGIC_OPERATORS( < )
LOGIC_OPERATORS( > )
LOGIC_OPERATORS( <= )
LOGIC_OPERATORS( >= )
ARITHMETIC_OPERATORS( + )
ARITHMETIC_OPERATORS( - )
ARITHMETIC_OPERATORS( * )
ARITHMETIC_OPERATORS( / )
// Prevent Macro-bleed:
#undef LOGIC_OPERATOR
#undef ARITHMETIC_OPERATOR
#undef OPERATORS
#undef LOGIC_OPERATORS
#undef ARITHMETIC_OPERATORS
FIXED_POINTS_END_NAMESPACE

@ -0,0 +1,155 @@
FIXED_POINTS_BEGIN_NAMESPACE
//
// Constructors
//
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction>::UFixed(void)
: Base()
{
}
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction>::UFixed(const IntegerType & integer)
: Base(RawType(static_cast<InternalType>(integer) << FractionSize))
{
}
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction>::UFixed(const IntegerType & integer, const FractionType & fraction)
: Base(RawType((static_cast<InternalType>(integer) << FractionSize) | fraction))
{
}
//
// Getters
//
template< unsigned Integer, unsigned Fraction >
constexpr typename UFixed<Integer, Fraction>::InternalType UFixed<Integer, Fraction>::getInternal(void) const
{
return this->value;
}
template< unsigned Integer, unsigned Fraction >
constexpr typename UFixed<Integer, Fraction>::IntegerType UFixed<Integer, Fraction>::getInteger(void) const
{
return static_cast<IntegerType>(this->value >> IntegerShift) & IntegerMask;
}
template< unsigned Integer, unsigned Fraction >
constexpr typename UFixed<Integer, Fraction>::FractionType UFixed<Integer, Fraction>::getFraction(void) const
{
return static_cast<FractionType>(this->value >> FractionShift) & FractionMask;
}
//
// Cast Operators
//
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction>::operator IntegerType(void) const
{
return this->getInteger();
}
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction>::operator float(void) const
{
return ((this->value & IdentityMask) * (1.0f / Scale));
}
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction>::operator double(void) const
{
return ((this->value & IdentityMask) * (1.0 / Scale));
}
template< unsigned Integer, unsigned Fraction >
template< unsigned IntegerOut, unsigned FractionOut >
constexpr UFixed<Integer, Fraction>::operator UFixed<IntegerOut, FractionOut>(void) const
{
using OutputType = UFixed<IntegerOut, FractionOut>;
using OutputInternalType = typename OutputType::InternalType;
using OutputShiftType = typename OutputType::ShiftType;
using InputType = UFixed<Integer, Fraction>;
using InputInternalType = typename InputType::InternalType;
using InputShiftType = typename InputType::ShiftType;
return
(FractionOut > FractionSize) ?
OutputType::fromInternal(static_cast<OutputInternalType>(static_cast<OutputShiftType>(this->value) << ((FractionOut > FractionSize) ? (FractionOut - FractionSize) : 0))) :
(FractionSize > FractionOut) ?
OutputType::fromInternal(static_cast<OutputInternalType>(static_cast<InputShiftType>(this->value) >> ((FractionSize > FractionOut) ? (FractionSize - FractionOut) : 0))) :
OutputType::fromInternal(this->value);
}
//
// Static Functions
//
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> UFixed<Integer, Fraction>::fromInternal(const typename UFixed<Integer, Fraction>::InternalType & value)
{
return UFixed<Integer, Fraction>(RawType(value));
}
//
// Member Operators
//
template< unsigned Integer, unsigned Fraction >
UFixed<Integer, Fraction> & UFixed<Integer, Fraction>::operator ++(void)
{
this->value += (1 << FractionSize);
return *this;
}
template< unsigned Integer, unsigned Fraction >
UFixed<Integer, Fraction> & UFixed<Integer, Fraction>::operator --(void)
{
this->value -= (1 << FractionSize);
return *this;
}
//
// Compound Assignment Operators
//
template< unsigned Integer, unsigned Fraction >
UFixed<Integer, Fraction> & UFixed<Integer, Fraction>::operator +=(const UFixed<Integer, Fraction> & other)
{
this->value += other.value;
return *this;
}
template< unsigned Integer, unsigned Fraction >
UFixed<Integer, Fraction> & UFixed<Integer, Fraction>::operator -=(const UFixed<Integer, Fraction> & other)
{
this->value -= other.value;
return *this;
}
template< unsigned Integer, unsigned Fraction >
UFixed<Integer, Fraction> & UFixed<Integer, Fraction>::operator *=(const UFixed<Integer, Fraction> & other)
{
using InternalType = typename UFixed<Integer, Fraction>::InternalType;
using PrecisionType = typename UFixed<Integer * 2, Fraction * 2>::InternalType;
const PrecisionType temp = (static_cast<PrecisionType>(this->value) * static_cast<PrecisionType>(other.value)) >> FractionSize;
this->value = static_cast<InternalType>(temp);
return *this;
}
template< unsigned Integer, unsigned Fraction >
UFixed<Integer, Fraction> & UFixed<Integer, Fraction>::operator /=(const UFixed<Integer, Fraction> & other)
{
using InternalType = typename UFixed<Integer, Fraction>::InternalType;
using PrecisionType = typename UFixed<Integer * 2, Fraction * 2>::InternalType;
const PrecisionType temp = (static_cast<PrecisionType>(this->value) << FractionSize) / static_cast<PrecisionType>(other.value);
this->value = static_cast<InternalType>(temp);
return *this;
}
FIXED_POINTS_END_NAMESPACE

@ -0,0 +1,233 @@
#pragma once
#include "Details.h"
#include "UFixed.h"
#include "SFixed.h"
//
// Declaration
//
FIXED_POINTS_BEGIN_NAMESPACE
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> floorFixed(const UFixed<Integer, Fraction> & value);
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> floorFixed(const SFixed<Integer, Fraction> & value);
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> ceilFixed(const UFixed<Integer, Fraction> & value);
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> ceilFixed(const SFixed<Integer, Fraction> & value);
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> roundFixed(const UFixed<Integer, Fraction> & value);
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> roundFixed(const SFixed<Integer, Fraction> & value);
template< unsigned Integer, unsigned Fraction >
constexpr bool signbitFixed(const SFixed<Integer, Fraction> & value);
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> absFixed(const SFixed<Integer, Fraction> & value);
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> copysignFixed(const SFixed<Integer, Fraction> & x, const SFixed<Integer, Fraction> & y);
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> nextafterFixed(const SFixed<Integer, Fraction> & from, const SFixed<Integer, Fraction> & to);
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> nextafterFixed(const UFixed<Integer, Fraction> & from, const UFixed<Integer, Fraction> & to);
//
// Unsigned Random
//
template< unsigned Integer, unsigned Fraction >
UFixed<Integer, Fraction> randomUFixed(void);
template< unsigned Integer, unsigned Fraction >
UFixed<Integer, Fraction> randomUFixed(const UFixed<Integer, Fraction> & exclusiveUpperBound);
template< unsigned Integer, unsigned Fraction >
UFixed<Integer, Fraction> randomUFixed(const UFixed<Integer, Fraction> & inclusiveLowerBound, const UFixed<Integer, Fraction> & exclusiveUpperBound);
//
// Signed Random
//
template< unsigned Integer, unsigned Fraction >
SFixed<Integer, Fraction> randomSFixed(void);
template< unsigned Integer, unsigned Fraction >
SFixed<Integer, Fraction> randomSFixed(const SFixed<Integer, Fraction> & exclusiveUpperBound);
template< unsigned Integer, unsigned Fraction >
SFixed<Integer, Fraction> randomSFixed(const SFixed<Integer, Fraction> & inclusiveLowerBound, const SFixed<Integer, Fraction> & exclusiveUpperBound);
FIXED_POINTS_END_NAMESPACE
//
// Definition
//
FIXED_POINTS_BEGIN_NAMESPACE
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> floorFixed(const UFixed<Integer, Fraction> & value)
{
using OutputType = UFixed<Integer, Fraction>;
using InternalType = typename OutputType::InternalType;
return OutputType::fromInternal(static_cast<InternalType>(value.getInternal() & ~OutputType::FractionMask));
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> floorFixed(const SFixed<Integer, Fraction> & value)
{
using OutputType = SFixed<Integer, Fraction>;
using InternalType = typename OutputType::InternalType;
return OutputType::fromInternal(static_cast<InternalType>(value.getInternal() & ~OutputType::FractionMask));
}
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> ceilFixed(const UFixed<Integer, Fraction> & value)
{
return UFixed<Integer, Fraction>((value.getFraction() == 0) ? value.getInteger() : (value.getInteger() + 1), 0);
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> ceilFixed(const SFixed<Integer, Fraction> & value)
{
return SFixed<Integer, Fraction>((value.getFraction() == 0) ? value.getInteger() : (value.getInteger() + 1), 0);
}
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> roundFixed(const UFixed<Integer, Fraction> & value)
{
using OutputType = UFixed<Integer, Fraction>;
return (value.getInternal() & OutputType::MidpointMask) != 0 ? ceilFixed(value) : floorFixed(value);
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> roundFixed(const SFixed<Integer, Fraction> & value)
{
using OutputType = SFixed<Integer, Fraction>;
return
(
((value.getInternal() & OutputType::MidpointMask) != 0) &&
!signbitFixed(value) ||
((value.getInternal() & OutputType::LesserMidpointMask) != 0)
)
? ceilFixed(value)
: floorFixed(value);
}
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> truncFixed(const UFixed<Integer, Fraction> & value)
{
return UFixed<Integer, Fraction>(value.getInteger(), 0);
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> truncFixed(const SFixed<Integer, Fraction> & value)
{
using OutputType = SFixed<Integer, Fraction>;
return
(value.getInternal() < 0) ?
OutputType::fromInternal(value.getInternal() & ~OutputType::FractionMask) + OutputType(1, 0) :
OutputType::fromInternal(value.getInternal() & ~OutputType::FractionMask);
}
template< unsigned Integer, unsigned Fraction >
constexpr bool signbitFixed(const SFixed<Integer, Fraction> & value)
{
return (value.getInternal() < 0);
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> absFixed(const SFixed<Integer, Fraction> & value)
{
return (signbitFixed(value)) ? -value : value;
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> copysignFixed(const SFixed<Integer, Fraction> & x, const SFixed<Integer, Fraction> & y)
{
return (signbitFixed(x) != signbitFixed(y)) ? -x : x;
}
template< unsigned Integer, unsigned Fraction >
constexpr SFixed<Integer, Fraction> nextafterFixed(const SFixed<Integer, Fraction> & from, const SFixed<Integer, Fraction> & to)
{
using ResultType = SFixed<Integer, Fraction>;
return
(from < to) ?
ResultType::fromInternal(from.getInternal() + 1) :
(from > to) ?
ResultType::fromInternal(from.getInternal() - 1):
to;
}
template< unsigned Integer, unsigned Fraction >
constexpr UFixed<Integer, Fraction> nextafterFixed(const UFixed<Integer, Fraction> & from, const UFixed<Integer, Fraction> & to)
{
using ResultType = UFixed<Integer, Fraction>;
return
(from < to) ?
ResultType::fromInternal(from.getInternal() + 1) :
(from > to) ?
ResultType::fromInternal(from.getInternal() - 1):
to;
}
//
// Unsigned Random
//
template< unsigned Integer, unsigned Fraction >
UFixed<Integer, Fraction> randomUFixed(void)
{
using InternalType = typename UFixed<Integer, Fraction>::InternalType;
return UFixed<Integer, Fraction>::fromInternal(FIXED_POINTS_DETAILS::RandomHelper<InternalType>::Random());
}
template< unsigned Integer, unsigned Fraction >
UFixed<Integer, Fraction> randomUFixed(const UFixed<Integer, Fraction> & exclusiveUpperBound)
{
using InternalType = typename UFixed<Integer, Fraction>::InternalType;
return UFixed<Integer, Fraction>::fromInternal(FIXED_POINTS_DETAILS::RandomHelper<InternalType>::Random() % exclusiveUpperBound.getInternal());
}
template< unsigned Integer, unsigned Fraction >
UFixed<Integer, Fraction> randomUFixed(const UFixed<Integer, Fraction> & inclusiveLowerBound, const UFixed<Integer, Fraction> & exclusiveUpperBound)
{
using InternalType = typename UFixed<Integer, Fraction>::InternalType;
return UFixed<Integer, Fraction>::fromInternal(inclusiveLowerBound.getInternal() + FIXED_POINTS_DETAILS::RandomHelper<InternalType>::Random() % exclusiveUpperBound.getInternal());
}
//
// Signed Random
//
template< unsigned Integer, unsigned Fraction >
SFixed<Integer, Fraction> randomSFixed(void)
{
using InternalType = typename SFixed<Integer, Fraction>::InternalType;
return SFixed<Integer, Fraction>::fromInternal(FIXED_POINTS_DETAILS::RandomHelper<InternalType>::Random());
}
template< unsigned Integer, unsigned Fraction >
SFixed<Integer, Fraction> randomSFixed(const SFixed<Integer, Fraction> & exclusiveUpperBound)
{
using InternalType = typename SFixed<Integer, Fraction>::InternalType;
return SFixed<Integer, Fraction>::fromInternal(FIXED_POINTS_DETAILS::RandomHelper<InternalType>::Random() % exclusiveUpperBound.getInternal());
}
template< unsigned Integer, unsigned Fraction >
SFixed<Integer, Fraction> randomSFixed(const SFixed<Integer, Fraction> & inclusiveLowerBound, const SFixed<Integer, Fraction> & exclusiveUpperBound)
{
using InternalType = typename SFixed<Integer, Fraction>::InternalType;
return SFixed<Integer, Fraction>::fromInternal(inclusiveLowerBound.getInternal() + FIXED_POINTS_DETAILS::RandomHelper<InternalType>::Random() % exclusiveUpperBound.getInternal());
}
FIXED_POINTS_END_NAMESPACE

@ -0,0 +1 @@
#include "FixedPointsCommon/FixedPointsCommon.h"

@ -0,0 +1,4 @@
#include "../FixedPoints.h"
#include "SFixedCommon.h"
#include "UFixedCommon.h"

@ -0,0 +1,15 @@
#pragma once
#include "../FixedPoints.h"
FIXED_POINTS_BEGIN_NAMESPACE
using SQ3x4 = SFixed<3, 4>;
using SQ7x8 = SFixed<7, 8>;
using SQ15x16 = SFixed<15, 16>;
using SQ31x32 = SFixed<31, 32>;
using SQ1x6 = SFixed<1, 6>;
using SQ1x14 = SFixed<1, 14>;
using SQ1x30 = SFixed<1, 30>;
using SQ1x62 = SFixed<1, 62>;
FIXED_POINTS_END_NAMESPACE

@ -0,0 +1,15 @@
#pragma once
#include "../FixedPoints.h"
FIXED_POINTS_BEGIN_NAMESPACE
using UQ4x4 = UFixed<4, 4>;
using UQ8x8 = UFixed<8, 8>;
using UQ16x16 = UFixed<16, 16>;
using UQ32x32 = UFixed<32, 32>;
using UQ1x7 = UFixed<1, 7>;
using UQ1x15 = UFixed<1, 15>;
using UQ1x31 = UFixed<1, 31>;
using UQ1x63 = UFixed<1, 63>;
FIXED_POINTS_END_NAMESPACE
Loading…
Cancel
Save