Integer is King? - final thoughts about the EQ challenge
- u-he
- 30215 posts since 8 Aug, 2002 from Berlin
I'm also not sure why in m32() a is shifted right 15 bits first while b is shifted 16 bits. Shouldn't both be shifted 16 bits? (line 
-
AdmiralQuality AdmiralQuality https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=83902
- Banned
- 6657 posts since 10 Oct, 2005 from Toronto, Canada
Trying to optimize a scale by a power of 2 by bitshifting? Is that still faster than a multiply these days?
If you get really clever you can make code with almost no mults (some are unavoidable of course) and no divs. Used to do this with image processing code back in the day.
If you get really clever you can make code with almost no mults (some are unavoidable of course) and no divs. Used to do this with image processing code back in the day.
- KVRAF
- 12615 posts since 7 Dec, 2004
it's working perfectly.
"q should be a long here, no?"
opps. no though, it doesnt matter at all. it only means the float is then converted to int and maybe a slight loss of accuracy since we get 24 bits rather than 32. easily fixed.
aq: you may not recognize this, i assume it's been a while since you've attended grade school. this however is long multiplication in base 2^16.
as for the scaling at 3*, no, it shouldnt be 6*. the m32 function produces the correct result and that is why some numbers are shifted by 15 rather than 16. the multiplication by 2 is done in-process rather than afterward, the result is the same.
as for the m32 function itself, nobody would use long multiplication this way for a 32x32 bit mul since it's supported by the x86 instruction set as i've already described. however, this is how you can manage NxN bit multiplications with limited registers, you must simply use 2^bit base numbers in your long multiplication. long division is also possible using the same methods but in reverse.
if you dont have time to look at the source, which is why i provided it, or you for some reason can not understand it:
the process is a naive ramp waveform filtered by a multimode ("state variable") filter. the order of the linear elements in the filter has been reversed so that the positive feedback compensation element is the second integrator rather than the first. the distortion is a result of (probably) me clipping the wrong way, i didnt spend that much time with it, i spent most of that two hours playing with other code and specifically writing some make files for other projects before i quickly wrote the int vs. float thing.
regardless of if the implementation is correct or not, the intent of this is to demonstrate certain float specific effects. the reason the distortion is decreased after a short period in the float version is because the phase becomes locked. if you have any experience writing pseudo-random number generators you should know that repeating patterns can emerge under the right(wrong for a rand) conditions. in this case, a specific set of conditions occurs and causes the float filter to lock into a perfectly repeating sequence - it has been phase locked or synced. this doesnt occur in the int version because the reasons for this locking are specific to the float data type. so long as both versions are matching (which i can not be sure of, although i think they are) all of the above and all i've previously stated is valid, and proven in a practical example. the code serves it's purpose, i did not write it to be fast or to sound good, it is designed only for the purpose of proving a point and it, i hope, does so completely.
"q should be a long here, no?"
opps. no though, it doesnt matter at all. it only means the float is then converted to int and maybe a slight loss of accuracy since we get 24 bits rather than 32. easily fixed.
aq: you may not recognize this, i assume it's been a while since you've attended grade school. this however is long multiplication in base 2^16.
as for the scaling at 3*, no, it shouldnt be 6*. the m32 function produces the correct result and that is why some numbers are shifted by 15 rather than 16. the multiplication by 2 is done in-process rather than afterward, the result is the same.
as for the m32 function itself, nobody would use long multiplication this way for a 32x32 bit mul since it's supported by the x86 instruction set as i've already described. however, this is how you can manage NxN bit multiplications with limited registers, you must simply use 2^bit base numbers in your long multiplication. long division is also possible using the same methods but in reverse.
if you dont have time to look at the source, which is why i provided it, or you for some reason can not understand it:
the process is a naive ramp waveform filtered by a multimode ("state variable") filter. the order of the linear elements in the filter has been reversed so that the positive feedback compensation element is the second integrator rather than the first. the distortion is a result of (probably) me clipping the wrong way, i didnt spend that much time with it, i spent most of that two hours playing with other code and specifically writing some make files for other projects before i quickly wrote the int vs. float thing.
regardless of if the implementation is correct or not, the intent of this is to demonstrate certain float specific effects. the reason the distortion is decreased after a short period in the float version is because the phase becomes locked. if you have any experience writing pseudo-random number generators you should know that repeating patterns can emerge under the right(wrong for a rand) conditions. in this case, a specific set of conditions occurs and causes the float filter to lock into a perfectly repeating sequence - it has been phase locked or synced. this doesnt occur in the int version because the reasons for this locking are specific to the float data type. so long as both versions are matching (which i can not be sure of, although i think they are) all of the above and all i've previously stated is valid, and proven in a practical example. the code serves it's purpose, i did not write it to be fast or to sound good, it is designed only for the purpose of proving a point and it, i hope, does so completely.
-
AdmiralQuality AdmiralQuality https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=83902
- Banned
- 6657 posts since 10 Oct, 2005 from Toronto, Canada
"base 65535?" Hexadoubletetratritetradecimal?aciddose wrote:aq: you may not recognize this, i assume it's been a while since you've attended grade school. this however is long multiplication in base 2^16.
(And I thought I mentioned working at powers of 2 already.
- KVRAF
- 12615 posts since 7 Dec, 2004
the code is probably wrong, i'm going to put more effort into it. i have a feeling the major difference is still in the implementation rather than between float and int here. the main thing is that this _isnt_ the configuration i was using long ago. also, the clipping thing is the result of a mistake and that almost definitely throws it all off. with moderate values the phase goes out of sync real fast which says to me that the coefficients are not equal.
the clipping is due to the input gain being too high. the input is at 1/8 and clipping is 1/4, so we only get 6db of headroom there. it should have more like 8-12db of headroom. adjust the clip upward or the input_gain downward to fix that.
the clipping is due to the input gain being too high. the input is at 1/8 and clipping is 1/4, so we only get 6db of headroom there. it should have more like 8-12db of headroom. adjust the clip upward or the input_gain downward to fix that.
- KVRAF
- 12615 posts since 7 Dec, 2004
ok, bugs fixed (i think?)
some secrets revealed about xhip's filter if you can understand the code. this is really basic stuff so.. sigh i suppose i can offer this. you know to be honest the thing i'm afraid of is some loser taking my source and using it to write a duplication of xhip in terms of audio processing code, then slap on some fancy gui and start selling it. i wouldnt otherwise mind showing it to all of you, i'd like to really open source it. the reason i dont is because i doubt it'll really benefit anybody except the "bad guys", i dont think you guys for example would be able to contribute to the open source project if it existed.
anyway.
http://xhip.cjb.net/temp/public/mmode.c
a large amount of the previous configuration's difference was due to error introduced in a couple places. i've discovered that my long multiplication function isnt working right and i'm too damn lazy to work on this any more today, i'm getting fed up with it.
despite that, with the problems fixed there was still a small difference, although i've found that i can make both int and float versions phase lock, so i deserve a spanking. i was wrong there, it isnt due to float specific behaviour.
i've still been unable to recreate the error conditions that i remember experiencing the last time i tried a float version, but i suspect that may be because either i still dont have the code working correctly, or, i'm not able to tweak around enough editing values by hand. i might need to put this into a vst plugin or something in order to allow us to tweak it and get some real comparison through a wide range of parameter configurations.
anyway, once again despite _that_, there is still observable difference in the configuration i'm offering in the new .c file here. i suspect this is actually due to limited resolution in one of the data types, but i havent gone through the process of tracking the resolution step-by-step to see exactly what the cause is. the important thing is, the float version seems to be going out of range while the int version seems to remain in range. or maybe the float version is in range while the int version is further in range.
i've also been able to observe that the float version is able to remain stable at very high positive feedback levels (very low res) and i'm not sure why. it might be related to precision, but it doesnt seem to me like float has an advantage here.
i'd have to go through step-by-step with the calculation for that as well, i'm just too bored with this to continue today. if anybody else wants to experiment, i'd be interested to hear about it, and you can upload your modified sources to http://xhip.cjb.net/upload if you like.
some secrets revealed about xhip's filter if you can understand the code. this is really basic stuff so.. sigh i suppose i can offer this. you know to be honest the thing i'm afraid of is some loser taking my source and using it to write a duplication of xhip in terms of audio processing code, then slap on some fancy gui and start selling it. i wouldnt otherwise mind showing it to all of you, i'd like to really open source it. the reason i dont is because i doubt it'll really benefit anybody except the "bad guys", i dont think you guys for example would be able to contribute to the open source project if it existed.
anyway.
http://xhip.cjb.net/temp/public/mmode.c
a large amount of the previous configuration's difference was due to error introduced in a couple places. i've discovered that my long multiplication function isnt working right and i'm too damn lazy to work on this any more today, i'm getting fed up with it.
despite that, with the problems fixed there was still a small difference, although i've found that i can make both int and float versions phase lock, so i deserve a spanking. i was wrong there, it isnt due to float specific behaviour.
i've still been unable to recreate the error conditions that i remember experiencing the last time i tried a float version, but i suspect that may be because either i still dont have the code working correctly, or, i'm not able to tweak around enough editing values by hand. i might need to put this into a vst plugin or something in order to allow us to tweak it and get some real comparison through a wide range of parameter configurations.
anyway, once again despite _that_, there is still observable difference in the configuration i'm offering in the new .c file here. i suspect this is actually due to limited resolution in one of the data types, but i havent gone through the process of tracking the resolution step-by-step to see exactly what the cause is. the important thing is, the float version seems to be going out of range while the int version seems to remain in range. or maybe the float version is in range while the int version is further in range.
i've also been able to observe that the float version is able to remain stable at very high positive feedback levels (very low res) and i'm not sure why. it might be related to precision, but it doesnt seem to me like float has an advantage here.
i'd have to go through step-by-step with the calculation for that as well, i'm just too bored with this to continue today. if anybody else wants to experiment, i'd be interested to hear about it, and you can upload your modified sources to http://xhip.cjb.net/upload if you like.
-
AdmiralQuality AdmiralQuality https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=83902
- Banned
- 6657 posts since 10 Oct, 2005 from Toronto, Canada
I'm thinking about doing an integer version of Naive LPF. No code to share (there's one or two things in there that are so naive they're actually secrets
) but I'd tell you roughly what I changed.
I wouldn't be worried about totally optimizing the math either, that's not the point, just getting the same task done with ints, and matching behavior as spot on exactly the same as I can get them. Which I'm VERY sure is possible.
Too bad I'm so busy fighting with a hang-the-ASIO-driver bug now that makes me have to reboot every time I try to run the plug-in or out of the debugger (doing a 2.4 SDK and VSTGUI 3.5 port at the same time... fun, NOT!) Though... it might be worth it just to take a break!
I wouldn't be worried about totally optimizing the math either, that's not the point, just getting the same task done with ints, and matching behavior as spot on exactly the same as I can get them. Which I'm VERY sure is possible.
Too bad I'm so busy fighting with a hang-the-ASIO-driver bug now that makes me have to reboot every time I try to run the plug-in or out of the debugger (doing a 2.4 SDK and VSTGUI 3.5 port at the same time... fun, NOT!) Though... it might be worth it just to take a break!
- KVRAF
- 12615 posts since 7 Dec, 2004
hm, you might want to reconsider using coding int as a vacation activity 
http://xhip.cjb.net/temp/public/int.flo ... erence.wav
here is the difference between the latest double output and int output. i'm using the x86 mul now rather than my long multiplication function, so it's much more accurate. the difference doesnt start to apear until you get into higher frequencies. you can tell it isnt an issue of differences in the coefficients since there is no difference in phase over time - they're locked into phase almost completely.
the int version "seems" to be "more correct" as far as i can see. that will require a more complete analysis of the output though. i'm still thinking i've got some error in my code, the difference is just too damn large. you can see in that .wav the difference is at -20db which is much higher than i remember measuring before. the difference in peak amplitude between the float and int version is an insane 6db. if there isnt any problem remaining with the code, this result would even surprise me.
http://xhip.cjb.net/temp/public/int.flo ... erence.wav
here is the difference between the latest double output and int output. i'm using the x86 mul now rather than my long multiplication function, so it's much more accurate. the difference doesnt start to apear until you get into higher frequencies. you can tell it isnt an issue of differences in the coefficients since there is no difference in phase over time - they're locked into phase almost completely.
the int version "seems" to be "more correct" as far as i can see. that will require a more complete analysis of the output though. i'm still thinking i've got some error in my code, the difference is just too damn large. you can see in that .wav the difference is at -20db which is much higher than i remember measuring before. the difference in peak amplitude between the float and int version is an insane 6db. if there isnt any problem remaining with the code, this result would even surprise me.
-
AdmiralQuality AdmiralQuality https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=83902
- Banned
- 6657 posts since 10 Oct, 2005 from Toronto, Canada
It's the kind of vacation where you don't need to get out of your chair.aciddose wrote:hm, you might want to reconsider using coding int as a vacation activity![]()
- u-he
- 30215 posts since 8 Aug, 2002 from Berlin
Hmmm, I've recently written my own BigInt lib using modular arithmetics. One major thing was multiplication of signed stuff. I ended up multiplying positive numbers and then taking the two's complement if necessary...
The modular thing in AD's code takes the sign bit into account for each of the operations, on MSBits as well as on LSBits. Thus the sign bit eats up 2 out of 32 bits. Also... two's complement... (-2 & 0x80007FFF) != -2... right?
Or maybe I just need another coffee...
The modular thing in AD's code takes the sign bit into account for each of the operations, on MSBits as well as on LSBits. Thus the sign bit eats up 2 out of 32 bits. Also... two's complement... (-2 & 0x80007FFF) != -2... right?
Or maybe I just need another coffee...
- KVRAF
- 12615 posts since 7 Dec, 2004
i think this works (tested by subtracting from the x86 asm functions, results in 0s)
Code: Select all
long m32l(long a, long b)
{
long r = 0;
r += (a>>16 & 0xFFFF) * (b>>16 & 0xFFFF);
r += ((a>>16 & 0xFFFF) * (b & 0xFFFF)) >> 16;
r += ((b>>16 & 0xFFFF) * (a & 0xFFFF)) >> 16;
r += ((a & 0xFFFF) * (b & 0xFFFF)) >> 16;
r += ((a^b) >> 31) & 1;
return 2*r;
}
-
- KVRist
- 174 posts since 19 Oct, 2004
It's quite an interesting challenge to do a 32 bit multiply using only a 32 bit reg.. I'm not sure if the version you posted is working properly, try 0x7fffffff*0x7fffffff, also negative*positive doesn't seem to work either..
Here's what I've come up with:
The only problem with this is when we scale-shift the registers, I can't see an efficient way to round up if we shift out bits, therefore it's giving rounded-down results with some inputs..
Sam
Here's what I've come up with:
Code: Select all
long sMul32(long a, long b)
{
long acc;
acc = ((unsigned long)((a&0x0000ffff)*(b&0x0000ffff)))>>31; //ulow*ulow
acc += ((a>>16)*(b&0x0000ffff))>>15; //shigh*ulow
acc += ((b>>16)*(a&0x0000ffff))>>15; //shigh*ulow
acc += ((a>>16)*(b>>16))<<1; //shigh*shigh
return acc;
}Sam
-
- KVRian
- 1002 posts since 1 Dec, 2004
My opinion on all this is that, hmm, all this stuff is a bit of a waste of time. Even if there was a sound difference, it would be very, very small, and probably masked by at least the much, much louder and audible main signal between 1khz and 4khz, not to mention the loud musical fundamentals under 1khz. This sort of fetishism is imho counter-productive. This also applies a bit to anti-alias stuff, although it's much more justified for alias (because it's actually relatively audible, although it's rarely proeminent and often mostly masked by the loud drums, depending on the case, and raw sharp waveforms at high frequencies do generate a lot of it).
I'm no audiophile. I'm just a composer.
I'm no audiophile. I'm just a composer.

