tips from a demo coder

General discussion for topics related to the FreeBASIC project or its community.
dafhi
Posts: 1645
Joined: Jun 04, 2005 9:51

tips from a demo coder

Post by dafhi »

this guy gives an interesting talk
https://www.youtube.com/watch?v=h4MS5zU_C0c
Last edited by dafhi on Dec 27, 2017 6:38, edited 2 times in total.
Imortis
Moderator
Posts: 1925
Joined: Jun 02, 2005 15:10
Location: USA
Contact:

Re: tips from a java demo coder

Post by Imortis »

He is not talking about java, but javascript. As for the stuff about floating point, which part are you talking about specifically?
dafhi
Posts: 1645
Joined: Jun 04, 2005 9:51

Re: tips from a demo coder

Post by dafhi »

4:10
Imortis
Moderator
Posts: 1925
Joined: Jun 02, 2005 15:10
Location: USA
Contact:

Re: tips from a demo coder

Post by Imortis »

Oh, yeah. I was not sure if you were talking about that or the pi approximations. That is very true. There are certain values that are impossible to store accurately as a floating point number because they will always be off by one digit at the end of the precision. It is because of the IEEE standard for encoding decimals that basically everything uses.

There are some numbers (can't remember which right now) that you can run this code and it will fail:

Code: Select all

Dim as single x = 10, y = 10
if x = y then
     Print "Equal"
end if
I don't think 10 is one of those numbers, but there are several. I will look it up later and give a real working example.

As a side not, the point of the pi approximations is to reduce the size of the javascript code. I don't THINK that would translate to smaller exe in a compiled language, but I have not tested. My gut says there would be no notable difference.
sancho3
Posts: 358
Joined: Sep 30, 2017 3:22

Re: tips from a demo coder

Post by sancho3 »

Code: Select all

Dim as single x = .1, y = .1 * .1 * .1
if x * x * x = y then
     Print "Equal"
else 
	print "not equal: ";x * x * x, y
	?
	? .1 * .1 * .1, x * x * x, x * x * .1
end if
Imortis
Moderator
Posts: 1925
Joined: Jun 02, 2005 15:10
Location: USA
Contact:

Re: tips from a demo coder

Post by Imortis »

sancho3 wrote:

Code: Select all

Dim as single x = .1, y = .1 * .1 * .1
if x * x * x = y then
     Print "Equal"
else 
	print "not equal: ";x * x * x, y
	?
	? .1 * .1 * .1, x * x * x, x * x * .1
end if
Yes, exactly.
TeeEmCee
Posts: 375
Joined: Jul 22, 2006 0:54
Location: Auckland

Re: tips from a demo coder

Post by TeeEmCee »

If you're comparing two floating point numbers for equality, you probably have a bug in your code.

...I had to fix such a bug in my own code just last night :/
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: tips from a demo coder

Post by caseih »

Imortis wrote:I don't think 10 is one of those numbers, but there are several. I will look it up later and give a real working example.
Only combinations of 1/2, 1/4, 1/8, 1/16, etc can be represented precisely with binary, up to the limit of the significant digits in the IEEE format you are using. Many common decimal fractions end up being infinitely-repeating sequences in binary. For example, if my binary division skills are working:
0.1 = 0.000110011001
0.2 = 0.00110011001
0.3 = 0.010011001
0.4 = 0.0110011001
But others are exact:
0.5 = 0.1
paul doe
Moderator
Posts: 1735
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: tips from a demo coder

Post by paul doe »

Yeah, comparing two floating point numbers for equality is tricky (if not even incorrect). Typical workaround:

Code: Select all

function cmpf( byref a as single, byref b as single, byval epsilon as single = 0.00000001 ) as boolean
	return( abs( a - b ) < epsilon )
end function

dim as single x = .1, y = .1 * .1 * .1

if( cmpf( x * x * x, y ) = true ) then
	? "Equal"
else
	? "not equal: "; x * x * x, y
	?
	? .1 * .1 * .1, x * x * x, x * x * .1
end if

? .1 * .1 * .1, x * x * x, x * x * .1

sleep()
dafhi
Posts: 1645
Joined: Jun 04, 2005 9:51

Re: tips from a demo coder

Post by dafhi »

caseih wrote: Only combinations of 1/2, 1/4, 1/8, 1/16, etc can be represented precisely with binary, up to the limit of the significant digits in the IEEE format you are using. Many common decimal fractions end up being infinitely-repeating sequences in binary. For example, if my binary division skills are working:
0.1 = 0.000110011001
0.2 = 0.00110011001
0.3 = 0.010011001
0.4 = 0.0110011001
But others are exact:
0.5 = 0.1
there's one more layer of magic peeled away from my perception of fpu logic :-)
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: tips from a demo coder

Post by caseih »

dafhi wrote:there's one more layer of magic peeled away from my perception of fpu logic :-)
Remember expanded notation for numbers?
142.342 = 1*10^2 + 4*10 +2 + 3*10^-1 + 4*10^-2 + 2*10^-3.
Binary works the same way:
142.342 = 10001110.0101011110001101... = 1*2^7 + 1*2^3 + 1*2^2 + 1*2^1 + 1*2^-2 + 1*2^-4 etc
Same for all bases. In IEEE floating point, basically all numbers are stored in a form like this:
sign*0.xxxxxxxxx * 2^exponent where xxxxxx is the binary rational. The leading zero is assumed and not stored.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: tips from a demo coder

Post by jj2007 »

paul doe wrote:Yeah, comparing two floating point numbers for equality is tricky (if not even incorrect).
It can be done if you specify a degree of precision, a tolerable delta, whatever. But I agree it's tricky - we had over a dozen threads in the Masm32 forum, for example: FPU compare real to integer problem
paul doe
Moderator
Posts: 1735
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: tips from a demo coder

Post by paul doe »

jj2007 wrote:It can be done if you specify a degree of precision, a tolerable delta, whatever.
Of course, that's what the 'epsilon' parameter of the code above is for. Over the years, as compilers improved and I got fed up, I slowly ported all of my ASM to HLL. This, for example, was a function I used a lot:

Code: Select all

function fmod( byval lhs as single, byval rhs as single ) as single
	' Computes the floating point remainder ( modulus division ) of two floating point numbers
	asm
		fld			dword ptr [ rhs ]				' Load dividend
		fld			dword ptr [ lhs ]				' Load modulus
		
		fprem														' Performs the float division and load the remainder in st( 0 )
		
		fstp		dword ptr [ function ]	' Loads the content of st( 0 ) into function result
		
		' Set the flags of the floating point registers to empty
		ffree		st( 0 )
		ffree		st( 1 )
		
		' Pops the stack
		fincstp
		fincstp
	end asm
end function
Which, when I moved to GCC, got replaced with:

Code: Select all

'' portable floating-point mod function
#ifndef fmod
	#define fmod( numer, denom )	numer - int( numer / denom ) * denom
#endif
with no noticeable speed loss. Back in the day, we were all doing tricks with fixed point math. The licks one needs to learn with floating point nowadays (if you're coding shaders, for example) are different, but quite interesting, indeed =D
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: tips from a demo coder

Post by caseih »

I'm not sure if there are standard, portable values for epsilon. But I've read some things that recommend these values:
single precision: 1E-5
double precision: 1E-9
long double precision: 1E-9
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: tips from a demo coder

Post by jj2007 »

paul doe wrote:Of course, that's what the 'epsilon' parameter of the code above is for.
Looks a bit too fixed and hand-crafted for my taste. Fcmp, for example, does it automatically for large ranges, and you can tell it do it with lo, medium, hi or top precision. Note the figures are 60 orders of magnitude apart and differ only in the last digit:

Code: Select all

  SetGlobals REAL10 MyPI=3.141592653589793238, hiPI=3.141592653589793239, loPI=3.141592653589793237
  SetGlobals REAL10 MyPI30=3.141592653589793238e30, hiPI30=3.141592653589793239e30, loPI30=3.141592653589793237e30
  SetGlobals REAL10 MyPIm30=3.141592653589793238e-30, hiPIm30=3.141592653589793239e-30, loPIm30=3.141592653589793237e-30
Post Reply