Live data from Hacker News

How to handle division by zero in a language that doesn't support exceptions?

programmers.stackexchange.com

11–20 of 66 posts

Re: How to handle division by zero in a language that doesn't support exceptions?

#11
post #10

It entirely depends on the application's role. If it's used in a video game with no save slots, where a crash is just going to lose lots of progress, I'd rather attempt to keep going even if there's an error, but only in release builds. Crash in debug builds to try and alert the programmer. If it's used to save important work, where the bad divide could lead to data corruption, it's probably better to crash than risk…

There's two competing software philosophies which are sometimes called "banker" and "moon rover." If you are writing a bank program, you want to catch errors immediately, to ensure that mistakes can't silently propagate. But if you are writing a moon rover, under no circumstances abort: keep going no matter what!

We have two Mars rovers right now, Opportunity and Curiosity. Fittingly, these use PowerPC chips, which are in the moon rover camp: divide-by-zero is zero. Really! Go get a PowerPC Mac, do a divide-by-zero, and you just silently get zero. Solution #1 baked into the ISA. Not many people seem to have noticed, so it can't have caused too much trouble.

(Apologies for reposting my reddit comment here)

Re: How to handle division by zero in a language that doesn't support exceptions?

#12
post #10

It entirely depends on the application's role. If it's used in a video game with no save slots, where a crash is just going to lose lots of progress, I'd rather attempt to keep going even if there's an error, but only in release builds. Crash in debug builds to try and alert the programmer. If it's used to save important work, where the bad divide could lead to data corruption, it's probably better to crash than risk…

There's two competing software philosophies which are sometimes called "banker" and "moon rover." If you are writing a bank program, you want to catch errors immediately, to ensure that mistakes can't silently propagate. But if you are writing a moon rover, under no circumstances abort: keep going no matter what! We have two Mars rovers right now, Opportunity and Curiosity. Fittingly, these use PowerPC chips, which a…

Yep, this is also the case with some gaming systems; eg the SNES CPU's ALU, and also its Sony APU (SPC700). Division by zero continues on instead of crashing. They usually return 0 for the quotient, and ~0 ("-1") for the remainder.

So if it's not too much work, I'd like my language to give me the option based on the type of application I want. But if it were forced to be a choice, I'd probably err on the side of safety.

Re: How to handle division by zero in a language that doesn't support exceptions?

#13
post #7

Earlier quoted context omitted.

Yeah, but they usually just say that the result is undefined. At least that's what C and C++ do. And it's useful for optimizers, because they can assume more about basic arithmetic in signed types and do some neat tricks.

> Yeah, but they usually just say that the result is undefined. Just to clarify, I think you're talking about the INT_MIN / -1 case? I think that floating-point division by zero is defined in C and C++.

Yes, I was talking about the signed integer overflow. Floating point division by zero is of course defined in C/C++, as per IEEE 754.

Re: How to handle division by zero in a language that doesn't support exceptions?

#14
post #10

It entirely depends on the application's role. If it's used in a video game with no save slots, where a crash is just going to lose lots of progress, I'd rather attempt to keep going even if there's an error, but only in release builds. Crash in debug builds to try and alert the programmer. If it's used to save important work, where the bad divide could lead to data corruption, it's probably better to crash than risk…

I was writing games in C++ for a long, long time, and recently started working on a very different project—a server using libuv and a lot of crypto operations with OpenSSL. I defined an ASSERT macro, and not thinking about it, wrote it so that in release builds, ASSERT does nothing. It's a very common thing to do in game engines: you do assertions on all sorts of things to catch user errors, but they slow the engine down a lot, and you don't want to crash the whole game because of some (maybe innocuous) error so you just ignore failed assertions.

Imagine my surprise when I did a release build for the first time and realized what I'd done :)

Re: How to handle division by zero in a language that doesn't support exceptions?

#16
post #10

It entirely depends on the application's role. If it's used in a video game with no save slots, where a crash is just going to lose lots of progress, I'd rather attempt to keep going even if there's an error, but only in release builds. Crash in debug builds to try and alert the programmer. If it's used to save important work, where the bad divide could lead to data corruption, it's probably better to crash than risk…

I was writing games in C++ for a long, long time, and recently started working on a very different project—a server using libuv and a lot of crypto operations with OpenSSL. I defined an ASSERT macro, and not thinking about it, wrote it so that in release builds, ASSERT does nothing. It's a very common thing to do in game engines: you do assertions on all sorts of things to catch user errors, but they slow the engine…

Could you elaborate a little on what happened? What exactly went wrong?

Re: How to handle division by zero in a language that doesn't support exceptions?

#17
Would this not be an excellent case for an optional type or Maybe monad? Instead of all NaN operations returning NaN, have them all return an optional type, similar to how swift dictionaries return an optional for property access. This is enforceable by the compiler.

Re: How to handle division by zero in a language that doesn't support exceptions?

#18

Earlier quoted context omitted.

I was writing games in C++ for a long, long time, and recently started working on a very different project—a server using libuv and a lot of crypto operations with OpenSSL. I defined an ASSERT macro, and not thinking about it, wrote it so that in release builds, ASSERT does nothing. It's a very common thing to do in game engines: you do assertions on all sorts of things to catch user errors, but they slow the engine…

Could you elaborate a little on what happened? What exactly went wrong?

Well, this was a server, and it was also multithreaded, so many synchronization bugs that didn't happen in debug builds did happen in release ones because of timing. Without assertions, though, none of these was caught on time, so I was left with mystical crashes, garbage data sent out to clients, etc etc. I spent hours and hours in valgrind and gdb, and only then realized that none of the assertions worked. When I re-enabled them, I was able to snipe (almost) all of the bugs easily.

But this is generally the kind of thing that happens when you turn a blind eye to errors somewhere where that's not a good way to go. In gamedev, sure, nobody cares, but if you're dealing with crypto and security-sensitive stuff, well, what I did was very, very bad. It's a small proof-of-concept pet project, but if I was ever to release something like that to the public, it would be very irresponsible of me.

Post reply on HN