Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trying to use SQ31x32 #18

Closed
nunovilhena opened this issue Mar 7, 2018 · 6 comments
Closed

Trying to use SQ31x32 #18

nunovilhena opened this issue Mar 7, 2018 · 6 comments
Assignees
Labels
Question This issue was a question asked prior to the introduction of discussions

Comments

@nunovilhena
Copy link

nunovilhena commented Mar 7, 2018

Hello Pharap,
Firstly, I would like to congratulate you for this work. :)
Maybe you can help me with a issue! I'm trying to use the SQ31x32 fixed point type, however I could not compile my code without errors. If I use the SQ15x16 type, I can compile and run my code but if I change to SQ31x32 I can't compile it.
I'm trying to do a simple multiplication:

SQ31x32 x = 1;
SQ31x32 y = 0.000200;
SQ31x32 z = 0.0;
z= x * y;

Could you help me or give me some feedback?
Thank you so much.
Nuno Vilhena


Arduino: 1.8.5 (Windows Store 1.8.10.0) (Windows 10), Placa:"Arduino Due (Programming Port)"

In file included from sketch\FixedPoints/FixedPoints.h:15:0,

                 from sketch\FixedPoints.h:15,

                 from C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:1:

sketch\FixedPoints/Details.h: In instantiation of 'struct FixedPointsDetails::LeastIntDef<127u>':

sketch\FixedPoints/Details.h:116:51:   required by substitution of 'template<unsigned int Bits> using LeastInt = typename FixedPointsDetails::LeastIntDef::Type [with unsigned int Bits = 127u]'

sketch\FixedPoints/SFixedBase.h:28:80:   required from 'class FixedPointsDetails::SFixedBase<62u, 64u>'

sketch\FixedPoints/SFixed.h:27:7:   required from 'class SFixed<62u, 64u>'

sketch\FixedPoints/SFixedFreeFunctions.h:173:80:   required from 'constexpr SFixed<Integer, Fraction> operator*(const SFixed<Integer, Fraction>&, const SFixed<Integer, Fraction>&) [with unsigned int Integer = 31u; unsigned int Fraction = 32u]'

C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:27:14:   required from here

sketch\FixedPoints/Details.h:110:3: error: static assertion failed: No type large enough

   static_assert(Bits <= BitSize<intmax_t>::Value, "No type large enough");

   ^

In file included from sketch\FixedPoints/FixedPoints.h:18:0,

                 from sketch\FixedPoints.h:15,

                 from C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:1:

sketch\FixedPoints/SFixedBase.h: In instantiation of 'class FixedPointsDetails::SFixedBase<62u, 64u>':

sketch\FixedPoints/SFixed.h:27:7:   required from 'class SFixed<62u, 64u>'

sketch\FixedPoints/SFixedFreeFunctions.h:173:80:   required from 'constexpr SFixed<Integer, Fraction> operator*(const SFixed<Integer, Fraction>&, const SFixed<Integer, Fraction>&) [with unsigned int Integer = 31u; unsigned int Fraction = 32u]'

C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:27:14:   required from here

sketch\FixedPoints/SFixedBase.h:44:16: error: instantiation of 'FixedPointsDetails::SFixedBase<Integer, Fraction>::value' as type 'FixedPointsDetails::SFixedBase<62u, 64u>::InternalType {aka void}'

   InternalType value;

                ^

sketch\FixedPoints/SFixedBase.h:44:16: error: 'FixedPointsDetails::SFixedBase<Integer, Fraction>::value' has incomplete type

sketch\FixedPoints/SFixedBase.h:44:16: error: invalid use of 'FixedPointsDetails::SFixedBase<62u, 64u>::InternalType {aka void}'

In file included from sketch\FixedPoints/FixedPoints.h:21:0,

                 from sketch\FixedPoints.h:15,

                 from C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:1:

sketch\FixedPoints/SFixed.h: In instantiation of 'class SFixed<62u, 64u>':

sketch\FixedPoints/SFixedFreeFunctions.h:173:80:   required from 'constexpr SFixed<Integer, Fraction> operator*(const SFixed<Integer, Fraction>&, const SFixed<Integer, Fraction>&) [with unsigned int Integer = 31u; unsigned int Fraction = 32u]'

