Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upInconsistencies with various division operators and NaN/Infinity #590
Comments
This was referenced May 10, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mgold
May 10, 2016
Contributor
I agree that it is consistent, but it allows ±Infinity and NaN, IEEE floating point abstractions, into the Int type, which may one day be represented as machine integers. Additionally, what should List.repeat (1//0) "foo" evaluate to? Empty list, sure, but when writing functions that take integers one loses guarantees that they are actually integers. Finally, it doesn't seem like one can perform operations on ±Infinity and NaN to obtain a finite non-integer value, but I'm still concerned about the possibility.
|
I agree that it is consistent, but it allows |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jvoigtlaender
May 10, 2016
Contributor
@mgold, do you have an alternative proposal to handle cases 1.-5. in a consistent way?
Not all of them necessarily need to be consistent. For example, 1. and 2. need not, since they are on different types. But 3. and 4. being inconsistent seems clearly undesirable, since both are some form of "mod division on integers".
|
@mgold, do you have an alternative proposal to handle cases 1.-5. in a consistent way? Not all of them necessarily need to be consistent. For example, 1. and 2. need not, since they are on different types. But 3. and 4. being inconsistent seems clearly undesirable, since both are some form of "mod division on integers". |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mgold
May 10, 2016
Contributor
2, 3, and 4 should either all return 0 or all throw runtime errors. 1 and 5 stay unchanged.
|
2, 3, and 4 should either all return 0 or all throw runtime errors. 1 and 5 stay unchanged. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jvoigtlaender
May 10, 2016
Contributor
2 returning 0 seems an abomination to me. Is there any precedent (say, a programming language) in which 1 divided by 0 is given as 0?
Making all of 2, 3 and 4 throw runtime errors was exactly the content of my closed #565 and #576. @rtfeldman disagreed.
|
2 returning 0 seems an abomination to me. Is there any precedent (say, a programming language) in which 1 divided by 0 is given as 0? Making all of 2, 3 and 4 throw runtime errors was exactly the content of my closed #565 and #576. @rtfeldman disagreed. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mgold
May 10, 2016
Contributor
Is there any precedent for a (Turing-complete) language to try so hard to avoid runtime errors? Ask a nonsense question, get a nonsense answer. Or, crash and hopefully catch the bug in development or testing. I'm actually undecided between the two.
I'm not sure exactly what @rtfeldman was talking about when he said he wanted to remove the check, so let's see what he has to say now that we've framed the issue a little better.
|
Is there any precedent for a (Turing-complete) language to try so hard to avoid runtime errors? Ask a nonsense question, get a nonsense answer. Or, crash and hopefully catch the bug in development or testing. I'm actually undecided between the two. I'm not sure exactly what @rtfeldman was talking about when he said he wanted to remove the check, so let's see what he has to say now that we've framed the issue a little better. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
rtfeldman
May 16, 2016
Member
To clarify, I'm not advocating one way or the other; I just wanted to note some facts (and an explanation I'd heard at some point for why some of them work the way they do) about the current state of things.
I have yet to encounter any of these edge cases in practice, and don't have particularly strong feelings about this.
|
To clarify, I'm not advocating one way or the other; I just wanted to note some facts (and an explanation I'd heard at some point for why some of them work the way they do) about the current state of things. I have yet to encounter any of these edge cases in practice, and don't have particularly strong feelings about this. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
rtoal
Jul 20, 2016
I just ran into case 2.
Anyone else seen a language in which 5 // 0 was 0? I found that really weird.
rtoal
commented
Jul 20, 2016
•
|
I just ran into case 2. Anyone else seen a language in which |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mgold
Jul 21, 2016
Contributor
Is there any precedent for a (Turing-complete) language to try so hard to avoid runtime errors? Ask a nonsense question, get a nonsense answer.
To be clear, the second sentence refers to division by zero as a nonsense question, not the question that you are asking.
To be clear, the second sentence refers to division by zero as a nonsense question, not the question that you are asking. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
evancz
Sep 22, 2016
Member
Consolidated all the math related stuff into the #721 meta issue. Follow along there!
|
Consolidated all the math related stuff into the #721 meta issue. Follow along there! |
evancz
closed this
Sep 22, 2016
jvoigtlaender
referenced this issue
Feb 2, 2017
Closed
String.toInt returns a Float in certain circumstances #831
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ohanhi
May 4, 2017
I just noticed you can actually coerce Infinity to be an Int:
> round (1 / 0)
Infinity : Int
This does not seem intentional, either.
ohanhi
commented
May 4, 2017
|
I just noticed you can actually coerce Infinity to be an
This does not seem intentional, either. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
fHachenberg
Jul 17, 2017
I strongly recommend to NOT make cases like (x / 0) return Infinity or sqrt(-1) return NaN as proposed above by jvoigtlaender. I come from a numerical computing background and my experience is that it's toxic to allow silent propagation of numeric exceptions. Infinity and NaN are NOT just values like any other float. In the worst case you end up with strange behaviour of your program at some distant point because a NaN result from some calculation spread through your code (NaN + x = NaN). Instead you want your program to crash as soon as possible because it obviously contains a bug.
fHachenberg
commented
Jul 17, 2017
|
I strongly recommend to NOT make cases like (x / 0) return Infinity or sqrt(-1) return NaN as proposed above by jvoigtlaender. I come from a numerical computing background and my experience is that it's toxic to allow silent propagation of numeric exceptions. Infinity and NaN are NOT just values like any other float. In the worst case you end up with strange behaviour of your program at some distant point because a NaN result from some calculation spread through your code (NaN + x = NaN). Instead you want your program to crash as soon as possible because it obviously contains a bug. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jvoigtlaender
Jul 17, 2017
Contributor
For the record:
1 / 0returningInfinityis what Elm currently does, not something that goes back to a proposal of minesqrt(-1)returningNaNisn't part of anything I proposed either
|
For the record:
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
fHachenberg
Jul 17, 2017
sorry for my inprecise citation.
- I saw that you proposed "1rem0 results in NaN (type Int, as before)" and generalized to "sqrt(-1)". My argument above certainly can be generalized to "1 rem 0" (-> don't return NaN).
- Sorry that my description suggested the status quo of "1/0" returning Inifinity to be part of your proposition. I consider this status quo to be a problem.
fHachenberg
commented
Jul 17, 2017
|
sorry for my inprecise citation.
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jvoigtlaender
Jul 17, 2017
Contributor
Also 1 `rem` 0 resulting in NaN is part of the status quo, not something I thought up.
But I do get that your general thrust is to raise a runtime error much more often than the status quo does. That is certainly one way to make things more consistent (than they are in the status quo, where some things raise runtime errors and others don't).
|
Also But I do get that your general thrust is to raise a runtime error much more often than the status quo does. That is certainly one way to make things more consistent (than they are in the status quo, where some things raise runtime errors and others don't). |
jvoigtlaender
referenced this issue
Sep 26, 2017
Closed
1 % 0 is an intentional runtime exception #909
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
rtavenner
Dec 29, 2017
I suggest defining m % 0 and rem m 0 to return m. Here is my reasoning:
- I would expect
mandm % nto be congruent modn, wheneverm % nis defined. There's a reason it's called the modulo operator! - Elm has a policy of "No Runtime Exceptions", so
m % nshould always be defined. - So for all m and n,
m % nexists, and is congruent tommodn. - By the definition of congruence mod
n,m - (m % n)is a multiple of n. - Setting
nequal to zero,m - (m % 0)is a multiple of zero. - Therefore,
m - (m % 0) = 0, and som % 0 = m.
By the same logic, rem m 0 should equal m.
Also note that with this definition, the formula m = (m // n) * n + rem m n holds universally.
rtavenner
commented
Dec 29, 2017
|
I suggest defining
By the same logic, Also note that with this definition, the formula |
jvoigtlaender commentedMay 10, 2016
Here is a collection of facts about current arithmetics behavior in Elm:
1 / 0results inInfinity(typeFloat)1 // 0results in0(typeInt)1 % 0throws a runtime error (typeInt)1rem0results inNaN(typeInt)isNaNandisInfinityboth have typeFloat -> BoolHere's several oddities/inconsistencies about those:
1divided by0is0is very strange. (2.)0on integers", namely%, but returning a result for another form of "mod division by0on integers", namelyrem, is inconsistent. (3. vs. 4.)NaNof typeInt, but not having the possibility of checking forNaNon typeInt, seems broken design. (4. and 5.)I propose to change the definitions of
//,%,isNaNandisInfinitysuch that:1 / 0results inInfinity(typeFloat, as before)1 // 0results inInfinity(typeInt, adapted behavior)1 % 0results inNaN(typeInt, adapted behavior)1rem0results inNaN(typeInt, as before)isNaNandisInfinityboth have typenumber -> Bool(generalized types, to be applicable to bothFloatandInt)In addition to better consistency, and correcting a mathematical wrongness (
1 // 0 = 0), this would have benefits in terms of efficiency, since//and%are currently performing extra checks on each invocation that would then go away.