Outsourcing saves money => Issues Help Desk => Topic started by: BPzeBanshee on January 23, 2015, 10:00:33 am

Title: "Precision" of floating points close to 0
Post by: BPzeBanshee on January 23, 2015, 10:00:33 am
I isolated one of three remaining compatibility issues with Warbird and it seems I'm treading old ground. I note this GitHub report here (https://github.com/enigma-dev/enigma-dev/issues/584) from a few years ago where it was described as a non-issue but in the interests of GM compatibility I'm inclined to disagree. Note my test build here: https://www.dropbox.com/s/516eqyqi4qq7o1s/Test8.gmk?dl=0

Basically, as you decrement in increments of 0.1 when you go from 0.1 to 0 the variable you're subtracting becomes some twisted number other than 0, which if you're using for if statements leads to different things happening based on what video renderer you're using. Under OpenGL it spits some weird scientific notation and stops, but in DX9 it becomes a truncated value and continues decrementing resulting in going past 0 entirely and into negative value territory. Of course in GM it hits 0.

I'm concerned that this particular behaviour is different for the OpenGL renderers vs the DirectX9 renderer, the latter which I understood was supposed to be closer to GM's behaviour as it too used DX9, and is causing noticable differences in my GM projects vs in GM itself. For a "non-problem" GM is handling things very differently from ENIGMA here and I think it'd be worthwhile to have some kind of precision toggle in the Compatibility/Progress sector.
Title: Re: "Precision" of floating points close to 0
Post by: TheExDeus on January 23, 2015, 06:21:55 pm
I don't see why there would be differences between GL and DX other than the visual representation (even that should be the same though). Both systems use the same type (double) for direction and speed in the instance system (as the instance system is actually not connected to the graphics system). But floating point types cannot actually represent very small numbers. That is why you should never do hspeed == 0, but instead hspeed <= 0.00012 or something similar. That is true in every programming language. GM just seems to round some of its internal variables, like direction and speed.

I checked and we have direction as double, but only allow it to have integer values. So the calculation that sets direction from vspeed is this:
Code: [Select]
*dir = int(180.0+180.0*(1.0-atan2(rval.d,*hspd)/M_PI))%360;
*spd = hypot(rval.d,*hspd);
Where rval.d is the set vspeed and hspd is the hspeed. This basically means that we evaluate "180.0+180.0*(1.0-atan2(5,0)/M_PI)" to something very close to 270, but not quite (269.9999999) and when we cast to int it truncates the decimal part, so we get left with 269.0. What I can do is just add a rounding there. This will fix this issue.

Also, you should probably use either GL1 or GL3, as DX systems are not as thoroughly tested and developed.
I'm not sure I will try to fix the speed not equaling zero, as that shouldn't be an issue even in compatibility with GM. You just should check ranges, not total equality.

Will have to investigate that weird DX bug, where it actually goes into reverse. Doesn't make much sense in my mind right now.

edit: Direction is rounded in this branch: https://github.com/enigma-dev/enigma-dev/pull/929 and in this commit: https://github.com/enigma-dev/enigma-dev/commit/0e358861fba53e7b6898df3696e94fc4fb2a3948

At some point it will be merged into master.

edit2: I honestly cannot tell why in DX mode the precision is different then in GL. Maybe some compiler options are changed which causes this. In GL is goes to E-12, while in DX only to E-06. So in GL the vspeed == 0 holds true, while in DX it does not, so the speed is decremented more. The proper fix for this is to actually test vspeed < 0.001 or we could just provide a special function for that (we do use one internally) or an epsilon value (precision) that can be checked against. So you could write vspeed < double_epsilon or something. Either way, I don't know if we want this for GM compatibility. As hspeed and vspeed are special variables, we can internally maybe do these checks and set them to 0. But I don't think we will do this for custom variables. So if you decrement your own variable, then you should check it yourself.
Title: Re: "Precision" of floating points close to 0
Post by: BPzeBanshee on January 27, 2015, 04:10:30 am
Seems you're right about GM rounding values all around. Did a bit of research and found GM:Studio has a math_set_epsilon function that allows for a system-wide version of what you describe and the latest update allows for the internal rounding to be switched off. IIRC GM 8.0 did not have this and just rounded from the 3rd place value for functions like vspeed.

Perhaps math_set_epsilon can be implemented and the folks with the fetish for having 0.05 - 0.05 = 1-0e2754whatsit or 0.0000000000000000000000000001 as normal behaviour can still do so using math_set_epsilon(0)?