Fixed point math benchmark

General FreeBASIC programming questions.
Post Reply
xlucas
Posts: 334
Joined: May 09, 2014 21:19
Location: Argentina

Fixed point math benchmark

Post by xlucas »

For a routine that I needed to go superfast and didn't require high precision, I was thinking of adding an extra boost through the old practice of switching to fixed point math. To my surprise, my test benchmarks are telling me this isn't a good idea. Even integers (without the extra multiplication/shifting) seem to work slightly slower than doubles. How come?

Code: Select all

Dim t As Double, n As LongInt
Dim As Double d1 = 299991, d2 = 299990, d3 = 1
Dim As LongInt i1 = 299991, i2 = 299990, i3 = 1

Print "Integers:"
t = Timer
Do
	i3 *= i1
	i3 /= i2
	n += 1
Loop Until Timer >= t + 1
Print n, i3
GetKey

Print "Doubles:"
t = Timer
Do
	d3 *= d1
	d3 /= d2
	n += 1
Loop Until Timer >= t + 1
Print n, d3
GetKey
On my computer, the code yields about 11 million iterations for integers and somewhat over 23 million iterations for doubles. What am I doing wrong? Or do current CPUs really perform better with floating point than with integers? :o
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Fixed point math benchmark

Post by dodicat »

You use longint.
change to long -optional
you are not resetting n
you cannot rely on the first run only.
Loop a while and see.

Code: Select all

Dim t As Double, n As Long
Dim As Double d1 = 299991, d2 = 299990, d3 = 1
Dim As Long i1 = 299991, i2 = 299990, i3 = 1

do

  i1 = 299991: i2 = 299990: i3 = 1  
Print "Integers:"
t = Timer
Do
   i3 *= i1
   i3 /= i2
   n += 1
Loop Until Timer >= t + 1
Print n, i3
'GetKey
d1 = 299991: d2 = 299990: d3 = 1

n=0

sleep 100
Print "Doubles:"
t = Timer
Do
   d3 *= d1
   d3 /= d2
   n += 1
Loop Until Timer >= t + 1
Print n, d3
print
sleep 200

'GetKey
loop until len(inkey) 
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: Fixed point math benchmark

Post by D.J.Peters »

you measured the timer() call too
note: integer div is "\" not "/"

By the way here are fast fixed point math including vector and matrix math.
(fadd, fmul, fmul, fdiv, fsin, fcos, fsqr, fsrqd, ftan ...)
viewtopic.php?f=7&t=22838

Joshy

32-bit data types on 64-bit OS
ints 1.225493478923397
real 16.572667466356

64-bit data types on 64-bit OS
Integers ...
Real ...
ints 2.146352917887271
real 1.429170743445866

Code: Select all

#ifndef __FB_64BIT__
type real as single
type ints as long
#else
type real as double
type ints as longint
#endif

Dim As real d1 = 299991, d2 = 299990, d3 = 1
Dim As ints i1 = 299991, i2 = 299990, i3 = 1
const N = 1000 * 1000 * 100

var tStart = Timer()

Print "Integers ..."
tStart = Timer()
for i as integer = 1 to n
   i3 *= i1
   i3 \= i2
next
var tInts=Timer()-tStart   

Print "Real ..."
tStart = Timer()
for i as integer = 1 to n
   d3 *= d1
   d3 /= d2
next
var tReal=Timer()-tStart   
print "ints " & tInts
print "real " & tReal
sleep

Last edited by D.J.Peters on Oct 22, 2017 0:24, edited 2 times in total.
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Fixed point math benchmark

Post by paul doe »

Hola cumpis
xlucas wrote:On my computer, the code yields about 11 million iterations for integers and somewhat over 23 million iterations for doubles. What am I doing wrong? Or do current CPUs really perform better with floating point than with integers? :o
You may also want to check out this:
https://dsp.stackexchange.com/questions ... omputation

Hope it helps.
Paul
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Fixed point math benchmark

Post by jj2007 »

If speed is really important, consider switching to packed singles. That is a factor 4 gain, but it requires a bit of SIMD skills.
xlucas
Posts: 334
Joined: May 09, 2014 21:19
Location: Argentina

Re: Fixed point math benchmark

Post by xlucas »

Oh! How could I be so stupid! Not resetting n is the main reason why this gives such weird values!

Dodicat: Thanks. I'm really surprised. I knew it was much better to perform the test several times, but I didn't expect it to give such a huge difference. Why would it be so slow the first time in comparison to the others?

