[No] Allow floating-point division by zero in ZScript

Moderator: GZDoom Developers

Allow floating-point division by zero in ZScript

Postby argv » Fri Jul 27, 2018 9:55 pm

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. :)
argv
 
Joined: 30 Aug 2016

Re: Allow floating-point division by zero in ZScript

Postby Major Cooke » Fri Jul 27, 2018 10:13 pm

ಠ_ಠ

Pardon my asking but, just what would you need infinity for?
User avatar
Major Cooke
Do unto others as you would have unto you. Judge yourself first.
 
Joined: 28 Jan 2007

Re: Allow floating-point division by zero in ZScript

Postby argv » Fri Jul 27, 2018 11:05 pm

From Use To Pickup:

Code: Select allExpand view
      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
 
Joined: 30 Aug 2016

Re: Allow floating-point division by zero in ZScript

Postby argv » Fri Jul 27, 2018 11:15 pm

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 allExpand view
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.
argv
 
Joined: 30 Aug 2016

Re: Allow floating-point division by zero in ZScript

Postby dpJudas » Fri Jul 27, 2018 11:33 pm

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.
dpJudas
 
 
 
Joined: 28 May 2016

Re: Allow floating-point division by zero in ZScript

Postby Graf Zahl » Sat Jul 28, 2018 1:32 am

Considering how much trouble NaNs have been with the JSON serializer, let's better not think about this any further.
User avatar
Graf Zahl
Lead GZDoom Developer
Lead GZDoom Developer
 
Joined: 19 Jul 2003
Location: Germany

Re: Allow floating-point division by zero in ZScript

Postby argv » Sat Jul 28, 2018 2:06 am

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.
argv
 
Joined: 30 Aug 2016

Re: Allow floating-point division by zero in ZScript

Postby dpJudas » Sat Jul 28, 2018 5:55 am

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.
dpJudas
 
 
 
Joined: 28 May 2016

Re: Allow floating-point division by zero in ZScript

Postby Gez » Sat Jul 28, 2018 8:41 am

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.
Gez
 
 
 
Joined: 06 Jul 2007

Re: Allow floating-point division by zero in ZScript

Postby Gutawer » Sat Jul 28, 2018 10:51 am

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
Gutawer
User Accounts Assistant
 
Joined: 16 Apr 2016
Discord: Gutawer#3431

Re: Allow floating-point division by zero in ZScript

Postby AFADoomer » Sat Jul 28, 2018 11:37 am

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 allExpand view
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 6:08 pm, edited 2 times in total.
User avatar
AFADoomer
 
Joined: 15 Jul 2003

Re: Allow floating-point division by zero in ZScript

Postby Graf Zahl » Sat Jul 28, 2018 11:40 am

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.
User avatar
Graf Zahl
Lead GZDoom Developer
Lead GZDoom Developer
 
Joined: 19 Jul 2003
Location: Germany

Re: Allow floating-point division by zero in ZScript

Postby argv » Sat Jul 28, 2018 4:09 pm

Is clamp also a single VM operation?
argv
 
Joined: 30 Aug 2016

Re: Allow floating-point division by zero in ZScript

Postby Graf Zahl » Sat Jul 28, 2018 4:10 pm

No. It's a min followed by a max.
User avatar
Graf Zahl
Lead GZDoom Developer
Lead GZDoom Developer
 
Joined: 19 Jul 2003
Location: Germany

Re: Allow floating-point division by zero in ZScript

Postby Gez » Sat Jul 28, 2018 4:58 pm

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 allExpand view
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 allExpand view
TweenChange = 1. / (max(time, 0.0001) * TICRATE);
Gez
 
 
 
Joined: 06 Jul 2007

Next

Return to Closed Feature Suggestions

Who is online

Users browsing this forum: No registered users and 2 guests