C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:27:14:   required from here

sketch\FixedPoints/SFixed.h:30:2: error: static assertion failed: Platform does not have a native type large enough for SFixed.

  static_assert(((Integer + 1) + Fraction) <= FIXED_POINTS_DETAILS::BitSize<intmax_t>::Value, "Platform does not have a native type large enough for SFixed.");

  ^

In file included from sketch\FixedPoints/FixedPoints.h:15:0,

                 from sketch\FixedPoints.h:15,

                 from C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:1:

sketch\FixedPoints/Details.h: In instantiation of 'struct FixedPointsDetails::LeastUIntDef<127u>':

sketch\FixedPoints/Details.h:105:53:   required by substitution of 'template<unsigned int Bits> using LeastUInt = typename FixedPointsDetails::LeastUIntDef::Type [with unsigned int Bits = 127u]'

sketch\FixedPoints/SFixed.h:37:77:   required from 'class SFixed<62u, 64u>'

sketch\FixedPoints/SFixedFreeFunctions.h:173:80:   required from 'constexpr SFixed<Integer, Fraction> operator*(const SFixed<Integer, Fraction>&, const SFixed<Integer, Fraction>&) [with unsigned int Integer = 31u; unsigned int Fraction = 32u]'

C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:27:14:   required from here

sketch\FixedPoints/Details.h:98:3: error: static assertion failed: No type large enough

   static_assert(Bits <= BitSize<uintmax_t>::Value, "No type large enough");

   ^

In file included from sketch\FixedPoints/FixedPoints.h:21:0,

                 from sketch\FixedPoints.h:15,

                 from C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:1:

sketch\FixedPoints/SFixed.h: In instantiation of 'class SFixed<62u, 64u>':

sketch\FixedPoints/SFixedFreeFunctions.h:173:80:   required from 'constexpr SFixed<Integer, Fraction> operator*(const SFixed<Integer, Fraction>&, const SFixed<Integer, Fraction>&) [with unsigned int Integer = 31u; unsigned int Fraction = 32u]'

C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:27:14:   required from here

sketch\FixedPoints/SFixed.h:48:35: error: variable or field 'IntegerShift' declared void

  constexpr const static ShiftType IntegerShift = FractionSize;

                                   ^

sketch\FixedPoints/SFixed.h:49:35: error: variable or field 'FractionShift' declared void

  constexpr const static ShiftType FractionShift = 0;

                                   ^

sketch\FixedPoints/SFixed.h:51:34: error: variable or field 'IntegerMask' declared void

  constexpr const static MaskType IntegerMask = FIXED_POINTS_DETAILS::IdentityMask<IntegerSize>::Value;

                                  ^

sketch\FixedPoints/SFixed.h:52:34: error: variable or field 'FractionMask' declared void

  constexpr const static MaskType FractionMask = FIXED_POINTS_DETAILS::IdentityMask<FractionSize>::Value;

                                  ^

sketch\FixedPoints/SFixed.h:54:34: error: variable or field 'IdentityMask' declared void

  constexpr const static MaskType IdentityMask = (IntegerMask << IntegerShift) | (FractionMask << FractionShift);

                                  ^

sketch\FixedPoints/SFixed.h:56:34: error: variable or field 'MidpointMask' declared void

  constexpr const static MaskType MidpointMask = FIXED_POINTS_DETAILS::MsbMask<FractionSize>::Value;

                                  ^

sketch\FixedPoints/SFixed.h:57:34: error: variable or field 'LesserMidpointMask' declared void

  constexpr const static MaskType LesserMidpointMask = MidpointMask - 1;

                                  ^

In file included from sketch\FixedPoints/SFixed.h:193:0,

                 from sketch\FixedPoints/FixedPoints.h:21,

                 from sketch\FixedPoints.h:15,

                 from C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:1:

sketch\FixedPoints/SFixedMemberFunctions.h:113:37: error: forming reference to void

 constexpr SFixed<Integer, Fraction> SFixed<Integer, Fraction>::fromInternal(const typename SFixed<Integer, Fraction>::InternalType & value)

                                     ^

