Allow floating-point division by zero in ZScript

Moderator: GZDoom Developers

argv
Posts: 184
Joined: Tue Aug 30, 2016 4:47 pm

Allow floating-point division by zero in ZScript

Post by argv »

Maybe I'm crazy, but since ZScript can represent floating-point infinity, shouldn't floating-point division by zero result in that, instead of crashing?

For the second time now, I've had to special-case division by zero, where infinity would have been a perfectly correct result. That got me thinking about this. Again, feel free to ignore me if I'm crazy. :)
User avatar
Major Cooke
Posts: 8170
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

Re: Allow floating-point division by zero in ZScript

Post by Major Cooke »

ಠ_ಠ

Pardon my asking but, just what would you need infinity for?
argv
Posts: 184
Joined: Tue Aug 30, 2016 4:47 pm

Re: Allow floating-point division by zero in ZScript

Post by argv »

From Use To Pickup:

Code: Select all

		if (HighlightState == FADING_IN || HighlightState == FADING_OUT) {
			double time;
			if (HighlightState == FADING_IN)
				time = ps.Settings.FadeInTime.GetFloat();
			else
				time = ps.Settings.FadeOutTime.GetFloat();
			
			// Avoid division by zero.
			// Division by zero would actually yield correct results (positive infinity), but the engine crashes instead of passing such a value through, so we have to special-case it.
			if (time <= 0.)
				TweenChange = 1;
			else
				TweenChange = 1. / (time * TICRATE);
			
			if (HighlightState == FADING_OUT)
				TweenChange = -TweenChange;
		}
		
		if (TweenChange)
			Tween = clamp(Tween + TweenChange, 0., 1.);
It needs to compute how fast an animation is to run, in floating-point change per tic (TweenChange). For user-friendliness, however, the menu options represent the animation speed as total duration in seconds (ps.Settings.Fade{In,Out}Time). To get from the latter to the former, I compute 1/(time*TICRATE).

It's perfectly valid to set the durations to 0, to turn off the animation entirely. This would be represented by TweenChange ≥ 1. ∞ ≥ 1, so an infinite result would result in correct behavior (clamp(Tween + ∞, 0, 1) = 1), and wouldn't require the special case.
argv
Posts: 184
Joined: Tue Aug 30, 2016 4:47 pm

Re: Allow floating-point division by zero in ZScript

Post by argv »

The other time I ran into this problem, I needed to compute how long it would take an actor to reach a destination at a given speed (ignoring portals and such), like so:

Code: Select all

Actor a = …;
Vector3 destination = …;
let travelTime = (destination - a.Pos).Length() / a.Speed;
Again, division by zero resulting in infinity would be correct here: an object with zero velocity takes infinite time to reach its destination.

I didn't end up using that code, but it did strike me as interesting at the time. It was the first time I remember writing a potential division by zero on purpose—or I would have, if the engine allowed it.

Of course, this would still yield incorrect results if the distance to the destination is also zero. 0/0 usually results in NaN or infinity, but in this case the actor would reach its destination in zero time despite zero speed, since it's already there.
dpJudas
 
 
Posts: 3036
Joined: Sat May 28, 2016 1:01 pm

Re: Allow floating-point division by zero in ZScript

Post by dpJudas »

Division by zero should never result in infinity. The only correct value is NaN.

There are pros and cons for allowing division by zero. The pro is obviously that it doesn't crash. On the other hand, you're now allowing NaN values to get stored and the rest of the engine has to be able to handle that. It also gets significantly harder to figure out what went wrong when you suddenly see NaN values a million miles away from the code that caused it.

Why not just check for zero the places where that is an allowed value? If travelTime gets a NaN value you have to check for that anyway.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49056
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: Allow floating-point division by zero in ZScript

Post by Graf Zahl »

Considering how much trouble NaNs have been with the JSON serializer, let's better not think about this any further.
argv
Posts: 184
Joined: Tue Aug 30, 2016 4:47 pm

Re: Allow floating-point division by zero in ZScript

Post by argv »

dpJudas wrote:Division by zero should never result in infinity. The only correct value is NaN.
IEEE 754 disagrees with you on this point. And it makes sense to me: as the divisor approaches zero, the result approaches infinity, so it follows that a divisor of zero ought to result in infinity.
Graf Zahl wrote:Considering how much trouble NaNs have been with the JSON serializer, let's better not think about this any further.
Ok, fair enough.
dpJudas
 
 
Posts: 3036
Joined: Sat May 28, 2016 1:01 pm

