|
|||||||
![]() |
|
|
LinkBack | Thread Tools |
|
|
#1 |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Dane number conversions, etc
The Dane programming guide does not give a full description of how Dane translates numbers from decimal to hexadecimal. I did some basic tests in Dane trying to verify how it handles the translations and the following seems to be how it works.
Positive Fractional numbers (0 < number <= 1) works as listed in programmers guide. i.e. Hex = Dec * (2^31-1) The guide however does not mention negative numbers. It seems that negative fractional numbers (-1 <= number < 0) are represented as follows: hex = ~( abs( (Dec) * (2^31-1) ) ) Where "~" inverses all the bits, and abs is the absolute value function. Integer numbers however work differently. Positive integers take their normal representation in hex (with the exception of 1 which gets translated to fractional 1). i.e. 3 decimal = 00000003 hex Negative integers (with the exception of -1 which gets translated to fractional -1) on the other hand seem to be represented as follows: hex = ~( abs(Dec) ) + 1 Rounding of floating point numbers that are greater than 1 or less than -1 seem to work as follows. (you can't use floating point numbers like this, but the .da will still compile, as Dane will round the numbers and give you a warning that the numbers were truncated). The numbers are rounded to the nearest integer (based on the 1st decimal place only), and then represented in hex using the above integer representations (this time including 1 and -1. 1 and -1 are treated as integers and not fractional numbers after rounding (i.e. 1.1 decimal gets rounded to 1 decimal and translated to 00000001 hex)) I thought I would post this info, so that other people do not have to try and figure it out themselves. Can anyone verify that the above is accurate for me? Maybe I will make a small utility to convert the numbers for anyone that wants to use it, and thus not have to constantly do it manually with a calculator, which can be a pain, especially with the negative numbers. Also, I did not find much information on kxctrl anywhere, but have found it useful (from just playing around with it to try and figure out what it does) in troubleshooting plugins, and for simple testing to verify how some things work in Dane, etc. If you run kxctrl with the -gui switch, you can use the "mp" command to view all of the loaded plugins. You can then use "mp" and the number of the plugin (as listed from the "mp" command, i.e. "mp 2") to view the registers, and thus verify the values of those registers. Of course it is only a snapshot of the registers (some of which might be changing 48000 times a second), but it is useful to check constant values, and check for saturations, and as I mentioned previously, for simple testing to verify how something might work in Dane, etc. I also found it useful the first time I tried to update the registers dynamically from C++, as I could set a breakpoint in C++ after updating the register, and then verify the value of that register using the "mp" command, etc, and thus verify that I was doing it right. Of course the registers values are in hexadecimal, and thus you need to know all the details of how to translate the values back and forth between decimal and hexadecimal (including negative numbers) and thus another reason for the first part of this post. Anyway, I thought I would include this info as well, so that maybe others who have not figured this out yet themselves, will not have to figure it out themselves. ![]() Hope this is useful. -Russ Last edited by Russ; Mar 11, 2005 at 11:09 PM. |
|
|
|
|
|
#2 |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Here is the info on converting from hexadecimal back to decimal. It is a little trickier becuase the same number in hex, can be used to represent an integer or a fractional number, so you will have to do which ever calculation fits the context.
First you need to check the sign bit. One way to do this, is to AND the number with 80000000 hex. A result of 0 means that the numbers is positive, otherwise (result is 80000000), the number is negative. Then you need to decide on the context (whether the number should be an integer or fractional number). For a positive fractional number, you do as stated in the Dane programming guide. Dec = Hex / (2^31+1) For a negative fractional number: Dec = -1 * ( ~(Hex) / (2^31+1) ) Again "~" is the one's compliment operator (invert all the bits in the number). For a positive integer number, convert directly to decimal (i.e. just change calculator from hex mode to decimal mode). For a negative integer: Dec = -1 * ( ~(Hex) + 1 ) I think that should cover all the number conversions. -Russ BTW: With the Windows calculator (in Scientific mode) you can use the "Not" key to invert the bits of a number (where you see "~" above, but make sure if you are in any mode other than decimal, that the display size is set to Dword). Last edited by Russ; Mar 7, 2005 at 10:19 PM. |
|
|
|
|
|
#3 |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
I thought I would add the steps to do all the conversions using the Windows Calculator for clarity.
First some additional info: Calculator should be in Scientific Mode (View -> Scientific) Digit Grouping can be useful for checking the Sign bit (View -> Digit Grouping) Display Size should be Dword (applicable to Hex, Oct, and Bin modes) The sign bit is the 32nd bit (read from right to left in Bin mode) Leading 0's are not shown in Bin mode, therefore you will either see a 1 (negative number) or nothing (positive number) at the location of the Sign bit. This is where Digit Grouping can be useful, as the bits will be in groups of 4 (making it easier to count the number of bits to check the Sign bit). i.e. 1100 0000 0000 0000 0000 0000 0000 0000 ^ The Sign bit. The conversions: Decimal Integers to Hexadecimal:
-Russ |
|
|
|
|
|
#4 |
|
kX user
Join Date: Apr 2004
Posts: 851
Rep Power: 0 ![]() |
If you like you could make it a html and I could put it in the guide.
__________________
Miss you, Steve... |
|
|
|
|
|
#5 |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Ok, I will do that. I was considering asking about that, but I was hoping someone could verify my conclusions first. Addionally I was trying to determine the precision used. For example, I noticed Dane will recognize up to 20 decimal places (but not accuratley), and was trying to figure out how it handled numbers such as these (does it round it off at same place, if so where?, etc, so far I haven't been able to figure it out for sure).
-Russ |
|
|
|
|
|
#6 |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Here is the test I was trying to use to determine the accuracy.
I converted 0x1 to decimal using Windows calculator. 0x2 = 0.000000000931322574615478515625 (this is exact) I then tested this number in Dane and it translared as 0x1 (which is incorrect, although was expected, as a truncation at any of the decimal places would have a semi-accurate result of 0x1). I then started from the last decimal place and started changing numbers trying to determine how many decimal places Dane used for it's translation, and to try and determine what is does with these numbers before translating (rounding, trucation, etc). The first place I noticed a difference was at the 18th decimal place. 0.000000000931322574615478515625 (this is exact number again) 0.000000000931322574 (Dane translated it as 0x1 - semi-accurate) 0.000000000931322575 (Dane translated it as 0x1 - not accurate) 0.000000000931322576 (Dane translated it as 0x2 - semi-accurate) The above result was confusing... If it was rounding off using the 18th decimal place, then the last 2 numbers should have had the same result, and if it was truncating the 18th decimal place then all 3 numbers should have had same result? As it was recognizing a difference in the 18th decimal place, I decided to work with second number (as it was the changing point), and see if it would recognize further decimal places. 0.000000000931322575 (starting number) 0.0000000009313225754 (Dane translated it as 0x1 - not accurate but consistant if it was rounding off based on this decimal place) 0.0000000009313225755 (Dane translated it as 0x2 - semi-accurate and consistant if it was rounding off based on this decimal place) 0.00000000093132257504 (Dane translated it as 0x1 - not accurate and not consitant) 0.00000000093132257505 (Dane translated it as 0x2 - not accurate and not consitant) I got as far as 22 decimal places: 0.0000000009313225750491 (translated to 0x1) 0.0000000009313225750492 (translated to 0x2) At this point, I couldn't make any sense of the results (i.e. couldn't find any logic to why the results were different, and gave up. It may even recognize further decimal places). When I say the result is semi-accuate, I mean that the result is correct, but it cannot be translated back to decimal accuratley. For this reason it is not important when using Dane (I usually only use 9 decimal places for entering numbers as Eyagos told me (in another thread) that DSP uses only 9 digits), but in trying to make a utility to mimic the translation that Dane uses I was trying to determine what it was doing, and obviously I have not figured it out as of yet. Anyway, that is what I meant when I mentioned precision above. |
|
|
|
|
|
#7 |
|
DriverHeaven Newbie
Join Date: Nov 2004
Posts: 7
Rep Power: 0 ![]() |
hello.
Russ, could you please clarify one thing i can't understand: in you first post you wrote: "Fractional numbers (0 < number <= 1) works as listed in programmers guide. i.e. Hex = Dec * (2^31-1)" in the second ost you state that "for a positive fractional number, you do as stated in the Dane programming guide. Dec = Hex / (2^31+1)" finally what scale is correct: '2^31-1' or '2^31+1' ? Later you confused me even more: "0x2 = 0.000000000931322574615478515625 (this is exact)" But "0.000000000931322574615478515625 = 2 / (2^31+0)" where i'm wrong? |
|
|
|
|
|
#8 |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Hi, that first line should read "Positive fractional numbers".
As for the scale, both are correct, depending on whether you are converting to hex or from hex. (One is the inverse of the other) As for the last part, that is my fault, I apologize. I actually did not use the Windows Calculator for that. I used the PowerToy Calculator (because I can enter in Functions and thus do the calculations quicker), with the precision set to 32 bits, and that is why you are getting different results (different precision). That might also be why I was having problems figuring out Dane's precision. I will have to try some more tests using a higher precision setting. Thanks for pointing that out. -Russ Last edited by Russ; Mar 11, 2005 at 11:22 PM. |
|
|
|
|
|
#9 |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Another thing that might be confusing you, is that the conversions are not exact. This is because 1 cannot be represented exactly using this method.
i.e. 1 = 0x7FFFFFFF 0x7FFFFFFF = 0.99999999906867742581820235316725 = 0.999999999 (9 digits) 0.5 = 0x3FFFFFFF 0x3FFFFFFF = 0.49999999930150806936365176487544 = 0.499999999 (9 digits) -Russ Last edited by Russ; Mar 11, 2005 at 11:26 PM. |
|
|
|
|
|
#10 |
|
DriverHeaven Newbie
Join Date: Nov 2004
Posts: 7
Rep Power: 0 ![]() |
>As for the scale, both are correct, depending on whether you are converting to hex or from hex.
I cannot agree. I think the scale should not depend on the direction of conversion. if it was like this then { H = D * (2^31-1); D = H / (2^31+1); } causes D = (D * (2^31-1)) / (2^31+1); and then we get (2^31+1) = (2^31-1); - impossible. ------------------ I assume that Dane uses "(2^31-1)" for positive numbers and "(2^31+0)" for negative. Then it becomes easy to explain inconsistency you mentioned above: "0.00000000093132257504 (Dane translated it as 0x1 - not accurate and not consitant) 0.00000000093132257505 (Dane translated it as 0x2 - not accurate and not consitant)" 0.00000000093132257504 * (2^31-1) = 1.99999999998033; (Dane thinks it's 1) 0.00000000093132257505 * (2^31-1) = 2.00000000000181; (Dane thinks it's 2) So it looks like it just uses truncation instead of more correct rounding. ------------------- "1 = 0x7FFFFFFF 0x7FFFFFFF = 0.99999999906867742581820235316725" Yep, that makes sense.... Otherwise both +1.0 and -1.0 must be represented as 0x80000000 (it seems to be a compromise for 32-bit fractionals) |
|
|
|
|
|
#11 |
|
DriverHeaven Newbie
Join Date: Nov 2004
Posts: 7
Rep Power: 0 ![]() |
btw. I think we can ask Eugene to post here the internal Dane's source code it uses for numeric conversions
(under persmission of Max probably). So anyone can see it and then correct/improve it if there's something really wrong. Is this possible? (finally, why should we conjecture?) |
|
|
|
|
|
#12 | ||
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Yeah, I know that it trucates the decimal result, when it converts to hex, I was trying to find out what it did with the original decimal number before the conversion (where the rounding or truncation point was).
I figured out what my problem was with the PowerToy calculator. Something happened (not sure what), that changed the function definitions that I was using, so it was doing 2^31, instead of 2^31-1, and thats why my calculations were wrong as you noticed. Quote:
![]() Quote:
i.e. -0.4 * 2^31 = -858993459.2 The Windows calculator uses the sign when it converts it to hex, and shows the correct result of 0xCCCCCCCD. But when you try to convert it back, the calculator does not use the sign bit, and converts it back as 3435973837, and then doing the division (3435973837 / 2^31), results in 1.6000000000931322574615478515625. |
||
|
|
|
|
|
#13 | |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Quote:
I am pretty sure I have the formulas correct (and Dane doesn't actually convert the values back to decimal, so it wouldn't help with that). I did make a utility to test with using those formulas and it was producing the same results as Dane (I didn't test extensively as of yet). I figured Dane just stored the values as doubles (in C++) and did the calculations using doubles (so my utility using doubles would end up with the same results). Then I noticed that Dane rounded floating point values, using the 1st decimal place only (which C++ doesn't do, C++, truncates when converting to integer), so I thought I should look into how Dane handled fractional numbers, to see if it did anything different, and thus my testing (which turned out to be flawed). Anyway, when I have a chance, I will redo my tests using the correct functions in PowerToy calculator. -Russ |
|
|
|
|
|
|
#14 | |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Quote:
-Russ |
|
|
|
|
|
|
#15 |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
I did a very quick test using both methods to compute 0.5 * 0.5:
0.5 * 0.5 = 0.25 0.5 ^ (2^31-1) = 0x3FFFFFFF 0.5 ^ (2^31) = 0x40000000 ------------------ static a=0.5 static b=0x40000000 static c=0 static d=0 macs c, 0, a, a macs d, 0, b, b ------------------ Here are the results: ; Registers [8000]: 'a' p=3fffffff; translated: 100; current=3fffffff [8001]: 'b' p=40000000; translated: 101; current=40000000 [8002]: 'c' p=0; translated: 102; current=1fffffff [8003]: 'd' p=0; translated: 109; current=20000000 0x1FFFFFFF / (2^31+1) = 0.249999999 (0.24999999941792339113637647072953) 0x20000000 / (2^31) = 0.25 (this is exact) -Russ Anyway, that is all for now. I'll look at it more tomorrow... |
|
|
|
|
|
#16 |
|
kX user
Join Date: Apr 2004
Posts: 851
Rep Power: 0 ![]() |
For 0x7fffffff the correct formula is:
0x7fffffff/(2^31-1)=1 For other positive fractional values: 0x20000000/2^31 = 0.25 0x40000000/2^31 = 0.5 etc. The conversion should be done after the hex value is converted to decimal (Powertoys calc does this automatically, windows default calc doesn't)
__________________
Miss you, Steve... |
|
|
|
|
|
#17 | ||
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Quote:
Quote:
-Russ |
||
|
|
|
|
|
#18 |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
BTW: As it turns out, negative fractional numbers on the other hand are being represented correctly, but I think that is just coincendental (although I cannot be sure how Dane is doing the conversion (whether it is using 2^31 or 2^31-1 for negatives).
i.e. -0.5 -0.5 * 2^31 = -1073741824 Then stored in 2's Compliment form: ~( abs(number)) + 1, for a negative number: abs(-1073741824) = 1073741824 = 1000000000000000000000000000000 binary ~(1000000000000000000000000000000) = 10111111111111111111111111111111 10111111111111111111111111111111 + 1 = 11000000000000000000000000000000 11000000000000000000000000000000 = 0xC0000000 You can get the same result using (2^32-1) and storing number in 1's compliment form (the formula I showed in my first post in this thread), but doing it the above way makes more sense. -Russ |
|
|
|
|
|
#19 |
|
kX user
Join Date: Apr 2004
Posts: 851
Rep Power: 0 ![]() |
Here's how double is converted to dword in the SDK:
Code:
inline dword _dbl_to_dspword(double x)
{
double y = (x * 2147483647.5) - 0.25;
y += 6755399441055744.0;
return ((dword*) &y)[0];
}
__________________
Miss you, Steve... |
|
|
|
|
|
#20 |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
You will notice that fractional numbers (including -1, excluding 1) can be represented exactly using this method:
2's Compliment: A Positive Number is represented as a simple unsigned binary. A Negative Number is represented as the binary number that when added to a positive number of the same magnitude equals zero. To form a negative number:
-1 * 2^31 = -2147483648 = ~(abs(-2147483648)) + 1 = 0x80000000 0x80000000 = ~(0x80000000) + 1 = 2147483648 / 2^31 = 1 * -1 = -1 -.5 * 2^31 = -1073741824 = ~(abs(-1073741824)) + 1 = 0xC0000000 0xC0000000 = ~(0xC0000000) + 1 = 1073741824 / 2^31 = .5 * -1 = -.5 .5 * 2^31 = 1073741824 = 0x40000000 0x40000000 = 1073741824 / 2^31 = .5 This makes all the conversions accurate both ways (except 1 as it cannot be represented exactly, and thus we have to choose the closest representation possible for it: 0x7FFFFFFF). -Russ Last edited by Russ; Mar 12, 2005 at 05:48 PM. |
|
|
|
|
|
#21 | |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Quote:
i.e. 0.5 = 0x3FFFFFFF Using the PowerToy Caculator with the function: test(x)=((x*2147483647.5) - 0.25) + 6755399441055744.0 test(0.5) = 6755400514797567.5 = 0x1800003FFFFFFF.8 -Russ Last edited by Russ; Mar 12, 2005 at 06:17 PM. Reason: should have read low 32 bits rahther than 16 |
|
|
|
|
|
|
#22 |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
I am not sure why that function was chosen (maybe it is what Creative uses?). Maybe it is to center the values more between -1 and 1. In any case, it makes the conversions confusing.
![]() -Russ |
|
|
|
|
|
#23 |
|
kX user
Join Date: Apr 2004
Posts: 851
Rep Power: 0 ![]() |
I think that the last line is the important one. I'm shure that the values are converted the way they should be. The values passed from c are always accurate - for instance if you test set_dsp_register("register", _dbl_to_dspword(1.0)); the value will always be 0x7fffffff and don't forget that for each control register in dane kx creates a fader, play around with it and you'll see that it is always accurate (move the fader and look at the dump, not the source).
__________________
Miss you, Steve... |
|
|
|
|
|
#24 | |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Quote:
Try testing set_dsp_register("register", _dbl_to_dspword(0.5)); and see what the result is (0x3FFFFFFF or 0x40000000). Currently my C++ is not setup to work with the Dane SDK, so I will have add all the libraries and stuff back in to test (I am using .NET, so if I want to do something that doesn't involve the kX SDK, I have to remove the VS 6.0 MFC files, etc). I will check it out when I have a chance. -Russ |
|
|
|
|
|
|
#25 |
|
kX user
Join Date: Apr 2004
Posts: 851
Rep Power: 0 ![]() |
As I said in my previous post you can check the faders created for 'control' registers in dane, I'm shure the conversion formula is the same - the 'vol' effect for instance. Set it to 50% and you'll se that it has set the control register to 0x40000000.
__________________
Miss you, Steve... |
|
|
|
|
|
#26 |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Ahh, that's interesting because Dane does not do that when it does the conversion. I will check that out.
-Russ |
|
|
|
|
|
#27 |
|
kX user
Join Date: Apr 2004
Posts: 851
Rep Power: 0 ![]() |
What do you mean that it does not do that, I don't see a reason why Eugene would use a different formula for dane and for the sdk.
__________________
Miss you, Steve... |
|
|
|
|
|
#28 |
|
HardwareHeaven Extreme Member
Join Date: Jan 2005
Posts: 4,984
Rep Power: 44 ![]() ![]() ![]() ![]() |
Type static a = 0.5 in Dane, save it, and then look at the Dump.
It stores 0.5 as 0x3FFFFFFF -Russ |
|
|
|
|
|
#29 |
|
kX user
Join Date: Apr 2004
Posts: 851
Rep Power: 0 ![]() |
I just checked in the sdk and he uses the same formula, so again - the secret must be that last line of code in _dbl_to_dspword, I'll have to check my C++ books to see what's that line actually doing, I have forgotten many things since I read them, things that I have never used...
__________________
Miss you, Steve... |
|
|
|
|
|
#30 | |
|
kX user
Join Date: Apr 2004
Posts: 851
Rep Power: 0 ![]() |
Quote:
__________________
Miss you, Steve... |
|
|
|
|
![]() |
| Bookmarks |
| Thread Tools | |
|
|