Argh. On my phone and didn't quite cover the last question!
Using 32-p for q works fine, but this requires some shifting around if one is feeding in the result of a previous <p> operation, as per my final thought above.
Iain
Argh. On my phone and didn't quite cover the last question!
Using 32-p for q works fine, but this requires some shifting around if one is feeding in the result of a previous <p> operation, as per my final thought above.
Iain
Edit: Removed faulty code... Will be back later with some that works, I hope!
[I realise the if
I've added could be optimised a little to use a negative shift operation, but I prefer explicit code and I never try to out-optimise my compiler ;-)]
OK, adding this to fixed_class.h seems to work (all the time now!), and provides the template function f_inv
to handle non-16-bit precision cases:
// q is the precision of the input
// output also has precision of q
template <int q>
inline fixed_point<q> f_inv(fixed_point<q> a)
{
int p=32-q;
int helper;
bool sign = false;
fixed_point<32-q> x;
fixed_point<q> retVal;
x.intValue = fixinv<q>(a.intValue);
helper=x.intValue;
if (a < 0) {
sign = true;
a = -a;
}
if (p==q) {
// Do nothing!
} else {
if (q<p) { // Need to right-shift
helper >>= (p-q);
} else { // Need to left-shift
helper <<= (q-p);
}
}
retVal.intValue = helper;
if (sign) {
return -retVal;
} else {
return retVal;
}
}
One can then do a*f_inv<P>(b)
iainism - IMHO this is confusing, and not explicit.
It appears to be
template <int q> inline fixed_point<q> f_inv(fixed_point<q> a)
but it actually adjust the number so that the return value is a fixed_point<32-q>
, and not a fixed_point<q>
.
IMHO it would be clearer if it were:
template <int p> inline fixed_point<p> f_inv(fixed_point<p> a)
and it kept all of the details of how it achieves that internal, and actually return a fixed_point<p>
.
Or it were
template <int p, int q> inline fixed_point<q> f_inv(fixed_point<p> a)
NB: it can silently overflow, and lose the most significant bits.
If it does helper <<= (q-p);
the upper bits are discarded which could have the effect of drastically changing the value.
Edit: NB 2: the sign might be incorrect, but this is related to the overflow due to helper <<= (q-p);
which could shift a '1' into the top, sign, bit, and change the sign of the value.
Hi gbulmer.
[The last paragraph of this post may be more significant then the remainder]
"It appears to be template <int q> inline fixed_point<q> f_inv(fixed_point<q> a)
but it actually adjust the number so that the return value is a fixed_point<32-q>, and not a fixed_point<q>."
Yes, it is slightly confusing, but this is due to the nature of Trenki's library function:
template <int q> inline fixed_point<q> fixinv(fixed_point<q> a)
Which sits behind inv<p>
(for p=) and takes a fixed_point<q>
but returns a fixed_point<32-q>
, which is fine for inv<16>. The purpose of my code is to convert the returned value back to fixed_point<q>
when q isn't 16.
I've corresponded with Trenki, who has pointed out that the sign conversion in my code above isn't necessary, as the sign bit is preserved by the bitwise shifts (something I'd forgotten in the 10 years or so since I last did bitwise operations!). His suggestion is:
// q is the precision of the input
// output also has precision of q
template<int q>
inline fixed_point<q> f_inv(fixed_point<q> a)
{
const int p = 32 - q;
fixed_point<q> retVal;
retVal.intValue = fixinv<q>(a.intValue);
if (q < p)
retVal.intValue >>= (p - q);
else
retVal.intValue <<= (q - p);
return retVal;
}
I suppose a logical step could be to create a .longValue
(similar to .intValue
) to allow overflow checking but I'm not sure how much use this would be, since this would still leave an opening for underflow when using a low number of fractional bits and inverting large numbers...
In any case this could all be moot, since in my (very brief) tests, it seems (that for p != 16) the division operator outperforms taking the product of a fixed_point<p>
and a f_inv<p>(fixed_point<p>)
. Which is a trifle vexing!
ianism
I've corresponded with Trenki, who has pointed out that the sign conversion in my code above isn't necessary, as the sign bit is preserved by the bitwise shifts
That is not completely accurate.
The sign is preserved for signed integers by >>=
.
As I mentioned in my earlier post, sign is not preserved for <<=
.
This shift could move a '1' into the most-significant-bit (msb), which is always an error because that bit represented part of the value, and not the sign of the value. The rewritten code still has the same error. The error won't happen on every value, only the values where a '1' is shifted into the msb.
The fact that division is faster is pretty interesting.
Hi gbulmer - thanks for catching that - you're absolutely right (again) about the sign bit. I really need to brush up on my bitwise operations!
iainism - while this isn't very helpful to you, but following you through this fixed point stuff is very interesting to me. I suspect several people are (or will be) getting some benefit from following along with you. So thanks for all you effort.
Indeed, as a Maple newcomer and audio enthusiast, I'm extremely interested in the outcome of this work. Is this the topic covering technical points about the "fixed point library" that is announced on the documentation of the Maple?
dapoup - This has been used to discuss the fixed point.
Some folks are trying a newer (than LeafLabs) gcc from https://launchpad.net/gcc-arm-embedded which has fixed point support built in.
Hi both - I'm glad this is proving useful to someone.
I will return to the library later this year, but at the moment working on the project for my MSc is swallowing somewhere between most and all of my time when I'm not sleeping!
You must log in to post.