I first used the obvious code and it seemed to not optimise so I did not bother with the argv parsing trick to turn off optimisations.
I was expecting to need to use that trick. Did the compiler optimise?
I’ll run the argv no-optimise version in a bit and see.
Please go and ask your mother how division is defined. Division is intended to invert multiplication (when possible) so if a/b = c
then this means that c
is something such that b*c = a
. If you say that 1/0 = 0
then this implies that 0*0 = 1
which is very clearly false in basic arithmetic.
There are some contexts in mathematics in which 1/0
is defined (e.g. the Riemann sphere) but it is not usually equal to 0
. The only exception I can think of right now is the zero ring in which 1 = 0
so 0*0 = 1
does hold. The zero ring is a trivial edge case that is not actually useful in computing though.
Here is a video that explains that 1/0
is undefined at “3rd grade level”: https://www.youtube.com/watch?v=WI_qPBQhJSM
I’ve no idea; it’s so compiler-dependent. But when I see something that appears to do nothing, I have to wonder if it’s been optimized out. Maybe it has, maybe it hasn’t. Maybe the CPU-level signal is happening, but it just doesn’t print anything to the console. Hard to know.
Let’s remove doubt.
#include <cstdio>
#include <iostream>
#include <string>
int main(int argc, char **argv) {
std::string cmd( argv[1] );
std::string arg1( argv[2] );
std::string arg2( argv[3] );
if( cmd == "float" ) {
double f1 = std::stod(arg1);
double f2 = std::stod(arg2);
std::cout << "f1 " << f1 << " f2 " << f2 << std::endl;
double result = f1/f2;
std::cout << "double float result " << result << std::endl;
} else {
// assume int
int i1 = std::stoi(arg1);
int i2 = std::stoi(arg2);
std::cout << "i1 " << i1 << " i2 " << i2 << std::endl;
double result = i1/i2;
std::cout << "int result " << result << std::endl;
}
}
macOS ARM llvm results:
% ./zero.sh
+ ./zero float 5 3
f1 5 f2 3
double float result 1.66667
+ ./zero float 5 0
f1 5 f2 0
double float result inf
+ ./zero int 5 3
i1 5 i2 3
int result 1
+ ./zero int 5 0
i1 5 i2 0
int result 0
Fedora 40 x86_64 gcc c++ results:
$ ./zero.sh
+ ./zero float 5 3
f1 5 f2 3
double float result 1.66667
+ ./zero float 5 0
f1 5 f2 0
double float result inf
+ ./zero int 5 3
i1 5 i2 3
int result 1
+ ./zero int 5 0
i1 5 i2 0
./zero.sh: line 6: 4830 Floating point exception(core dumped) ./zero int 5 0
Fedora 40 aarch64 gcc c++ results:
$ ./zero.sh
+ ./zero float 5 3
f1 5 f2 3
double float result 1.66667
+ ./zero float 5 0
f1 5 f2 0
double float result inf
+ ./zero int 5 3
i1 5 i2 3
int result 1
+ ./zero int 5 0
i1 5 i2 0
int result 0
Microsoft Visual C++ results:
C:\Users\barry\tmpdir>.\zero float 5 3
f1 5 f2 3
double float result 1.66667
C:\Users\barry\tmpdir>echo 0
0
C:\Users\barry\tmpdir>.\zero float 5 0
f1 5 f2 0
double float result inf
C:\Users\barry\tmpdir>echo 0
0
C:\Users\barry\tmpdir>.\zero int 5 3
i1 5 i2 3
int result 1
C:\Users\barry\tmpdir>echo 0
0
C:\Users\barry\tmpdir>.\zero int 5 0
i1 5 i2 0
C:\Users\barry\tmpdir>echo -1073741676
-1073741676
-1073741676 is 0xC0000094 which is STATUS_INTEGER_DIVIDE_BY_ZERO
In summary only on X86_64 is there a divide by zero CPU exception.
Both Windows 11 and Fedora 40 Linux do the same thing.
The relevant specification was linked above, the differing behavior based on architecture might have a logical reason from the compiler’s pov, but ultimately this is undefined behavior and people should not rely on the examples above as removing doubt, the behavior is subject to change as compilers are allowed to do anything when presented with undefined behavior.
I agree its undefined.
What I wanted to show is how C++ was handling this as an example for the OP to consider, and I was just curious.
Python’s ZeroDivisionError is so entrenched, I don’t expect it to change, but if we were somehow starting over (the time to do this would have been in the Python 2 → 3 transition), I think that
0 / 0
→ float("nan")
and
nonzero / 0
→ float("inf") if nonzero > 0 else float("-inf")
with a warning, rather than an error, might be better. Why? Because it’s what NumPy does.
>>> numer, denom = 0, 0
>>> numer / denom
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
while
>>> numer, denom = np.float64(0), np.float64(0)
>>> numer / denom
<stdin>:1: RuntimeWarning: invalid value encountered in scalar divide
nan
>>> numer, denom = np.float64(1), np.float64(0)
>>> numer / denom
<stdin>:1: RuntimeWarning: divide by zero encountered in scalar divide
inf
>>> numer, denom = np.float64(-1), np.float64(0)
>>> numer / denom
-inf
It makes more sense to align Python’s behavior with NumPy than aligning it with some C or C++ compilers, since Python numbers and NumPy numbers often get mixed in a script. It would be nice to have fewer edge cases to have to check, such as, “My library function accepts numbers from users, and users might not even know whether they’re passing in Python numbers or NumPy numbers, since it depends sensitively on how they were computed. Well, I guess I have to prepare for both cases and handle the different kinds of errors they would each result in.”
Incidentally, it is good that NumPy returns nan/inf/‒inf for division by zero, since large arrays of computed values (with measurement error and floating-point error) might accidentally include a few zeros. Even at the level of 1 in a billion, it would happen in a GB-scale dataset. I’m not saying there’s any correct real-valued result for division by zero, but allowing 99.9999999% of the billion array elements to pass through the calculation without having to check for errors—with the wrong ones labeled as “not a meaningful result”—is useful.
If a child enters 1/0 and it doesn’t work they will learn something very important - specifically that division by zero is undefined in maths and incorrect. It’s certainly far from conventional to define 0/0 as 0 (or 1 - which children often do as well).
The only valid response to return are either return a non-integer value which represents “Not a number” OR to throw an exception. You clearly don’t like the latter, but what about the former?
Well, if the result was to return something which represents “Not a number” - for example “None”, then the number would likely next be used in some other calculation. That next step will result in this error:
TypeError: unsupported operand type(s) for *: ‘NoneType’ and ‘int’
At which point they’re left with an even more cryptic error.
Some people in the thread suggested infinity as an option. However, Infinity isn’t a number either, but while the expression “1/n” tends to infinity as n tends to zero it never gets to infinity. Why ? Because infinity is also not a number - it’s a limit. So again you’re now dealing with something which isn’t a number (Infinity) as a value to define something which is undefined.
Someone raised teaching here. If (and only if) someone was taught as a child that 1/0 == 0 then I’m afraid that teacher was not very good. In defense of teachers in the UK, up to 16 there’s no requirement for them to have a maths degree, and may have forgotten that they should’ve been taught as a child that division by 0 is not defined. (I’ve known people with PE degrees teaching maths ) At post-16 (A-Level) I’ve never come across a teacher that didn’t have one. (Any maths graduate who teaches that division by zero is valid shouldn’t be teaching)
Just because some compilers get this wrong (neither g++ nor clang++ do though), is not a reason for python to get it wrong. That might seem unfair and weird but it isn’t. In python it’s reasonable to write code using the “better to ask forgiveness pattern” rather than “look before you leap”.
Taking your example of C/C++/etc you’re expected to do it the other way round - look before you leap. So if you give a function/operation garbage (like division by zero), you should expect garbage back. In this case 1/0 is giving the division operator garbage - so in C/C++/etc what you get back is garbage and extremely compiler specific. Some might give you MAXINT, some might give 0, some will segfault. This is in keeping with C/C++ philosophy of “if you break it, you get to keep the pieces” in the spirit of speed.
If you want to give a GPU garbage in C++ it’ll happily do so. If you write stuff that’s undefined in C++, it’ll do something. It won’t be correct, it’s liable to change and break in different versions, but it’ll happily do it. But won’t be “correct” (for example accessing memory you shouldn’t).
Interesting, just tried this with g++ 13.2, and it bails with the error:
$ g++ -Werror test.cpp -o div
test.cpp: In function ‘int main(int, char**)’:
test.cpp:4:10: error: division by zero [-Werror=div-by-zero]
4 | x = 1/0;
| ~^~
cc1plus: all warnings being treated as errors
If you remove the -Werror (but why would you?) option, and try to run the resulting binary, it again doesn’t result work the way you state:
$ ./div
Floating point exception (core dumped)
Both these scenarios are in keeping with how I’d expect C++ to work in this scenario.
Testing with clang++ (18.1) I get this
$ clang++ test.cpp -o div
test.cpp:4:10: warning: division by zero is undefined [-Wdivision-by-zero]
4 | x = 1/0;
| ^~
1 warning generated.
That version doesn’t segfault - BUT that doesn’t make the code or return value correct. It just means it’s doing whatever it “feels” like - a handful of outputs:
$ for i in
seq 1 10
; do ./div; done
-1533562544
2016252240
2062467408
-2077007536
-182644400
(With floats, both g++ and clang return inf - clang stops warning, but g++ still warns)
In python the default is to throw an exception if you pass in invalid parameters to functions, so throwing an exception here makes perfect sense. Especially since pretending the result is a number/masking the error will result in making it difficult to debug what’s going wrong.
Incidentally, I think python not shying away from basic mathematical truths is quite sensible really.
Sorry, but a hard no from me.
I was a math teacher, and Oscar is entirely correct. There are “infamous” math “proofs” that show 1 == 2 by sticking a disguised zero division in the middle (e.g. something like z/(x -y) where x== y).
As Apple’s Siri used to say:
Imagine that you have zero cookies and you split them evenly among zero friends. How many cookies does each person get? See? It doesn’t make sense. And Cookie Monster is sad that there are no cookies. And you are sad that you have no friends
It is hard to find things in math, that are not defined somewhere in math. More common is, like in this case, that depending on the context/need they get one definition or another. It is more a phenomenon of elementary education, where you want to prevent students making some mistakes, like doing division by zero to accomplish cancelation of multiplication, that rigid dogmas like that are taught.
It is not so much the undefinition, but that there are multiple options, and that they are less widely used, that computer languages report the error. Even in finite precision floating point arithmetic, where division by 0
is perfectly defined in all cases, returning a unique instance of the type, it is still reported to the user, to allow them to make choices according to their use case.
This is a vacuous statement (in math). There is no such thing as number in mathematics. So, the statement is not saying anything. Statements that would make sense are “infinity is not a natural number”, or “infinite is not a real number”, which are true; but then there are statements like “infinity is not a cardinal number”, or infinity is not a surreal number" that are not accurate.
In those, it is not so much the division by zero the culprit, but to deduce that because it is defined it ought to cancel multiplication.
Being the inverse of multiplication is not the only use of division. One might want to have division, including division by zero, for example, because it has a convenient geometric interpretation.
Nonsense. Numbers are well defined; there are a number of[1] viable definitions, all with the same effect. Counting numbers can be defined by set cardinality, positive real numbers can be defined as distance, you can delve into p-adic numbers for a different way of defining them, etc, etc.
If you disagree with me, find some evidence to back your point, instead of making bald - and entirely meaningless - statements.
pun intended ↩︎
Well, you just don’t know what you are talking about. Number is a concept in common language. It is not in mathematics. And the reason is simple, there is no need for it. There are no theorems that need it as a hypothesis. There are, however, in which the hypotheses involve specific sets, or categories, some of which are concepts that have compound names that one of the words is “number”.
From the math perspective, division by zero cannot return 0 in any scenario. Division by zero of any real number not equal to zero will lead to ±infinities, which are not numbers.
0/0 is not defined as a real number because, based on the original function, it may return any number at all (see the (x-1)/(x-1) function, for example).
So, raising exceptions in this scenario is a pretty rational way to avoid absurd calculations. If your case requires custom math for division by zero, you can always create your subclass of int or float and redefine behaviour for division by zero as you want.
correctly to say, operations like 0/0, 0^0, inf * 0, inf / inf are not defined for real or complex numbers.
Probably, for some other set of numbers in high-level math, the answer would be different. But reality is enough for most of our world, and even complex numbers are overkill.
Let’s not do that kind of thing here. This topic was heated from the get-go, I expect seasoned community members to navigate those without fanning the flames.
I’m not going to rise to the frankly offensive tone you’re taking Franklinvp. If you can’t make your point politely, it’s not a point worth taking seriously.
Division by zero is undefined for mathematics. Clearly I am talking about the specific domains of real numbers and integers, because that’s the domains that this exception is raised in. Yes, you can define anything you like if you define your own system of mathematics - you’re free to pick your own axioms after all.
If you disagree, a) please do so in a reasonable fashion, I have some suggested reading - since they form the basis of my understanding, and I’d like to know where they got it so “vacuously” wrong.
" A Course of Pure Mathematics, but G H Hardy". The reason I’m suggesting reading it, is because it was a required text when I started my degree decades ago. It’s a solid decent read if a bit dense these days. I believe earlier editions are available for free these days due to copyright expiration.
Maybe the fundamentals have changed? If so, if this book isn’t correct (if you’ve read it/worked through it) , could you recommend me a better one? Or in particular point out which arguments it puts forward which are incorrect?
One thing you will find in in that book is a axiomatic progression from the natural numbers through integers, rationals, irrationals and so on - as anyone who’s taken a basic degree level course on Mathematical Analysis will tell you. (At least in the UK, other curricula are available.) It does also cover in depth concepts like limits (such as Infinity) and so on.
I responded to the original post. I defended a possible reason they may have been taught incorrectly. I referenced the standard point of GIGO (which C++ will happily support) and stated why I disagree with the argument put forward. I tried to do so politely and I hope the OP took it politely.
As someone who has built software / hardware systems designed for use by children (successfully - far more so than I expected), I fully understand the desire to simplify things sometimes. But simplifying them to the extent of hiding fundamental errors? No, that’s a pretty bad idea.
Quite why you’ve decided to be quite so offensive though. That doesn’t particular feel constructive, it doesn’t help the conversation and is hardly the sort of behaviour I was previously used to from the python community.
If you can make your points without describing people’s points as vacuous or stating that they don’t know what their talking about, then maybe I’ll respond. However I have better things to do.
bye all!