Re: Allow floating-point division by zero in ZScript

Post by dpJudas »

argv wrote:IEEE 754 disagrees with you on this point. And it makes sense to me: as the divisor approaches zero, the result approaches infinity, so it follows that a divisor of zero ought to result in infinity.
Alright, I only tested the 0.0/0.0 case before writing that. Nevertheless, you can't apply that kind of logic you're doing here mathematically. If you read the link closely this is about trying to handle underflow situations in a more graceful way.

Remember that infinity in floating point doesn't mean mathematical infinity. It means the value overflowed for what can be represented with this number of bits.
Gez
 
 
Posts: 17833
Joined: Fri Jul 06, 2007 3:22 pm

Re: Allow floating-point division by zero in ZScript

Post by Gez »

argv wrote:And it makes sense to me: as the divisor approaches zero, the result approaches infinity, so it follows that a divisor of zero ought to result in infinity.
Nothing makes sense when division by zero is involved.

Keep in mind that division is the inverse operation of multiplication. That is to say, if you have X × Y = Z, then you also have Z ÷ Y = X. Based on that, if some random number, let's say 12, is divided by zero and gives you infinity, then that means that infinity multiplied by zero gives you 12. Do you see the problem?

Even better: X ÷ X = 1. This is true for every number. So what is X = 0? Shouldn't you get 0 ÷ 0 = 1? But wait, 0 ÷ X = 0; this also is true for any number. So 0 ÷ 0 = 0? But it's also equal to 1 and to infinity!

Therefore, if X ÷ 0 is legal, then 0 = 1 = infinity. Good luck getting the rest of your maths to still work after that.
User avatar
Gutawer
Posts: 469
Joined: Sat Apr 16, 2016 6:01 am
Preferred Pronouns: She/Her

Re: Allow floating-point division by zero in ZScript

Post by Gutawer »

argv wrote:And it makes sense to me: as the divisor approaches zero, the result approaches infinity, so it follows that a divisor of zero ought to result in infinity.
The result only approaches infinity as you take the limit in the positive numbers, taking the limit in the negative numbers gives a limit of -infinity, so this has to be undefined because it has (at least) two limits. As Gez points out, sometimes you can have more than two, like with 0/0 = x which, using algebra, can be turned into 0 = 0x, which is true for every number, so therefore x must be undefined here too but with an infinite number of results.
User avatar
AFADoomer
Posts: 1322
Joined: Tue Jul 15, 2003 4:18 pm
Contact:

Re: Allow floating-point division by zero in ZScript

Post by AFADoomer »

For brevity's sake, I usually end up putting in a "max([divisor that might end up as zero], [arbitrary small number]);" call in cases like this...

e.g.:

Code: Select all

TweenChange = 1. / (max(time, 0.0001) * TICRATE);
Not sure if that slows things down internally any more/less than using if statements to the same effect, but I haven't noticed any issues so far.

EDIT: Fixed incorrect example, in case someone else stumbles across this post. Thanks, Gez!
Last edited by AFADoomer on Sat Jul 28, 2018 5:08 pm, edited 2 times in total.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49056
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: Allow floating-point division by zero in ZScript

Post by Graf Zahl »

In terms of scripting, min and max are VM opcodes so they are very efficient. An 'if' requires a branch which is 2 more costly instructions most of the time.
argv
Posts: 184
Joined: Tue Aug 30, 2016 4:47 pm

Re: Allow floating-point division by zero in ZScript

Post by argv »

Is clamp also a single VM operation?
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49056
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: Allow floating-point division by zero in ZScript

Post by Graf Zahl »

No. It's a min followed by a max.
Gez
 
 
Posts: 17833
Joined: Fri Jul 06, 2007 3:22 pm

Re: Allow floating-point division by zero in ZScript

Post by Gez »

AFADoomer wrote:For brevity's sake, I usually end up putting in a "max([calculations], [arbitrary small number]);" call in cases like this...

e.g.:

Code: Select all

TweenChange = max(1. / (time * TICRATE), 1);
Not sure if that slows things down internally any more/less than using if statements to the same effect, but I haven't noticed any issues so far.
I don't get it -- this doesn't avoid the potential division by zero, does it?

I'd expect more something like this:

Code: Select all

TweenChange = 1. / (max(time, 0.0001) * TICRATE);
Post Reply

Return to “Closed Feature Suggestions [GZDoom]”