16 June 2011, 08:46 | #1 |
Zone Friend
Join Date: Apr 2006
Location: Gothenburg/Sweden
Age: 48
Posts: 345
|
Floating point without FPU
Are there any clever ideas on how to deal with (or simulate) floating point values in 68k asm? I've been coding 68k asm for many years but almost never worked with decimals.
My code would look something like this psuedocode below. I could perhaps do it with the FPU but last time I experimented with the FPU it was quite slow.. "Psuedocode:" move.l #113.66,d0 .... sub.l #2,d0 blt minus ... minus: add.l #113.66,d0 ... |
16 June 2011, 09:42 | #2 |
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,552
|
When 16-bit precision is enough, you could try 16+16 bits fixed point numbers:
Code:
move.l #(113<<16)|$a8f5,d0 ; $10000*0.66 = $a8f5 ... sub.l #(2<<16),d0 |
16 June 2011, 13:37 | #3 |
it's all in your head
Join Date: Feb 2011
Location: The Netherlands
Posts: 174
|
multiply by a thousand? :P (cheating perhaps)
|
16 June 2011, 14:00 | #4 |
move.l #$c0ff33,throat
Join Date: Dec 2005
Location: Berlin/Joymoney
Posts: 6,865
|
|
16 June 2011, 17:22 | #5 |
Registered User
Join Date: Nov 2006
Location: Stockholm, Sweden
Posts: 237
|
There are also a bunch of pages out there on the interwebs which describe how fixed point arithmetic works.
|
23 June 2011, 23:44 | #6 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,690
|
What you do is you treat it like a unit vector with scale, except the scale is a shift and not a multiply.
Decimal example: 0.4356347*10^-1 is 0.04356347 0.4356347*10^7 is 4356347 (-1, 7 are exponent, 0.43... is mantissa or unit vector) Binary example: 4356347>>9=8508 (.490234375) 4356347<<9=too big for a longword, if signed numbers are used (9 is exponent in the form of an ASR or ASL, becoming -9 or 9, respectively) (4356347 is the mantissa or unit vector, fitting in how many bits are left after you decide how many bits to reserve for the exponent) You simply decide on a binary representation of a floating-point number in whatever word size is efficient. You could go with 64-bit where 1 longword is the exponent and the other the mantissa (%01111111 11111111 11111111 11111111 is the highest possible positive number corresponding to 0.9999999999999999999...) Or you could go 32-bit, something like %seeeeee Smmmmmmm mmmmmmmm mmmmmmmm where you have a signed exponent and a Signed mantissa and separate them into two registers before each computation. You will get overflow or NAN (not a number) when the result of a computation doesn't fit in the format you chose. To solve that, you normalize the results and keep factors separate, or factorize before computing. For high-precision calculations that are simple, you can usually modify the calculations instead, to just make sure it doesn't become a problem. For both of these, you need 32-bit multiply and divide at least, if you want to support all 680x0 processors you need to write functions for that. My favorite is a 5-bit word for exponent and a word for mantissa; this makes writing the macros trivial. You only have "4.5 decimals" but usually it's possible to combine calculations to keep things in range so this doesn't affect the (rounded) result. To round a number you add half the value of its highest unsigned bit before shifting down, or shift 1 less, addq #1, then asr #1. |
17 July 2011, 20:28 | #7 |
Posts: n/a
|
Fixed point is what you want, most of the time.
Earlier this year I tinkered around with a raytracer that ran on the GBA. I wrote it in C++: The whole thing was templatized, and I could use float and double as the basic data type or substitute my own fixed point data type which was a template too (two template args: the integer type to use and how many bits to use for the fractional part). |
05 February 2015, 16:50 | #8 |
Registered User
Join Date: Aug 2008
Location: Salisbury
Posts: 773
|
Hey guys, thought I'd drag this thread up rather than starting another one.
I'm thinking of using a longword as fixed point, top half int, bottom half decimals. I'm doing a division calculation which gives me the int part and then a remainder in the top half. How do I recalculate the remainder into the required decimal value? |
05 February 2015, 17:34 | #9 |
Total Chaos forever!
Join Date: Aug 2007
Location: Waterville, MN, USA
Age: 49
Posts: 2,200
|
There is an implementation in c99 at https://code.google.com/p/libfixmath/ or use the 64 by 32 bit division routines on an 020+ or use Utility.library on Kickstart 2+ to get the same results.
|
05 February 2015, 17:42 | #10 |
Registered User
Join Date: Aug 2008
Location: Salisbury
Posts: 773
|
Needs to be 68000 only sadly, also calling out to a library is going to greatly impede the speed of the code.
I'm using this to mix multiple sounds together, so the calculations are done thousands of times, one cycle per resulting sample. I'm just trying to shave some time off it at the moment. |
06 February 2015, 15:25 | #11 |
Registered User
Join Date: Aug 2008
Location: Salisbury
Posts: 773
|
Got it working now, thought I'd post the code in case anyone wants to see it.
Code:
.loop moveq #0,d0 moveq #0,d1 moveq #0,d2 move.w osc_baseperiod,d1 ; base period move.w osc_period(a0),d2 ; get this per divs d2,d1 ; divide the periods swap d1 ; swap the remainder to lower tst.w d1 ; test is remainder exists beq.b .norem ; no then no point doing the rest.. move.w d1,d0 ; copy remainder to safe reg muls #$1000,d0 ; multiply remainder by 4096 divs d2,d0 ; divide it by original asl.w #4,d0 ; shift fraction result up move.w d0,d1 ; copy fraction to our delta result .norem move.l d1,osc_posdelta(a0) ; delta result Last edited by h0ffman; 06 February 2015 at 15:41. Reason: better comments |
06 February 2015, 23:22 | #12 |
Banned
Join Date: Dec 2014
Location: Montreal
Posts: 129
|
If you are short on time I would recommend using a 16 bit fraction, this allows you to just do a swap to obtain the integer value after rounding which I seem to recall is faster than a 4 bit shift.
|
07 February 2015, 17:37 | #13 |
Glastonbridge Software
Join Date: Jan 2012
Location: Edinburgh/Scotland
Posts: 2,243
|
it is certainly faster than a multiply, indeed why multiply by 4096? this way you end up with bottom 4 bits zero, you've lost 4 bits of precision already.
you will need to account for the sign of the remainder (if the dividend might be negative. the sign of the remainder is the same as the sign of the dividend) |
18 March 2015, 23:11 | #14 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,690
|
Didn't think of moving this to the Assembler forum when I replied. Bad me. Now corrected
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
What's the point? | Mounty | project.WHDLoad | 7 | 24 January 2013 23:18 |
Any point upgrading to WB 3.9? | nixxjsteve | support.Apps | 3 | 10 January 2011 14:12 |
Found -> Galactic (Was: Looks like Woody's World but with floating king(s) ) | killergorilla | Looking for a game name ? | 12 | 24 March 2006 15:51 |
Floating menus? | Mojo2000 | New to Emulation or Amiga scene | 6 | 30 January 2003 14:35 |
Is there any point????? | backtoskooldaze | support.Hardware | 1 | 06 April 2002 06:27 |
|
|