Joshy: Wow! Fixed point with all the functions! Well, if I do this with fixed point, it's not a whole program using it. It'd be just one routine that would make its calculations with fixed point. It'd be a few multiplications and a couple of divisions, it's just it'd be called many, many times. So instead of building functions, I'd probably just enter the fixed point math inline. So from your numbers, I understand that switching to fixed point is only worth it if I am to use the same word width as my compiled code? (I imagine that a 32bit ELF running under a 64bit GNU would still run fast because it'd be running in a 32bit code memory region, but if I will use Longs, I have to compile in 32bit and if I will use LongInts, I have to compile in 64bit or just use Integers, right?)

Paul Doe: ¡Gracias! Yep, that's more or less what I was starting to think. On today's computers, it looks like fixed point math may be worth it, but you have to take lots of precautions. Just using fixed point instead of floating point at any random place in the program will likely make it slower. I'll take a benchmark for Singles vs Doubles.

jj2007: As a matter of fact, I may later on translate that single routine to assembly and call it from my program, but as you say, I would have to be very skilled to use packed singles. I'm going to first try the routine with doubles and see how slow it really is, then I'll try optimising it with singles, some fixed point, etc. If I see it is worth it, I'll translate it to assembly and I'll study packed floats to see if I can get that working. I don't want to complicate my code more than necessary, but if it looks like it'll be necessary, I will.
grindstone
Posts: 862
Joined: May 05, 2015 5:35
Location: Germany

Re: Fixed point math benchmark

Post by grindstone »

xlucas wrote:Why would it be so slow the first time in comparison to the others?
Maybe because some values become cached at the first run?
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Fixed point math benchmark

Post by dodicat »

I did a little test.
I made a C library file function multiplying two floats (singles), 4 lines of C
I compared with a freebasic function.
looping 1 to 50000000 and accumulating a float
(f+=mult(1.8876,-1.00097)


result:

Code: Select all

Time  0.2511555792298168    Pure C   result      -3.355443e+007
Time  0.3508026434574276    pure FB  result      -3.355443e+007

Time  0.4116691944655031    Pure C   result      -3.355443e+007
Time  0.3614287024829537    pure FB  result      -3.355443e+007

Time  0.2476997915655375    Pure C   result      -3.355443e+007
Time  0.3490622595418245    pure FB  result      -3.355443e+007

Time  0.2498644923325628    Pure C   result      -3.355443e+007
Time  0.3631800361908972    pure FB  result      -3.355443e+007

Time  0.2480419827625155    Pure C   result      -3.355443e+007
Time  0.362808759091422     pure FB  result      -3.355443e+007

Time  0.2481223978102207    Pure C   result      -3.355443e+007
Time  0.3702811852563173    pure FB  result      -3.355443e+007

Time  0.2500718601513654    Pure C   result      -3.355443e+007
Time  0.3465009594801813    pure FB  result      -3.355443e+007

Time  0.2493067209143192    Pure C   result      -3.355443e+007
Time  0.3533146679401398    pure FB  result      -3.355443e+007

  
The freebasic was 32 bit -gen gcc.
-gen gas is a little faster.

If I optimize the -gen gcc -W3 -O2 then it is faster but the result is incorrect.
Conclusion from these few code lines -- C is faster at multiplying floats than FreeBASIC.
xlucas
Posts: 334
Joined: May 09, 2014 21:19
Location: Argentina

Re: Fixed point math benchmark

Post by xlucas »

(Written before your last post, Dodicat, but relevant)

Ha, ha, ha... no! I just found out why:

Simply because Dodicat made the same mistake I made. He fixed mine and reset n to 0 after the first loop, but forgot to do the same after the second. Dodicat: after fixing that, it looks like there virtually is no difference between integers and floating point. It doesn't seem to matter if it's single or double or whether it's long or longint. My guess is the reason is that the check for Timer is so much slower than the multiplication and division that the latter go unnoticed.

Now we're talking...

Code: Select all

Dim t As Double, n As Long
Dim As Double d1 = 299991, d2 = 299990, d3 = 1
Dim As Long i1 = 299991, i2 = 299990, i3 = 1
Dim k As Long

do

  i1 = 299991: i2 = 299990: i3 = 1 
Print "Integers:"
t = Timer
Do
   For k = 1 To 1000
	   i3 *= i1
	   i3 /= i2
	   n += 1
   Next k
Loop Until Timer >= t + 1
Print n, i3
'GetKey
d1 = 299991: d2 = 299990: d3 = 1

n=0

sleep 100
Print "Doubles:"
t = Timer
Do
	For k = 1 To 1000
	   d3 *= d1
	   d3 /= d2
	   n += 1
	Next k
Loop Until Timer >= t + 1
Print n, d3
print
sleep 200

n=0

'GetKey
loop until len(inkey) 
Still, the difference is not immense
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Fixed point math benchmark

Post by dodicat »

Oops!
sorry n

If you use addition or multiplication then integers are faster.
But the division (/) slows down integers.
Maybe as suggested use (\) for integers.
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Fixed point math benchmark

Post by dodicat »

Try without timer swamping and using integer division for integers.

Code: Select all

Dim t As Double, n As Long
Dim As Double d1 = 299991, d2 = 299990, d3 = 1
Dim As Long i1 = 299991, i2 = 299990, i3 = 1
Dim k As Long

do

  i1 = 299991: i2 = 299990: i3 = 1 
Print "Integers:"
t = Timer

   For k = 1 To 100000000
      i3 *= i1
      i3 \= i2
      n += 1
   Next k

Print  timer-t, i3,n
'GetKey
d1 = 299991: d2 = 299990: d3 = 1

n=0

sleep 100
Print "Doubles:"
t = Timer

   For k = 1 To 100000000
      d3 *= d1
      d3 /= d2
      n += 1
   Next k

Print timer-t, d3,n
print
sleep 200

n=0

'GetKey
loop until len(inkey)
sleep  
xlucas
Posts: 334
Joined: May 09, 2014 21:19
Location: Argentina

Re: Fixed point math benchmark

Post by xlucas »

Oh! I thought operator / was mapped to operator \ when the two operands were integers! But it makes sense it doesn't, since it has to return a floating point number anyway. So I'm getting that plain integers are 19% faster than doubles when multiplying and dividing.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Fixed point math benchmark

Post by jj2007 »

I've put a testbed in the Masm32 forum.

It seems that floats and doubles are about 30% faster than integers.

Note that FreeBasic uses the FPU to do the div:

Code: Select all

mov dword ptr [ebp-14], 1 
mov eax, [ebp-38]        
imul eax, [ebp-30]       
mov ebx, eax             
mov [ebp-38], ebx        
fild dword ptr [ebp-38]  
fild dword ptr [ebp-34]  
fxch st(1)               
fdivrp st(1), st         
fistp dword ptr [ebp-38]
Same in hand-written assembly:

Code: Select all

fild i3
fimul i1
fidiv i2
fistp i3
Shorter and faster. Note also that the accuracy of results is much lower with integer arithmetics.
Post Reply