7 ms·
How to handle division by zero in a language that doesn't support exceptions?
- haberman 12y agoFor 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 12y agoYeah, 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 12y ago> 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 12y agoYes, I was talking about the signed integer overflow. Floating point division by zero is of course defined in C/C++, as per IEEE 754.
- logicallee 12y agoCalling it undefned is a cute meta-exception, but the compiler (or runtime) still does something when hitting that code.
- klodolph 12y agoYeah, the compiler typically assumes it works, and encodes assumptions that it does work into the surrounding code. On some systems you will get SIGFPE. On other systems, the result is something defined like 0. On some systems, the result is whatever happened to be in some register or whatever.
- pjmlp 12y ago> At least that's what C and C++ do. And it's useful for optimizers, And for security exploits.
- thegeomaster 12y agoSounds 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.
- yohanatan 12y agoVisual Basic has this mode. See 'on error resume next': http://msdn.microsoft.com/en-us/library/aa266173(v=vs.60).aspx http://msdn.microsoft.com/en-us/library/aa266173(v=vs.60).as...
- byuu 12y agoI 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()
- Myrmornis 12y agoI think it's the only language I have worked with that's so happy to chug along and ignore errors that arise in execution Other technologies designed to render content for web browsers do this also, such as javascript and the django template rendering engine.
- analog31 12y agoThinking 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 12y agoIt'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.
- deleted 12y ago[deleted]
- byuu 12y agoIt 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 12y agoThere'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 12y agoYep, 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.
- logicalsolut 12y agoHow do you specify a value that is neither greater than nor less than in no more than 2 bits?
- recursive 12y agoIt would be equal. (to what?)
- drdeca 12y agoIt 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 12y agoYes. 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.
- eldude 12y agoWould 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 12y agoThat's was I proposed at reddit (a maybe monad).
- masters3d 12y agoI 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. :/
- Tloewald 12y agoA 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.
- jagger27 12y agoWorse yet, just return the highest possible value of the data type. Probably a 32bit integer.
- klodolph 12y agoNo, 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 12y agoBut 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?
- anon4 12y agoI 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.
- ori_b 12y ago> One more idea I didn't see is to mark the variable as "invalid". That's what NaN is.
- aromogato 12y agoNot quite, marking a variable as invalid in this context is essentially a job for the type system. For example, in C, you can have a void* which can be null. This can lead to seg faults, and NaN has the same pitfall. Instead, with the Maybe idea above, the type system explicitly makes you handle the NaN case since the type is a discriminated union. This is like `int?` in C#.
- ericHosick 12y agoI like the idea of providing an alternate value or even alternate flow of execution. The action to take when dividing by 0 is based on context: it is a business behavior. In my opinion, it is no different than any other business requirement (for example: passwords must be longer than 8 characters, etc.). A language should allow a developer to configure the action to take when a division by zero occurs within a given context: the default being an exception and/or termination of program execution.
- jrockway 12y agoresult, err := x / y if err != nil { do something }
- Riesling 12y agoSince 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 12y agoActually, 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.
- p0nce 12y agoCrash immediately. A divide by zero is always an unrecoverable error. Same story with array out-of-bounds access and null dereferences.
- deleted 12y ago[deleted]
- bluecalm 12y agoNot 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.
- Kiro 12y agoWhat's the difference between option 3 and an exception?
- klodolph 12y agoOption 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 12y agoBut 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.
- nhenezi 12y agoYou can catch exceptions
- klodolph 12y agoThere 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.html https://mail.mozilla.org/pipermail/rust-dev/2014-June/010363...
- true_religion 12y agoThis 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.
- Someone 12y agoNaNs 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 12y ago2'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 12y agoIt 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 12y agoAfter 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.
- oelmekki 12y agoSounds 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.
- chrisbennet 12y agoTo 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.
- VLM 12y agoMy 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.