Hacking dist/soft (dividing by 3)


#1

I realise this is more of a general programming question to a certain extent but it's related to the specifics of the processor and peculiarities of the Axoloti number range. I hope someone will humour me but please delete this if it's considered to be off topic.

I'm trying to make a "no gain" version of dist/soft for use in things like feedback loops. Using a graphing calculator I've worked out that what I need is x-(x^3)/3, what I'm actually wondering is if anyone knows a shortcut to working out the /3 bit.

As I understand it, division is quite expensive, so avoiding directly dividing would be beneficial. One idea I had was to use init to store a number in a variable, that when used with ___SMMUL would be like multiplying by 0.33333. Is that the best approach or is there a better one?

So sort of a programming question, but hopefully not an annoying "teach me C++ pls" post.
Cheers,
SPF


#2

Division by a constant should not be too expensive. Alternatively you could multiply (with smmul) by (1/3)*2^27

Like this: ___SMMUL(x3 <<3, 44739243 <<2)

What you're trying to do however is exactly what dist soft does. I think it's sufficient to simply copy the code


#3

Cool thanks, I'll give that a go. That's similar to what I was suggesting but using a precomputed "0.3333", I was going to try and calculate it in init. Would I gain a tiny bit of precision by calculating the coefficient 'pre-scaled' so that the bitshift isn't required in the ___SMMUL operation?


#4

I guess you could put the whole <<5 bitshifting inside the constant and perform the operation in one take. It would surely be more precise (less truncation errors)and to some extent more efficient.
Even though both effects are quite negligible.


#5

So I think the constant I want is 1431655765, ___SMMUL-ing that with a number should divide it by a third, no bitshifting required. Does that sound right? I used the binary mode in the windows calculator to divide 1<<32 by 3, effectively building the <<5 into it.


#6

Sounds pretty reasonable to me. Try to smmul it and see if it smmuls correctly.


#7

Sounds like a good approach to me too.

If you have an expression like

___SMMUL(x3 <<3, 44739243 <<2)

then the x3 << 3 and 44739243 << 2 are evaluated before __SMMUL is called, so it doesn't matter if you have those calculations in the function call or somewhere else. Computationally, the values will be calculated first, then __SMMUL will be called in either case. In that respect, calculating the actual value of the constant and putting it in an init section can be beneficial, because you can tweak the exact value to get exactly the gain you need, down to the last bit.

What I'm getting at is that since you are trying to get a zero gain function for feedback loops, you might want to tweak the exact value to compensate for other rounding errors so that you get a total gain of exactly one for the whole loop.


#8

Good suggestiong Ricard, thanks! I forgot to come back and say it worked as expected, but yes tweaking that constant may be helpful due to rounding errors.