View Full Version : Fixed point math

Legolas

31-05-2007, 12:11 PM

System: Windows XP sp2

Compiler: arm-nds-fpc 2.1.4. i386-win32

API: none

I need to do some conversion from floating point values to 1.19.12 fixed point. The code I have found in C is:

#define floattof32(n) ((int32)((n) * (1 << 12)))

that I have tried to convert in this way:

function floattof32(n: cfloat): cint32; inline;

begin

floattof32 := (cint32(n) * (1 shl 12));

end;

but does not work as I expected. Can anyone help me here?

Robert Kosek

31-05-2007, 12:58 PM

Heh, I had a whole reply typed up when I noticed something. Look at the C macro again for a second. The typecast is on the result of the shift and multiplication, and not the number before the multiplication. So your function should be:function floattof32(n: cfloat): cint32; inline;

begin

floattof32 := cint32((n) * (1 shl 12));

end;

Legolas

31-05-2007, 01:10 PM

Uh-oh... You are right... :oops:

However it does not work too

Robert Kosek

31-05-2007, 01:32 PM

Don't worry, I shot myself in the foot with a sizable if-then-else block the other day (just about driving myself nuts in the process). What exactly are you trying to do? I don't understand the multiplication in there. If you wanted to store the whole 32bit number as an integer you would call move() and shift the value over.

Legolas

31-05-2007, 01:45 PM

I need to store the floating point value in a 32 bit integer, where the 1st bit is the sign, bits from 2 to 20 are holding the integer part and 21 to 32 the fraction part. It's for 3d on Nintendo DS, because this particular format number is used to handle matrix transformations via hardware.

Robert Kosek

31-05-2007, 01:47 PM

Ouch. I really don't know how to help you then. Maybe someone else can who has a better knowledge of those things.

savage

31-05-2007, 01:54 PM

Do you have an example of type of input and expected output?

Legolas

31-05-2007, 02:09 PM

Do you have an example of type of input and expected output?

Thanks, mates. At this time I'm at work. As soon as I'll come back home I'll make it :)

savage

31-05-2007, 02:10 PM

btw, in Delphi 6 the previous code you posted does not compile as I get an invalid typecast error.

The following code appears to convert between the floats and Ints ( to a few decimal places ), but I'm not sure if it is what you are looking for...

function FloatToInt32(n: single): integer;

begin

result := Round((n) * (1 shl 12));

end;

function Int32ToFloat(n: integer): single;

begin

result := ( (n) / (1 shl 12) );

end;

procedure TForm1.Button1Click(Sender: TObject);

begin

ShowMessage( FloatToStr( Int32ToFloat( FloatToInt32( 1.1 ) ) ) );

end;

Legolas

31-05-2007, 07:16 PM

I have tried every possible combination of trunc/round/shl/shr, but the obvious one:

function floattof32(n: cfloat): cint32; inline;

begin

floattof32 := trunc((n) * (1 shl 12));

end;

This one seems working as expected, though I have learned "never think that something works, even when it seems working". Thanks again, guys! And stay tuned, because I'm making some other strange type conversion routines :lol:

savage

31-05-2007, 07:26 PM

When I used trunc it gave me slight incorrect values converting back, but maybe that's ok for you.

Legolas

31-05-2007, 07:42 PM

Comparing C and Pascal results, all seems ok. I have preferred to use trunc because AFAIK it should be faster than round, at least on delphi/win32. On fpc/arm it should be faster too, I suppose :think:

pziko

31-05-2007, 11:39 PM

I think Round will be much faster (twice?) than Trunc because Trunc has to reset the FPU. Try each a couple of million times in a loop and see.

Mirage

01-06-2007, 05:54 AM

Round() much faster.

I also thought that Trunc() faster then Round() and now have to change a lot of code.:(

michalis

01-06-2007, 06:22 AM

Calling Trunc is doing exactly what the C code does. In C, typecasting float to integer causes automatic truncing (rounding to nearest integer towards zero, this is exactly what the Trunc in Pascal does).

BTW, what speed differences do you guys get with Delphi/win32 between Round and Trunc ?

I tested with FPC 2.0.4, Linux, i386, and got

Test Single:

Trunc time: 4.35

Round time: 3.37

Test Double:

Trunc time: 4.58

Round time: 3.37

Test Extended:

Trunc time: 5.82

Round time: 5.08

which means that Round is indeed faster, but not terribly (and it matters only if you really do an awful lot of these calls, so it does not necessarily matter).

Legolas

01-06-2007, 06:48 AM

I think Round will be much faster (twice?) than Trunc because Trunc has to reset the FPU. Try each a couple of million times in a loop and see.

Uhm... I'm working on ARM cpu, where the FPU is not present. I'm wondering about the speed in this case :think:

These might do a fair chunk of what you need. I've been playing around recently with fixed point math in C using templated classes. It is easier when the precision is the same for both fixed point numbers, but there are calculations for when both fixed point numbers have different precisions and you want the result in a third precision.

Edit: The FixedToInt function went missing, and the IntToFixed function had a typo.

type

Fixed = Integer;

const

Prec = 12;

function IntToFixed(Value: Integer): Fixed;

begin

IntToFixed := Value shl Prec;

end;

function FixedToInt(Value: Fixed): Integer;

begin

FixedToInt := Value shr Prec;

end;

function FloatToFixed(Value: Single): Fixed;

begin

FloatToFixed := Round(Value * (1 shl Prec));

end;

function FixedToFloat(Value: Fixed): Single;

begin

{ Multiply by 1.0 to convert to floating point before the divide }

FixedToFloat := (Value * 1.0) / ((1 shl Prec) * 1.0);

end;

function FixedAdd(A, B: Fixed): Fixed;

begin

FixedAdd := A + B;

end;

function FixedSub(A, B: Fixed): Fixed;

begin

FixedSub := A - B;

end;

function FixedMul(A, B: Fixed): Fixed;

begin

FixedMul := (A * B) shr Prec;

end;

function FixedDiv(A, B: Fixed): Fixed;

begin

FixedDiv := (A shl Prec) / B;

end;

Mirage

02-06-2007, 11:14 AM

Uhm... I'm working on ARM cpu, where the FPU is not present. I'm wondering about the speed in this case :think:

In that case Trunc() may be faster. It needs testing.

Legolas

02-06-2007, 11:33 AM

Sly: thanks a lot! That's gold for me :)

I hope they help. They were coded in my head as I haven't actually done fixed-point in Pascal before (only done it in C). So I hope they work.

Powered by vBulletin® Version 4.2.5 Copyright © 2020 vBulletin Solutions Inc. All rights reserved.