In file included from sketch\FixedPoints/FixedPoints.h:18:0,

                 from sketch\FixedPoints.h:15,

                 from C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:1:

sketch\FixedPoints/SFixedBase.h: In instantiation of 'class FixedPointsDetails::SFixedBase<62u, 64u>::RawType':

sketch\FixedPoints/SFixed.h:64:14:   required from 'class SFixed<62u, 64u>'

sketch\FixedPoints/SFixedFreeFunctions.h:173:80:   required from 'constexpr SFixed<Integer, Fraction> operator*(const SFixed<Integer, Fraction>&, const SFixed<Integer, Fraction>&) [with unsigned int Integer = 31u; unsigned int Fraction = 32u]'

C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:27:14:   required from here

sketch\FixedPoints/SFixedBase.h:36:23: error: instantiation of 'FixedPointsDetails::SFixedBase<Integer, Fraction>::RawType::value' as type 'const InternalType {aka const void}'

    const InternalType value;

                       ^

sketch\FixedPoints/SFixedBase.h:36:23: error: 'FixedPointsDetails::SFixedBase<Integer, Fraction>::RawType::value' has incomplete type

sketch\FixedPoints/SFixedBase.h:36:23: error: invalid use of 'const InternalType {aka const void}'

sketch\FixedPoints/SFixedBase.h:39:30: error: forming reference to void

    constexpr inline explicit RawType(const InternalType & value) : value(value) {}

                              ^

In file included from sketch\FixedPoints/SFixed.h:194:0,

                 from sketch\FixedPoints/FixedPoints.h:21,

                 from sketch\FixedPoints.h:15,

                 from C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:1:

sketch\FixedPoints/SFixedFreeFunctions.h: In instantiation of 'constexpr SFixed<Integer, Fraction> operator*(const SFixed<Integer, Fraction>&, const SFixed<Integer, Fraction>&) [with unsigned int Integer = 31u; unsigned int Fraction = 32u]':

C:\Users\FCTUNL\Documents\Arduino\Test_Floating2\Test_Floating2.ino:27:14:   required from here

sketch\FixedPoints/SFixedFreeFunctions.h:174:123: error: invalid operands of types 'void' and 'void' to binary 'operator*'

  return SFixed<Integer, Fraction>::fromInternal(static_cast<InternalType>((static_cast<PrecisionType>(left.getInternal()) * static_cast<PrecisionType>(right.getInternal())) >> Fraction));

                                                                                                                           ^

sketch\FixedPoints/SFixedFreeFunctions.h:175:1: error: body of constexpr function 'constexpr SFixed<Integer, Fraction> operator*(const SFixed<Integer, Fraction>&, const SFixed<Integer, Fraction>&) [with unsigned int Integer = 31u; unsigned int Fraction = 32u]' not a return-statement

 }

 ^

exit status 1
Erro ao compilar para a placa Arduino Due (Programming Port).

Este relatório teria mais informação com a
opção «Mostrar mensagens detalhadas durante a
compilação» seleccionada nas Preferências.
@Pharap
Copy link
Owner

Pharap commented Mar 9, 2018

Unfortunately this is a limitation that I currently don't have a work around for.

Fixed point multiplication results in a type twice as large as the source type, which is then scaled back down to the appropriate type.
For example, in the case of UQ8x8 it results in a UQ16x16, which is then scaled back down to a UQ8x8 to give the final result.
(There's also a multiply function that doesn't scale back down, in case the larger precision is wanted for some reason.)

In the case of UQ32x32, which is backed by a uint64_t and similarly SQ31x32, which is backed by an int64_t, i.e. both require 64 bits to be stored.
When multiplying either of these, the resulting type would require 128 bits to be stored.
But there is no 128 bit type by default (i.e. no uint128_t or int128_t), so to fix the issue I'd have to either introduce one or introduce a workaround that can reliably achieve 128 bit multiplication.
That would mean implementing a multiplication algorithm instead of being able to rely on the compiler to generate the appropriate multiplication code, which would take a fair bit of research beforehand.


Truth be told, when I originally wrote this I wasn't anticipating people wanting to use the 64 bit-backed types because I wasn't aware of the ARM-based Arduino MCUs, I was only aware of the AVR-based ones which can only realistically achieve 32-bit backed, 16-bit backed ant 8-bit backed variations.

@nunovilhena
Copy link
Author

Hi,
Thanks for your reply!
That was what I was expecting about the multiplication issue!!!
However, I'd like to ask you about another issue!
If I do the multiplication:

SQ15x16 x = 320.153;
SQ15x16 y = 0.000200;
SQ15x16 z = 0.0;

z = x*y;

The result is z = 0.06349182 however the real value is 0.06403060, that means the error is 0.008. If you are using 16 bits for the decimal part, the resolution should be 2^-16 = 0.00001525878. Thus, why the error started in the thousandth part?
Best regards.
Nuno Vilhena

@Pharap
Copy link
Owner

Pharap commented Mar 12, 2018

The error happens when the floats are first converted as well, not just during the multiplication.

320.153 gets stored as 320.1530151367187500 (320 + 10028/65536)
0.0002 gets stored as 0.0001983642578125 (0 + 13/65536)

320.1530151367187500 * 0.0001983642578125 = 0.063506915234029293060302734375
((320 + 10028/65536) * (0 + 13/65536) = (0 + 4161/65536))

So actually 0.0634918212890625 isn't too far off.

Unfortunately you'll always have some amount of error because of the difficulty of expressing decimal fractions in binary.

For example, you can't exactly store 0.153.
Using SQ15x16 the closest you can get is either:
10028 / 65536 = 0.15301513671875
10027 / 65536 = 0.1529998779296875


If you know that the integer part will have a limited range then you can improve the precision of the fractional part.
For example, if you know the integer part isn't going to exceed 2000 then you could make your own type alias using SQ11x20 = SFixed<11, 20>;, which would give you greater precision.

Using SFixed<11, 20> gets a final result of 0.0638113021850585.
Using SFixed<10, 21> gets a final result of 0.0639648437500000.
Using SFixed<9, 22> gets a final result of 0.0639648437500000.
(And so on.)

Even a full 32 bits of fraction would only be able to represent 0.153 as 0.1529999971389770.
In fact I'm not sure how many bits you'd need to actually manage to represent it properly using a fraction-over-power-of-two approach, it might not be possible.


Ultimately depending on what you're calculating, fixed points might not actually be the best solution.
Fixed points are better for dealing with smaller ranges of values.
If you need to cover a large range of values that have both a large integer part and a large fractional part then floating points probably are more suitable.

@Pharap
Copy link
Owner

Pharap commented Mar 17, 2018

As it has been 5 days since the last post,
I'm considering closing this issue.

@nunovilhena,
Have I successfully answered your questions?
Is there something you think I should do to make this problem more obvious in the library documentation or the library source (e.g. give a clearer error message)?

@nunovilhena
Copy link
Author

Hello Pharap,
Sorry my late reply but this week is being very stressful for me!
About my question, yes, you have.
If you could include something to advise about those limitations, should be better yes. About the multiplication/ division limitations and how the conversions between float to fixed_point is done (to show why there are a error in the calculations with your library!
So, you can close this issue, many thanks!

Nuno Vilhena

@Pharap
Copy link
Owner

Pharap commented Mar 17, 2018

It's ok, I wasn't trying to rush you.
I just thought you might have intended to reply and then forgotten because you had other things to do.
(I have sometimes forgotten to press 'send'/'comment' on messages before and only realised the next day.)

I have opened a second issue (#23) to remind myself to add a proper explanation.

As I have answered all your questions, I will close this issue.

@Pharap Pharap closed this as completed Mar 17, 2018
@Pharap Pharap self-assigned this Apr 4, 2018
@Pharap Pharap added Meta This change affects the repository Question This issue was a question asked prior to the introduction of discussions and removed Meta This change affects the repository labels Mar 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question This issue was a question asked prior to the introduction of discussions
Projects
None yet
Development

No branches or pull requests

2 participants