digitalmars.D - Eliminate the baroque floating-point operators a la !<>=
- Andrei Alexandrescu (24/24) May 17 2009 Hello,
- Denis Koroskin (3/27) May 17 2009 Does anyone other than Don uses them at all?
- div0 (15/56) May 17 2009 -----BEGIN PGP SIGNED MESSAGE-----
- Don (17/58) May 17 2009 Sad to say, I mostly only use !<>=, and that's because it's defined in
- Andrei Alexandrescu (3/7) May 17 2009 So is it ok to yank them?
- Don (10/19) May 18 2009 Yes if and only if we get agreement from Tango that tango2.math can use
- dsimcha (28/52) May 17 2009 I personally would like to see the whole NaNs not having a defined order...
- Don (8/40) May 17 2009 Agreed. It's quite ridiculous that x==x fails for some values of x
- BCS (4/7) May 17 2009 But math deals with numbers (for the most part) and as the name says NaN...
- grauzone (2/2) May 17 2009 By the way, why is it that the is operator has the same behavior as ==
- Andrei Alexandrescu (6/53) May 17 2009 Yah, there was a discussion on the C++ standardization mailing list too....
- Jason House (2/38) May 17 2009 I like the concept of NaN-aware operators, but IMHO, the most common ope...
- Michiel Helvensteijn (30/42) May 17 2009 Actually, I like the concept of comparison operators for partial orders.
- Michiel Helvensteijn (6/11) May 17 2009 Hm, I now realise this may be a problem for D, since it uses == for equa...
- Lionello Lunesu (10/11) May 18 2009 It's an old wish of mine that this be used for the invocation of opCmp
Hello, I think the floating-point operators: a !<>= b a !<> b a <> b a <>= b a !> b a !>= b a !< b a !<= b are useless. A simple peephole optimization in the compiler can automatically rewrite NaN test followed by regular operations into the operations above, for example: isNaN(a) || isNan(b) || a >= b is the same as a !< b This is in keeping with what the compiler does when seeing code like: a = x / y; b = x % y; There's a peephole optimization that groups the / and the % together into an assembler operation that does both. If this is the way to go, we better be congruent and use explicit isNaN tests (that are then optimized) instead of defining eight extra operators. Andrei
May 17 2009
On Sun, 17 May 2009 21:14:46 +0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Hello, I think the floating-point operators: a !<>= b a !<> b a <> b a <>= b a !> b a !>= b a !< b a !<= b are useless. A simple peephole optimization in the compiler can automatically rewrite NaN test followed by regular operations into the operations above, for example: isNaN(a) || isNan(b) || a >= b is the same as a !< b This is in keeping with what the compiler does when seeing code like: a = x / y; b = x % y; There's a peephole optimization that groups the / and the % together into an assembler operation that does both. If this is the way to go, we better be congruent and use explicit isNaN tests (that are then optimized) instead of defining eight extra operators. AndreiDoes anyone other than Don uses them at all? I don't care if they are removed from D.
May 17 2009
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Denis Koroskin wrote:On Sun, 17 May 2009 21:14:46 +0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:+vote Me too. isNaN is a lot easier to read. - -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFKEEiET9LetA9XoXwRAiyPAJ9CaZhm8eLuvzwmbsGtDiboEzz+qACfR9kD AvlFq15dYJO91X6vyLkvJMw= =J5dd -----END PGP SIGNATURE-----Hello, I think the floating-point operators: a !<>= b a !<> b a <> b a <>= b a !> b a !>= b a !< b a !<= b are useless. A simple peephole optimization in the compiler can automatically rewrite NaN test followed by regular operations into the operations above, for example: isNaN(a) || isNan(b) || a >= b is the same as a !< b This is in keeping with what the compiler does when seeing code like: a = x / y; b = x % y; There's a peephole optimization that groups the / and the % together into an assembler operation that does both. If this is the way to go, we better be congruent and use explicit isNaN tests (that are then optimized) instead of defining eight extra operators. AndreiDoes anyone other than Don uses them at all? I don't care if they are removed from D.
May 17 2009
Denis Koroskin wrote:On Sun, 17 May 2009 21:14:46 +0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Sad to say, I mostly only use !<>=, and that's because it's defined in the language so that it works at compile time (and is unaffected by the Tango/Phobos incompatibility problem). Also x!=x works just as well as an isNaN test. The silly thing is, in asm, I would never use the equivalent comparison. In x86, for instance, a floating point < compare sets TWO flags; one for less, one for NaN. You almost always want to treat NaN specially, so you do one compare and two branches. The NCEG operators only really allow you to move all of the special cases into a single test, but you end up doing a second comparison anyway, so it doesn't really buy you very much at all. Inclusion of the NCEG operators was a bit of tokenism, making a _very_ strong statement that D took numerical programmers seriously. But I think D's at the point where it can make that statement without relying on tokenism. Don.Hello, I think the floating-point operators: a !<>= b a !<> b a <> b a <>= b a !> b a !>= b a !< b a !<= b are useless. A simple peephole optimization in the compiler can automatically rewrite NaN test followed by regular operations into the operations above, for example: isNaN(a) || isNan(b) || a >= b is the same as a !< b This is in keeping with what the compiler does when seeing code like: a = x / y; b = x % y; There's a peephole optimization that groups the / and the % together into an assembler operation that does both. If this is the way to go, we better be congruent and use explicit isNaN tests (that are then optimized) instead of defining eight extra operators. AndreiDoes anyone other than Don uses them at all? I don't care if they are removed from D.
May 17 2009
Don wrote:Inclusion of the NCEG operators was a bit of tokenism, making a _very_ strong statement that D took numerical programmers seriously. But I think D's at the point where it can make that statement without relying on tokenism.So is it ok to yank them? Andrei
May 17 2009
Andrei Alexandrescu wrote:Don wrote:Yes if and only if we get agreement from Tango that tango2.math can use std.math. There's one other minor issue: isNaN() isn't supposed to trigger on signalling NaNs, but !<>= should trigger them. I'm not sure that _anyone_ actually cares about this difference (you can use isSignallingNaN() in the rare case where you don't want to trigger it), but it would be a difference from IEEE if we signalled when isNaN() is called, which is what would happen if we recreated the !<>= operators by merging isNaN with <,>, =.Inclusion of the NCEG operators was a bit of tokenism, making a _very_ strong statement that D took numerical programmers seriously. But I think D's at the point where it can make that statement without relying on tokenism.So is it ok to yank them? Andrei
May 18 2009
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s articleHello, I think the floating-point operators: a !<>= b a !<> b a <> b a <>= b a !> b a !>= b a !< b a !<= b are useless. A simple peephole optimization in the compiler can automatically rewrite NaN test followed by regular operations into the operations above, for example: isNaN(a) || isNan(b) || a >= b is the same as a !< b This is in keeping with what the compiler does when seeing code like: a = x / y; b = x % y; There's a peephole optimization that groups the / and the % together into an assembler operation that does both. If this is the way to go, we better be congruent and use explicit isNaN tests (that are then optimized) instead of defining eight extra operators. AndreiI personally would like to see the whole NaNs not having a defined ordering thing done away with entirely. This probably won't happen b/c it's (I would guess) in the IEEE standard. However, the fact that a NaN is not less than, equal to, or greater than, anything creates an extremely annoying special case when doing generic programming for anything that requires a total ordering, such as trees and sorting. Sorting, trees, etc. require a consistent total ordering, and NaNs mean that, technically, floating point numbers don't have one. This means that any generic tree or sorting code that doesn't deal with this as a special case somehow is technically broken, or, if you look at it differently, these algorithms are invalid for floating point numbers. For example, try the following code in release mode (in debug mode, an assert fails). import std.stdio, std.algorithm, std.random; void main() { double[] foo = new double[20]; foreach(i, ref elem; foo) { elem = (i & 1) ? double.nan : i; } randomShuffle(foo); sort(foo); writeln(foo); } This is enough of a corner case that, in most of the generic code I write, I consider anything that expects a total ordering to just have completely undefined behavior when there isn't one, but this is obviously not an optimal solution. I actually prefer not to know what some of my code does when given a range of floats with a bunch of NaNs.
May 17 2009
dsimcha wrote:== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s articleAgreed. It's quite ridiculous that x==x fails for some values of x (namely NaN). On this NG, I've mentioned the rationale for why that is (eg, if NaN==NaN, then sqrt(-4) == sqrt(-9)). But unfortunately, in solving an obscure corner case, the IEEE standard destroyed one of the most basic axioms in mathematics. It's one of those things that Seemed Like A Good Idea At The Time. The cure is a millions times worse than the disease. But it's in hardware, so it's Too Late Now.Hello, I think the floating-point operators: a !<>= b a !<> b a <> b a <>= b a !> b a !>= b a !< b a !<= b are useless. A simple peephole optimization in the compiler can automatically rewrite NaN test followed by regular operations into the operations above, for example: isNaN(a) || isNan(b) || a >= b is the same as a !< b This is in keeping with what the compiler does when seeing code like: a = x / y; b = x % y; There's a peephole optimization that groups the / and the % together into an assembler operation that does both. If this is the way to go, we better be congruent and use explicit isNaN tests (that are then optimized) instead of defining eight extra operators. AndreiI personally would like to see the whole NaNs not having a defined ordering thing done away with entirely. This probably won't happen b/c it's (I would guess) in the IEEE standard. However, the fact that a NaN is not less than, equal to, or greater than, anything creates an extremely annoying special case when doing generic programming for anything that requires a total ordering, such as trees and sorting.
May 17 2009
Hello Don,But unfortunately, in solving an obscure corner case, the IEEE standard destroyed one of the most basic axioms in mathematics.But math deals with numbers (for the most part) and as the name says NaN is Not a Numebr. (Not that I think it is or isn't a bad idea, I'm not in a position to know.)
May 17 2009
By the way, why is it that the is operator has the same behavior as == regarding NaNs? IMHO is should just compare the values bitwise.
May 17 2009
Don wrote:dsimcha wrote:Yah, there was a discussion on the C++ standardization mailing list too. It turns out that x == x is a pretty fundamental concept and if a type as common as float breaks it with panache, then it's pretty complicated to change language fundaments to account for such a case. Andrei== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s articleAgreed. It's quite ridiculous that x==x fails for some values of x (namely NaN). On this NG, I've mentioned the rationale for why that is (eg, if NaN==NaN, then sqrt(-4) == sqrt(-9)). But unfortunately, in solving an obscure corner case, the IEEE standard destroyed one of the most basic axioms in mathematics. It's one of those things that Seemed Like A Good Idea At The Time. The cure is a millions times worse than the disease. But it's in hardware, so it's Too Late Now.Hello, I think the floating-point operators: a !<>= b a !<> b a <> b a <>= b a !> b a !>= b a !< b a !<= b are useless. A simple peephole optimization in the compiler can automatically rewrite NaN test followed by regular operations into the operations above, for example: isNaN(a) || isNan(b) || a >= b is the same as a !< b This is in keeping with what the compiler does when seeing code like: a = x / y; b = x % y; There's a peephole optimization that groups the / and the % together into an assembler operation that does both. If this is the way to go, we better be congruent and use explicit isNaN tests (that are then optimized) instead of defining eight extra operators. AndreiI personally would like to see the whole NaNs not having a defined ordering thing done away with entirely. This probably won't happen b/c it's (I would guess) in the IEEE standard. However, the fact that a NaN is not less than, equal to, or greater than, anything creates an extremely annoying special case when doing generic programming for anything that requires a total ordering, such as trees and sorting.
May 17 2009
Andrei Alexandrescu Wrote:Hello, I think the floating-point operators: a !<>= b a !<> b a <> b a <>= b a !> b a !>= b a !< b a !<= b are useless. A simple peephole optimization in the compiler can automatically rewrite NaN test followed by regular operations into the operations above, for example: isNaN(a) || isNan(b) || a >= b is the same as a !< b This is in keeping with what the compiler does when seeing code like: a = x / y; b = x % y; There's a peephole optimization that groups the / and the % together into an assembler operation that does both. If this is the way to go, we better be congruent and use explicit isNaN tests (that are then optimized) instead of defining eight extra operators. AndreiI like the concept of NaN-aware operators, but IMHO, the most common operators are prone to misuse. If D moves for the peephole optimizations, I'd request a function called ordered(a,b) in addition to isNaN(a). Non-nullable and non-nanable types would be handy...
May 17 2009
Andrei Alexandrescu wrote:I think the floating-point operators: a !<>= b a !<> b a <> b a <>= b a !> b a !>= b a !< b a !<= b are useless.Actually, I like the concept of comparison operators for partial orders. When I first read the D1 specs, this set of operators was one of the features I especially liked. However, at the time I didn't realise they were solely for floating point numbers. They would make more sense if they could be overloaded. For example, they can be used for multi-objective optimization. With more than one objective, you need a way to express comparability of two potential solutions (<>= means comparable). They would be good for expressing the subset relation, where < is the strict subset relation and A <>= B would express that one of A and B is a subset of the other. Logically, they would be defined for the Boolean truth-values. False and true are incomparable to each other, but equal to themselves. And for those people that don't (want to) know about all of these extra operators, they don't have to. What's more, when it comes to integers, <> and != are equivalent, which is nice for those programmers that are familiar with one, but not the other. There's this thing, though. I would make it so !(a op b) is equivalent to (a !op b). It's a nice property. The IEEE standard requires that you set a certain exception flag when comparing with a NaN value, right? Well, just set the flag with the extra operators as well. The !(a op b) = (a !op b) thing can even be extended to the and/or/xor operators. I know that most of these operators don't make sense with integers and booleans. But you can give a compiler warning when you have a comparison with a predictable return value. In fact, everything I've said here is part of the Mist programming language. Inspired by D's example. :-) -- Michiel Helvensteijn
May 17 2009
Michiel Helvensteijn wrote:There's this thing, though. I would make it so !(a op b) is equivalent to (a !op b). It's a nice property. The IEEE standard requires that you set a certain exception flag when comparing with a NaN value, right? Well, just set the flag with the extra operators as well. The !(a op b) = (a !op b) thing can even be extended to the and/or/xor operators.Hm, I now realise this may be a problem for D, since it uses == for equality and != for non-equality. A consequence of using = for assignment, one of the most irritating backwards-C-compatibility things ever. -- Michiel Helvensteijn
May 17 2009
a <> bIt's an old wish of mine that this be used for the invocation of opCmp (instead of opEquals), returning an int, and valid for struct/class/built-ins/etc... (like perl's <=>, I think) As for the other operators, I never used them and I don't think I would use them ever often enough to remember what operator had what function. Using isNan sure is more clear and therefor safer :) As per Don's comment, the compiler would just have to remember that after a comparison the NaN flag is still correctly set and any isNan() could simply be skipped, resulting in only an additional branch instruction! L.
May 18 2009