Post Reply
Posts: 10
Joined: Fri May 09, 2008 1:16 am


Post by Legolas » Mon Jun 25, 2012 7:08 pm

Consider this code:

Code: Select all

#include <nds.h>

#include <stdio.h>

volatile float incr = 0.0f;
volatile float decr = 0.0f;
volatile float value = 8.0f;
void Vblank() {
	incr += 0.1f;
	decr -= 0.1f;
int main(void) {
	irqSet(IRQ_VBLANK, Vblank);

	while(1) {
		printf("\x1b[6;0HIncr = %f",incr);
		iprintf("\x1b[7;0HIncr = %08X",floattov16(incr));  
		printf("\x1b[10;0HDecr = %f",decr);
		iprintf("\x1b[11;0HDecr = %08X",floattov16(decr));
		iprintf("\x1b[13;0HAbsolute = %08X",floattov16(8.0f));
		iprintf("\x1b[14;0Hvalue = %08X",floattov16(value));

	return 0;
floattov16 converts incr and decr saturating the results, but value and 8.0f are converted as 0x00007FFF. I'm a little bit confused, is this the expected behavior?

Posts: 30
Joined: Fri Dec 17, 2010 1:34 pm
Location: Either side of South Bypass, Madrid, Spain

Re: floattov16

Post by eradsoft » Tue Jun 26, 2012 7:21 am

Yes, that behaviour is correct.
v16 is one of the vertex coordinate formats used to provide vertices
to the DS 3D hardware.
For example glVertex3v16() function in videoGL.h uses it.
It is a 16 bit fixed point format where 4 bits are used for the integer part
and 12 bits for the fractional part. Negative vertex coordinates are
represented in two's complement.
This way:
1 is represented by 0001.0000 0000 0000
2 is represented by 0010.0000 0000 0000
3 is represented by 0011.0000 0000 0000
4 is represented by 0100.0000 0000 0000 etc..
-1 is represented by 1111.0000 0000 0000
-2 is represented by 1110.0000 0000 0000
-3 is represented by 1101.0000 0000 0000
-4 is represented by 1100.0000 0000 0000 etc...

You can distinguish the negative from the positive
numbers in two's complement by looking at the most
significant bit (MSB) of the representation:
-A 0 in the MSB means positive number
-A 1 in the MSB means negative number

Non integer coordinates use the negative powers of 2
from the point, for example
0.5 is represented by 0000.1000 0000 0000
0.25 is represented by 0000.0100 0000 0000
however your testing 0.1 increment is not exact:
0.1 is represented by 0000.0001 1001 1001
which is not exact
(0.1 has a periodic fractional part in binary)

The problem relays in the maximum and minimum
values you can represent:
Maximum 0111.1111 1111 1111 which is less than 8.0,
aproximately 7,99975586
Minimum 1000.0000 0000 0000 which is exactly -8.0,
this not what your programs prints probably because
there is a rounding problem since 0.1 in binary is
not exact.

So if you are representing a 3D model in the DS you
need to stick to this range, probably scaling down the
whole model coordinates.

There is also another coordinate vertex format, V10.
This format uses 4 bits for integer part and 6 for
fractional part. This way the x,y and z coordinates
of a vertex can be held in a 32 bit word.
This one is used for writing in GFX_VERTEX10 port
of the 3D hardware

Hope this helps
Welcome, my son, to the machine.
Pink Floyd.

Posts: 10
Joined: Fri May 09, 2008 1:16 am

Re: floattov16

Post by Legolas » Tue Jun 26, 2012 5:50 pm

Ok, that makes sense, thank you :)
But I can't understand why same values are converted in different manners:

Code: Select all

float value = 10.0f; -> floattov16(value) returns 0xFFFFA000
#define value 10.0f -> floattov16(value) returns 0x00007FFF

Posts: 355
Joined: Thu Jul 02, 2009 1:19 pm

Re: floattov16

Post by elhobbs » Tue Jun 26, 2012 6:25 pm

10.0f is outside of the valid range for a v16 value, so I am not sure what you are expecting. I suspect it has something to do with the type you are returning the results to combined with how the preprocessor/compiler is optimizing away the defines to a static value in the second case.

Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests