
How to handle division by zero in a language that doesn't support exceptions? - prajjwal
http://programmers.stackexchange.com/questions/208677/how-to-handle-divide-by-zero-in-a-language-that-doesnt-support-exceptions
======
analog31
Thinking back to when I was a novice programmer, and the consequences of my
mistakes when working on stuff that was probably over my head, "terminate with
extreme prejudice" seems like the only acceptable option. No result and a call
from a user seems better than a wrong result. Folks will use a tool for safety
(personal or financial) critical tasks without really thinking about failure
modes.

Things like pocket calculators, Excel, and even web forms, will cough up a
lung and quit when they hit an exception. So I think that novices of today are
probably amply familiar with this mode of operation, even before learning to
program.

~~~
to3m
It's bad enough even when you've got years of experience of debugging programs
and you find an error that only reveals itself at the end of some long
sequence of operations. For a language that's supposed to be targeted at the
inexperienced, letting bogus results propagate is just cruel.

I'd definitely incline towards an immediate abort. But for processes that run
overnight, presumably because they take a long time, who can say? If there's a
1 day turnaround time, and the results are so important that it absolutely
must not stop, and yet inexperienced programmers are responsible for writing
the code that runs... well, I'm not sure one thing is going to be a huge
improvement over something else. It's probably going to end up a bit painful
whatever you do.

------
haberman
For IEEE floating point, there is NaN and +/-Infinity which are raised when
dividing by zero:
[http://grouper.ieee.org/groups/754/faq.html#exceptions](http://grouper.ieee.org/groups/754/faq.html#exceptions)

For integers that don't have NaN/infinity values the options are less clear.
Note that languages with two's complement fixed width signed types like int32
have the same problem with INT32_MIN / -1, since the result is not
representable as an int32.

~~~
thegeomaster
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.

~~~
haberman
> 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++.

~~~
thegeomaster
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.

------
Someone
NaNs are an incredibly good idea, but it turns out we really need only one.

Also, two's complement signed integers have an asymmetry that INT_MIN <
-INT_MAX.

Therefore, I were to design a CPU today, I would add arithmetic instructions
that treated INT_MIN as a NaN, thus removing the asymmetry, and giving us an
integer NaN.

16 bit int values would range from -32767 to +32767, with the bit pattern now
used for -32768 being NaN. You would use it for everything that isn't
representable as an int (overflow, underflow, 3/2 (as opposed to 3 mod 2),
etc)

Yes, that CPU would also would have instructions for doing the regular modulo
2^16 arithmetic, but 'sane ints' would help not penalize programming languages
that want to do sane integer arithmetic.

~~~
keeperofdakeys
2's complement (the binary representation of numbers in a cpu) has one awesome
feature, if you add two signed numbers, even if one or both are negative, you
get the right answer. This means that you can add two numbers without checking
if one is negative, saving time and scarce circuit space. In order to add a
NaN, you'd need a check for NaN. This would basically double the amount of
time an add would take, and add more circuit paths to the core of the cpu.

If we use a single bit dedicated to signalling NaN, the overhead might be
worth it. Of course, we lose half of our range in doing so.

~~~
cesarb
It wouldn't double the amount of time for an add (or any other operation), if
it's implemented in hardware the comparison can be done in parallel with the
addition, and the result of the addition ignored at the end if the compare
returned true.

It would increase the use of space by the circuit, but not by much. And we
already have circuitry doing similar things to set the flags (zero, carry,
overflow, parity...).

If you want a real-world system with a single extra bit for every value (on
registers at least), see the Itanium and its NaT bit (used for speculative
loads).

~~~
keeperofdakeys
After writing it, I realised that you could just do both in parallel, but it
soon makes things much more complicated since nearly everything is based on
adds.

------
anon4
I liked the ternary operator where you provide an alternate value in case the
denumerator is 0.

One more idea I didn't see is to mark the variable as "invalid". A general
"this variable doesn't have a value because the program did something bad",
which carries a full stack trace with itself. Then, if you ever use that value
anywhere, the result is again invalid, with the new operation attempted on top
(i.e. if the invalid value ever appears in an expression, the entire
expression yields invalid and no function calls are attempted; an exception
would be boolean operators - true or invalid is true and false and invalid is
false - there may be other exceptions to that, too). Once that value is no
longer referenced anywhere, you log a nice long description of the entire
chain where things were wrong and continue business as usual. Maybe email the
trace to the project lead or something.

Something like the Maybe monad basically. It will work with anything else that
can fail, too, and you can allow people to construct their own invalids. And
the program will continue to run as long as the error isn't too deep, which is
what is really wanted here, I think.

~~~
goblin89
> One more idea I didn't see is to mark the variable as "invalid". A general
> "this variable doesn't have a value because the program did something bad",
> which carries a full stack trace with itself.

A simple way to handle exceptions like that (and I didn't see it mentioned
among the answers) is to return 2-tuple from the function: result value and
error information. The latter could be empty, but both could be present.

Though this might be overcomplicating things, given that OP targets the
language at novices.

~~~
derefr
Yep. You’d think that in, say, Haskell, the division operator would return
Maybe Num. It’s much more obvious when you’ve got Nothing than when you’ve got
NaN.

------
VLM
My favorite non-discussed answer on SE or here on HN (or at least I didn't
find it) is to disallow division other than as syntactic sugar for literal
definitions (and just output an error message if your syntactic sugar has a
zero denominator)

But but but how would they ... don't worry about it, its a programming
language for novices. If they knew what to do, they wouldn't be novices using
a novice language anyway.

I like this design because its self limiting. If they don't understand the
problem, they certainly won't understand how to fix it when it breaks anyway.

The problem with giving 3 year olds matches and knives and guns is not some
weird inherent moral argument about the items, its because the kids have no
idea how to fix some resulting problems and even the non-noobs can't fix some
of the resulting problems. So don't give noobs the ability to shoot themselves
in their foot. Its pretty simple.

Of course a logical next extension is removal of logarithms and many other
math functions. Thats OK. Its a language for noobs so it doesn't have to have
a full set of arithmetic. Unless this guy is implementing the next
"mathematica" or "R" or similar, in which case he has big problems.

------
oelmekki
Sounds to me like a language targeted at novice developers (and I suppose with
that author means people with no programming background) should add a very
strong emphasis on simulations and notifications.

Won't it be ok that program crashes if :

1\. it was likely the error was catch during a simulation before deployment

2\. author of code received a mail immediately to let know something bad
occurred

Such a language should probably be much bigger than our usual programming
language and include at core what is usually added by dev tools (tests and
notifications).

There was a discussion on HN a few days ago on "test only development" (link
has been marked "dead" since then, though), that is tests that produce code.
It reminds me of what "programming" a holodeck looks like in star trek : you
describe what you want and computer manage to produce code that achieves it.

Without getting so far, you could ask your users to describe what data looks
like in input and what it should looks like on ouput, as a core feature of the
language rather than on a separated and optional layer. Then, on build, you
run a "simulation" (yes, that is just testing) to ensure code behaves as
expected.

And you build notifications (by mail, for exemple) as a core feature of the
language too, maybe even include version control (you have to think hard how
to make that user friendly for your target) in order everybody has a idea of
what changed before the crash (this could be reported in notification).

When you have all of that, it does not matter if division by zero makes
program crash.

------
true_religion
This isn't related to the question at hand, but one of the most interesting
ways to handle this was in a smalltalk app i saw, which turned the result into
a custom NaN and stuffed the execution context into the variable so even if
you restored it from the database, you'd know exactly where the divide by zero
occurred. That's different from all the other languages where NaNs propagate
but you don't know their origin.

------
byuu
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 the corruption. Although
if you have the capability to ask the user what to do, that would be ideal.

If it's to develop something that handles money or lives, or is eg deployed on
a satellite, not even crashing is acceptable. In that case, I'd force the
language to have the user test with something like Haskell's "Maybe". For
instance:

    
    
        if(result = x / y) {  //x / y returns an object: maybe<int>
          z = result.get()
        }  // } else { handle division by zero case }
    

(edit: of course even that isn't fool-proof if the user tries hard enough to
work around your safeguards. But you can't blame the language if the user is
actively thwarting it.)

~~~
ridiculous_fish
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)

~~~
byuu
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.

------
thegeomaster
Sounds like a new PHP in the making, someone even mentioned it in the link. I
think it's the only language I have worked with that's so happy to chug along
and ignore errors that arise in execution. And the exception system was just
thrown on top of it in PHP5 as an afterthought. Ugh.

~~~
byuu
I greatly dislike the language myself, but to be fair, it does allow the case
where even a notice will terminate execution; and then to special-case
functions that can safely fail with an @ prefix. Most people just turn all of
that off with error_reporting()

------
eldude
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.

~~~
jesuslop
That's was I proposed at reddit (a maybe monad).

------
klodolph
There was, well, a _long_ thread on integer overflow on rust-dev a couple
weeks ago.

[https://mail.mozilla.org/pipermail/rust-
dev/2014-June/010363...](https://mail.mozilla.org/pipermail/rust-
dev/2014-June/010363.html)

------
p0nce
Crash immediately. A divide by zero is always an unrecoverable error. Same
story with array out-of-bounds access and null dereferences.

~~~
bluecalm
Not really. Sometimes it's faster to do the calculations and check after the
fact if NaN flag was set instead of checking for division by zero at every
point. Languages that auto crash on division by zero will always be slower at
such applications.

------
Tloewald
A really sly option would be to, effectively, allow infinitesimals. So 10/0
would return 10/0 (perhaps a kind of NaN but with more information retained),
and if you multiplied it by 0 elsewhere you'd get 10. Probably a bad idea for
novice programmers but interesting to consider.

~~~
klodolph
No, this is wrong.

In order to work with infinitesimals in any reasonable way, you have to define
how they work. There _is_ a reasonable way to extend the real numbers in a
larger field containing infinitesimals. Such a field is non-Archimedean and
has very surprising properties: for example, you can construct a geometry in
which Euclid's fifth postulate is false, and yet the angles on a triangle
still always add up to 180. These fields also allow you to formalize your
intuition about the way infinitesimals like "dx" and "dy" in calculus and
analysis work: you can take an equation and multiply both sides by dx, for
example. This is ordinarily meaningless, since the term dy/dx is ordinarily
just notation that does not actually signify a fraction. In non-standard
analysis, it IS a fraction. I think it's a shame that analysis classes in
college don't use non-Archimedean fields because the proofs are so much
simpler.

However, even in these fields which admit infinitesimals, there is no
definition for x/0\. You can prove it for yourself.

Suppose x = 10/0.

    
    
        0*x = 10
        (0+0)*x = 10
        0*x + 0*x = 10
        10 + 10 = 10
        20 = 10
    

So this is just an all-around bad idea, because it permits us to say that 10 =
20. And all we had to say that 10/0 had a value... we didn't even say what
that value was.

P.S. Although infinitesimals exist, non-standard analysis still does not
permit you to, say, plug ∞ into an equation, because there are many different
infinite numbers. However, other systems (projective geometry) admit ∞ as a
value.

~~~
grkvlt
But in an environment manipulating symbols where one of them 'x' has the
property that multiplying by zero gives ten, I don't think the above sequence
could happen, or at least the symbolic evaluator would arrange things so that
the first time it sees '0 * x' it replaces that with 10. So to evaluate the
truth of the expression '(a+b) * x = 10' with 'a' and 'b' equal to zero, we
just need to ensure the 'a+b' is evaluated to zero before the multiplication,
using the axiom 'n+0=n' and we are back to '0 * x' on the LHS, which is ten.

I think it should be possible with appropriate precedence of the evaluation
rules?

~~~
klodolph
You're turning something which is merely wrong into a total nightmare.
Suddenly, 0+0 is not 0, because you have to wait to see if you multiply it by
x first before you can evaluate 0+0! Now there are multiple distinct values
for 0! Chaos and disharmony abound! In your system, 0+0=0+0, and 1+1=1+1. You
can't simplify any of your equations! In your system, 1+1=2 is FALSE!

No, seriously. Quit while you're ahead. Now that you know that dividing by
zero and getting a result is not a logically consistent proposition, you can
stop trying. That's the awesome thing about logic: once you PROVE something is
impossible, you're done.

------
logicalsolut
How do you specify a value that is neither greater than nor less than in no
more than 2 bits?

~~~
recursive
It would be equal. (to what?)

~~~
drdeca
It could also be fuzzy!

In combinatorial game theory, the star game is fuzzy with zero: not less or
greater, but not equal either.

The zero game is (iirc) the game where neither the left nor the right player
have any moves, so whoever's turn it is loses.

The star game (*) is iirc the game where both players have the move to move to
the zero game, so whoever starts wins.

But the star game is fuzzy with the zero game, less than the 1 game, and more
than the -1 game.

Iirc.

~~~
klodolph
Yes. To elaborate, this construction is called the "surreal numbers", and it
is the largest ordered field. All ordered fields are isomorphic to subsets of
the surreal numbers.

------
jrockway

       result, err := x / y
       if err != nil {
          do something
       }

~~~
Riesling
Since you are using go syntax... I don't think that this will work in go,
because division by zero will cause the function to panic.

~~~
jrockway
Actually, it doesn't even compile in go, because / doesn't return two
arguments. But he's writing his own language, not using go, so this limitation
need not apply.

------
Kiro
What's the difference between option 3 and an exception?

~~~
klodolph
Option 3 is like calling abort() in C: you can't stop it from killing the
process, unlike exceptions which can be caught and handled.

~~~
Kiro
But why would you want to catch and handle division by zero? Seems like the
normal thing an exception should do in that case is to kill the process.

------
masters3d
I would have said you can do it like this as in swift.

let x = 1231231 let z = 0

if z == 0 { println("Cant divide by zero") } else { println(x / z) }

But swift doesn't support exceptions either. :/

------
chrisbennet
To paraphrase a famous quote:

If when faced with a problem you say "I know, I'll make my own computer
language!" Now you have 2 problems.

