| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
$0DD0 * 0.1234567890 in assembly. How to?
Taking into account the fair compromise of precision, what is the fastest and shortest method for multiplying a 16bit value for a floating point number like 0.1234567890?
Please explain it as if you were writing the book "arithmetic for dummies with 6502/10". Tnx. |
|
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: Taking into account the fair compromise of precision, what is the fastest and shortest method for multiplying a 16bit value for a floating point number like 0.1234567890?
Please explain it as if you were writing the book "arithmetic for dummies with 6502/10". Tnx.
You explicitly say floating point number? Are you sure you know it is a floating point number, if so, in which format, which standard? It's by far easier to use fixed point numbers. Just as with binary where each digit has a value of 2^x the decimal part will have a value of 2^-1.
So for example with an 8.8 fixed point number you have 8 bits for the integer part and 8 bits for the fraction part:
iiiiiiii.ffffffff
So the fraction part can express as small values as 1/256.
Now, to multiply this with a 16-bit integer number, simply do a 16bit * 16bit multiply. The number of incoming integer bits will correspond to the number of outcoming integer bits, same holds for fraction bits. You will input 16 integer bits and another 8 integer bits, giving a total of 24 bits. The fractional input is 8 bits, so you have 8 bits fraction in the result also.
So: 16.0 * 8.8 = 24*8 in terms of bit precision of the integer.fractional parts.
So, unless you're forced to perform floating point, consider use fixed point instead. And then use my multiplication routines at: http://codebase64.org/doku.php?id=base:seriously_fast_multiplic.. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
fastest and shortest way is not to do it. no demo or game code out there does stuff like this. you have to be clever and find a simpler way to do what you want: reducing precision to 8bit*8bit or making use of tables, or just go around it.
and what jackasser said. :) |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: fastest and shortest way is not to do it. no demo or game code out there does stuff like this. you have to be clever and find a simpler way to do what you want: reducing precision to 8bit*8bit or making use of tables, or just go around it.
and what jackasser said. :)
The 3D-engine in Andropolis is all about 8.8*8.8 and 8.8 / 8.8. :) |
| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
So...
if i need to multiply with "fixed point" the value $0DD0 * 0.12345 i must treat $0DD0 if it's $0D.$D0 and multiply for ... what? $D0*12345 and... $0D*$00 ?
Someone can explain... please? |
| |
Fresh
Registered: Jan 2005 Posts: 101 |
It highly depends on what you want to achieve, however you can proceed this way:
- Use 16 bits to represent 0.1234567890 (0 bit at the left of the decimal point and 16 at the right)
- Use 16 bits to represent $DD00 (16 bit at the left of the decimal point and 0 a the right)
This way you need to multiply the following numbers:
$1F9Ax$DD00
Use Jackasser's routine and then consider the 32 bit results as a 16.16 fixed point value.
It's like doing ie 0.5*5: you compute 5*5 ant then you move the decimal point position of the result according to multipliers. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
Quote: So...
if i need to multiply with "fixed point" the value $0DD0 * 0.12345 i must treat $0DD0 if it's $0D.$D0 and multiply for ... what? $D0*12345 and... $0D*$00 ?
Someone can explain... please?
0.5*5.0 is a good example. multiply 0.5 with 10 you get 5. 5*5=25 divide the result with 10, you get 2.5.
now do the same with 256.
1. 0.123456789*256=31.
2. 31*0dd0= 109616.
3. 109616 / 256 = 428
checking the result: dd0*0.123456789 = 436
the difference between the result is the precision loss of using only 8.8 bits math. (throwing away the fraction at the *256 step, hence you can not have fraction in a byte)
note that you dont need to actually divide by 256. dividing by 256 is equal to shifting the bits 8 times to the right. but as we are working with bytes, the multiply result is already using several bytes. just use the part of the result which represents the shifting already.
if you need more precision you have to use a bigger number than 256. |
| |
Fresh
Registered: Jan 2005 Posts: 101 |
In my last post I've written $DD00 instead of $0DD0: it's a stupid typo, consider every occurence of $DD00 as $0DD0. |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: So...
if i need to multiply with "fixed point" the value $0DD0 * 0.12345 i must treat $0DD0 if it's $0D.$D0 and multiply for ... what? $D0*12345 and... $0D*$00 ?
Someone can explain... please?
It's really basic math. Consider the numbers 15*73. To multiply these you write the following:
15
*73
First you do 3*5 = 15. Save the 1-digit:
15
*73
-----
5
Then you do 3*1 = 3 (+1 from previous multiplication) = 4:
15
*73
-----
45
Then you do 7*5 = 35. Save the 3-digit:
15
*73
-----
45
5
And finally you do 7*1 = 7 (+3 from the previous mul) = 10:
15
*73
-----
45
105
Then you add them together: 1050 + 45 = 1095.
Now with decimals, f.e. 1.5 * 7.3 you would do exactly the same and end up with 10.95. Or if you did 15*7.3 you would get 109.5.
Now instead of treating each digit as a 10-base value, simple treat it as a 256-base value. (i.e. each byte is a digit). And do EXACTLY the same.
There's nothing more to it really. |
| |
Frantic
Registered: Mar 2003 Posts: 1648 |
Amen! |