www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - More on semantics of opPow: return type

reply Don <nospam nospam.com> writes:
As has been mentioned in previous posts, a ^^ b should be right 
associative and have a precedence between multiplication and unary 
operators. That much is clear.


Operations involving integers are far less obvious (and are actually 
where a major benefit of an operator can come in).

Using the normal promotion rules, 10^^2 is an integer. The range 
checking already present in D2 could be extended so that the compiler 
knows it'll even fit in a byte. This gets rid of one of the classic 
annoyances of C pow:  int x = pow(2, 10); doesn't compile without a cast.

But the difficult question is, what's the type of 10^^-2 ? Should it be 
an error? (since the result, 0.01, is not representable as an integer). 
Should it return zero? (just as 1/2 doesn't return 0.5). For an example 
of these semantics, see http://www.tcl.tk/cgi-bin/tct/tip/123.html).
Or should it return a double?
Or should 10^^2 also be a double, but implicitly castable to byte 
because of the range checking rules?

I currently favour making it an error, so that the normal promotion 
rules apply. It seems reasonable to me to require a cast to floating 
point in there somewhere.
This is analagous to the similar case f ^^ 0.1; where f is known to be 
negative. This gives a complex result, creating a run-time error 
(returns a NaN). But, there's no standard error and no NaNs for integer 
underflow.

One could also make int ^^ uint defined (returning an int), but not int 
^^ int. Again thanks to range checking, int ^^ uint ^^ uint would work, 
because although uint ^^ uint is an int, it's known to be positive, so 
would implicitly convert to int. But would making int ^^ int illegal, 
make it too much of an annoying special case?

I strongly suspect that x^^y, where x and y are integers, and the value 
of y is not known at compile time, is an extremely rare operation.

Also, should int^^uint generate some kind of overflow error? Although 
other arithmeic integer operators don't, it's fantastically easy to hit 
an overflow with x^^y. Unless x is 1, y must be tiny (< 64 to avoid 
overflowing a ulong).
Dec 07 2009
next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
On Mon, 07 Dec 2009 13:13:34 +0100, Don <nospam nospam.com> wrote:

 As has been mentioned in previous posts, a ^^ b should be right  
 associative and have a precedence between multiplication and unary  
 operators. That much is clear.


 Operations involving integers are far less obvious (and are actually  
 where a major benefit of an operator can come in).

 Using the normal promotion rules, 10^^2 is an integer. The range  
 checking already present in D2 could be extended so that the compiler  
 knows it'll even fit in a byte. This gets rid of one of the classic  
 annoyances of C pow:  int x = pow(2, 10); doesn't compile without a cast.

 But the difficult question is, what's the type of 10^^-2 ? Should it be  
 an error? (since the result, 0.01, is not representable as an integer).  
 Should it return zero? (just as 1/2 doesn't return 0.5). For an example  
 of these semantics, see http://www.tcl.tk/cgi-bin/tct/tip/123.html).
 Or should it return a double?
 Or should 10^^2 also be a double, but implicitly castable to byte  
 because of the range checking rules?

 I currently favour making it an error, so that the normal promotion  
 rules apply. It seems reasonable to me to require a cast to floating  
 point in there somewhere.
 This is analagous to the similar case f ^^ 0.1; where f is known to be  
 negative. This gives a complex result, creating a run-time error  
 (returns a NaN). But, there's no standard error and no NaNs for integer  
 underflow.

 One could also make int ^^ uint defined (returning an int), but not int  
 ^^ int. Again thanks to range checking, int ^^ uint ^^ uint would work,  
 because although uint ^^ uint is an int, it's known to be positive, so  
 would implicitly convert to int. But would making int ^^ int illegal,  
 make it too much of an annoying special case?

 I strongly suspect that x^^y, where x and y are integers, and the value  
 of y is not known at compile time, is an extremely rare operation.

 Also, should int^^uint generate some kind of overflow error? Although  
 other arithmeic integer operators don't, it's fantastically easy to hit  
 an overflow with x^^y. Unless x is 1, y must be tiny (< 64 to avoid  
 overflowing a ulong).

I believe int^^int should not be defined (it's basically useless, as one would (almost) always want an integer result, and a float result could easily be had by casting). As regards n^^(x >= n.sizeof * 8), I'm not 100% sure. I'm leaning towards only allowing int^^ubyte, but it seems constraining. -- Simen
Dec 07 2009
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Don wrote:
 As has been mentioned in previous posts, a ^^ b should be right 
 associative and have a precedence between multiplication and unary 
 operators. That much is clear.
 
 
 Operations involving integers are far less obvious (and are actually 
 where a major benefit of an operator can come in).
 
 Using the normal promotion rules, 10^^2 is an integer. The range 
 checking already present in D2 could be extended so that the compiler 
 knows it'll even fit in a byte. This gets rid of one of the classic 
 annoyances of C pow:  int x = pow(2, 10); doesn't compile without a cast.
 
 But the difficult question is, what's the type of 10^^-2 ? Should it be 
 an error? (since the result, 0.01, is not representable as an integer). 
 Should it return zero? (just as 1/2 doesn't return 0.5). For an example 
 of these semantics, see http://www.tcl.tk/cgi-bin/tct/tip/123.html).
 Or should it return a double?
 Or should 10^^2 also be a double, but implicitly castable to byte 
 because of the range checking rules?
 
 I currently favour making it an error, so that the normal promotion 
 rules apply. It seems reasonable to me to require a cast to floating 
 point in there somewhere.
 This is analagous to the similar case f ^^ 0.1; where f is known to be 
 negative. This gives a complex result, creating a run-time error 
 (returns a NaN). But, there's no standard error and no NaNs for integer 
 underflow.
 
 One could also make int ^^ uint defined (returning an int), but not int 
 ^^ int. Again thanks to range checking, int ^^ uint ^^ uint would work, 
 because although uint ^^ uint is an int, it's known to be positive, so 
 would implicitly convert to int. But would making int ^^ int illegal, 
 make it too much of an annoying special case?
 
 I strongly suspect that x^^y, where x and y are integers, and the value 
 of y is not known at compile time, is an extremely rare operation.
 
 Also, should int^^uint generate some kind of overflow error? Although 
 other arithmeic integer operators don't, it's fantastically easy to hit 
 an overflow with x^^y. Unless x is 1, y must be tiny (< 64 to avoid 
 overflowing a ulong).

Nice analysis. IMHO this should lead us to reconsider the necessity of "^^" in the first place. It seems to be adding too little real value compared to the complexity of defining it. Andrei
Dec 07 2009
next sibling parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Andrei Alexandrescu wrote:
 Don wrote:
 As has been mentioned in previous posts, a ^^ b should be right 
 associative and have a precedence between multiplication and unary 
 operators. That much is clear.


 Operations involving integers are far less obvious (and are actually 
 where a major benefit of an operator can come in).

 Using the normal promotion rules, 10^^2 is an integer. The range 
 checking already present in D2 could be extended so that the compiler 
 knows it'll even fit in a byte. This gets rid of one of the classic 
 annoyances of C pow:  int x = pow(2, 10); doesn't compile without a cast.

 But the difficult question is, what's the type of 10^^-2 ? Should it 
 be an error? (since the result, 0.01, is not representable as an 
 integer). Should it return zero? (just as 1/2 doesn't return 0.5). For 
 an example of these semantics, see 
 http://www.tcl.tk/cgi-bin/tct/tip/123.html).
 Or should it return a double?
 Or should 10^^2 also be a double, but implicitly castable to byte 
 because of the range checking rules?

 I currently favour making it an error, so that the normal promotion 
 rules apply. It seems reasonable to me to require a cast to floating 
 point in there somewhere.
 This is analagous to the similar case f ^^ 0.1; where f is known to be 
 negative. This gives a complex result, creating a run-time error 
 (returns a NaN). But, there's no standard error and no NaNs for 
 integer underflow.

 One could also make int ^^ uint defined (returning an int), but not 
 int ^^ int. Again thanks to range checking, int ^^ uint ^^ uint would 
 work, because although uint ^^ uint is an int, it's known to be 
 positive, so would implicitly convert to int. But would making int ^^ 
 int illegal, make it too much of an annoying special case?

 I strongly suspect that x^^y, where x and y are integers, and the 
 value of y is not known at compile time, is an extremely rare operation.

 Also, should int^^uint generate some kind of overflow error? Although 
 other arithmeic integer operators don't, it's fantastically easy to 
 hit an overflow with x^^y. Unless x is 1, y must be tiny (< 64 to 
 avoid overflowing a ulong).

Nice analysis. IMHO this should lead us to reconsider the necessity of "^^" in the first place. It seems to be adding too little real value compared to the complexity of defining it. Andrei

It adds a lot of value to the ones that actually use it, even though you may not be one of them. Exponentiation is extremely common in numerics. Here are some statistics for you: A Google code search (see below) for FORTRAN code using the power operator **, which until recently didn't have a D equivalent, yields roughly 56100 results. A search for the FORTRAN equivalents of << yield 400 results for ILS() and 276 results for LSHIFT(). Yet, left shift apparently deserves a place in D. (I've used http://www.google.com/codesearch, with the following search strings for **, ILS and LSHIFT, respectively: [0-9a-zA-Z)]\*\*[0-9a-zA-Z(] lang:fortran ils\([0-9a-zA-Z] lang:fortran lshift\([0-9a-zA-Z] lang:fortran As statistics go, this is probably not a prime example, but it is at least an indication.) -Lars
Dec 07 2009
next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Lars T. Kyllingstad wrote:
 Andrei Alexandrescu wrote:
 Don wrote:
 As has been mentioned in previous posts, a ^^ b should be right 
 associative and have a precedence between multiplication and unary 
 operators. That much is clear.


 Operations involving integers are far less obvious (and are actually 
 where a major benefit of an operator can come in).

 Using the normal promotion rules, 10^^2 is an integer. The range 
 checking already present in D2 could be extended so that the compiler 
 knows it'll even fit in a byte. This gets rid of one of the classic 
 annoyances of C pow:  int x = pow(2, 10); doesn't compile without a 
 cast.

 But the difficult question is, what's the type of 10^^-2 ? Should it 
 be an error? (since the result, 0.01, is not representable as an 
 integer). Should it return zero? (just as 1/2 doesn't return 0.5). 
 For an example of these semantics, see 
 http://www.tcl.tk/cgi-bin/tct/tip/123.html).
 Or should it return a double?
 Or should 10^^2 also be a double, but implicitly castable to byte 
 because of the range checking rules?

 I currently favour making it an error, so that the normal promotion 
 rules apply. It seems reasonable to me to require a cast to floating 
 point in there somewhere.
 This is analagous to the similar case f ^^ 0.1; where f is known to 
 be negative. This gives a complex result, creating a run-time error 
 (returns a NaN). But, there's no standard error and no NaNs for 
 integer underflow.

 One could also make int ^^ uint defined (returning an int), but not 
 int ^^ int. Again thanks to range checking, int ^^ uint ^^ uint would 
 work, because although uint ^^ uint is an int, it's known to be 
 positive, so would implicitly convert to int. But would making int ^^ 
 int illegal, make it too much of an annoying special case?

 I strongly suspect that x^^y, where x and y are integers, and the 
 value of y is not known at compile time, is an extremely rare operation.

 Also, should int^^uint generate some kind of overflow error? Although 
 other arithmeic integer operators don't, it's fantastically easy to 
 hit an overflow with x^^y. Unless x is 1, y must be tiny (< 64 to 
 avoid overflowing a ulong).

Nice analysis. IMHO this should lead us to reconsider the necessity of "^^" in the first place. It seems to be adding too little real value compared to the complexity of defining it. Andrei

It adds a lot of value to the ones that actually use it, even though you may not be one of them. Exponentiation is extremely common in numerics. Here are some statistics for you: A Google code search (see below) for FORTRAN code using the power operator **, which until recently didn't have a D equivalent, yields roughly 56100 results. A search for the FORTRAN equivalents of << yield 400 results for ILS() and 276 results for LSHIFT(). Yet, left shift apparently deserves a place in D.

FORTRAN also has the ISHFT() shift function, which gives about 2000 results on Google. Still way less than for **.
 (I've used http://www.google.com/codesearch, with the following search 
 strings for **, ILS and LSHIFT, respectively:
 
     [0-9a-zA-Z)]\*\*[0-9a-zA-Z(] lang:fortran
     ils\([0-9a-zA-Z] lang:fortran
     lshift\([0-9a-zA-Z] lang:fortran

ishft\([0-9a-zA-Z] lang:fortran -Lars
Dec 07 2009
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Lars T. Kyllingstad wrote:
 Andrei Alexandrescu wrote:
 Nice analysis. IMHO this should lead us to reconsider the necessity of 
 "^^" in the first place. It seems to be adding too little real value 
 compared to the complexity of defining it.

 Andrei

It adds a lot of value to the ones that actually use it, even though you may not be one of them. Exponentiation is extremely common in numerics.

Well I write numerics and I do use exponentiation occasionally, but never to the extent of yearning for ^^. "Extremely common" would be, I think, quite difficult to argue.
 Here are some statistics for you: A Google code search (see below) for 
 FORTRAN code using the power operator **, which until recently didn't 
 have a D equivalent, yields roughly 56100 results.
 
 A search for the FORTRAN equivalents of << yield 400 results for ILS() 
 and 276 results for LSHIFT(). Yet, left shift apparently deserves a 
 place in D.
 
 
 (I've used http://www.google.com/codesearch, with the following search 
 strings for **, ILS and LSHIFT, respectively:
 
     [0-9a-zA-Z)]\*\*[0-9a-zA-Z(] lang:fortran
     ils\([0-9a-zA-Z] lang:fortran
     lshift\([0-9a-zA-Z] lang:fortran
 
 As statistics go, this is probably not a prime example, but it is at 
 least an indication.)

Thanks for collecting the evidence. To make it more meaningful, you may want to report it to the total number of lines of code searched. I don't know how to do that with codesearch. FWIW, this search: [0-9a-zA-Z)]\*\*[013456789a-zA-Z(] lang:fortran yields 30,300 results, meaning that almost half the uses of exponentiation is to square things. So I'm not sure what this all is supposed to argue for or against. What I can say is that Don's analysis suggested to me, let's leave all that aggravation to overloads of pow() and call it a day. I was much more in favor of ^^ before I saw how quickly it gets complicated. That kind of stuff just doesn't strike me as the kind of things you put straight in the core language. Andrei
Dec 07 2009
next sibling parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Andrei Alexandrescu wrote:
 Lars T. Kyllingstad wrote:
 Andrei Alexandrescu wrote:
 Nice analysis. IMHO this should lead us to reconsider the necessity 
 of "^^" in the first place. It seems to be adding too little real 
 value compared to the complexity of defining it.

 Andrei

It adds a lot of value to the ones that actually use it, even though you may not be one of them. Exponentiation is extremely common in numerics.

Well I write numerics and I do use exponentiation occasionally, but never to the extent of yearning for ^^. "Extremely common" would be, I think, quite difficult to argue.

Yeah, I get a little carried away. The point I was trying to make is that it's not as uncommon as some would have it. The fundamental reason why I want opPow so badly is in fact not even how often I use it. If that was the case, I'd want a special "writefln" operator as well. The main reason is that exponentiation is such a basic mathematical operation, right up there with addition and multiplication, that it deserves an operator of its own. I also seem to remember someone (was it Don or bearophile, perhaps?) listing various optimisation possibilities that are more readily available if ^^ is a built-in operator.
 Here are some statistics for you: A Google code search (see below) for 
 FORTRAN code using the power operator **, which until recently didn't 
 have a D equivalent, yields roughly 56100 results.

 A search for the FORTRAN equivalents of << yield 400 results for ILS() 
 and 276 results for LSHIFT(). Yet, left shift apparently deserves a 
 place in D.


 (I've used http://www.google.com/codesearch, with the following search 
 strings for **, ILS and LSHIFT, respectively:

     [0-9a-zA-Z)]\*\*[0-9a-zA-Z(] lang:fortran
     ils\([0-9a-zA-Z] lang:fortran
     lshift\([0-9a-zA-Z] lang:fortran

 As statistics go, this is probably not a prime example, but it is at 
 least an indication.)

Thanks for collecting the evidence. To make it more meaningful, you may want to report it to the total number of lines of code searched. I don't know how to do that with codesearch. FWIW, this search: [0-9a-zA-Z)]\*\*[013456789a-zA-Z(] lang:fortran yields 30,300 results, meaning that almost half the uses of exponentiation is to square things.

...which is still a valid use case, since foo*foo evaluates foo twice and square(foo) is no better than pow(foo, 2).
 So I'm not sure what this all is supposed to argue for or against. What 
 I can say is that Don's analysis suggested to me, let's leave all that 
 aggravation to overloads of pow() and call it a day. I was much more in 
 favor of ^^ before I saw how quickly it gets complicated. That kind of 
 stuff just doesn't strike me as the kind of things you put straight in 
 the core language.

You could say the same for arrays. T[new] and ~=, anyone? ;) -Lars
Dec 07 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Lars T. Kyllingstad:
 I also seem to remember someone (was it Don or bearophile, perhaps?) 
 listing various optimisation possibilities that are more readily 
 available if ^^ is a built-in operator.

It was Don, I think. Those optimizations can be done with the pow, ipow and cpow (real, integer, complex, this is just an idea) functions too. GCC for example simplifies cases when the exponent is 2 or 3 (that are the most common): // C code #include "stdio.h" #include "math.h" #include "stdlib.h" int main() { int x = atoi("100"); printf("%f\n", pow(x, 2)); return 0; } Compiled with: gcc version 4.3.3-dw2-tdm-1 (GCC) gcc -Wall -S -O3 test2.c -o test2.s ... call _atoi pushl %eax fildl (%esp) addl $4, %esp fmul %st(0), %st movl $LC1, (%esp) fstpl 4(%esp) call _printf ... Some weeks ago I have filed a bug asking for a similar optimization in LLVM too (so LDC too will have it). Bye, bearophile
Dec 07 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Bill Baxter:

 Holy smokes!  You actually file bugs in the LLVM database?!

Don't ask me why. Eleven so far, you can't find five of them because in the beginning another person has filed them for me in a strange way. LLVM devs have asked me so many times, on IRC. One of those performance bugs has already being half-fixed, with nice results: http://llvm.org/bugs/show_bug.cgi?id=5501 I feel dumb, I understand nearly nothing of what they do and how they do it, it's another (higher) level... I may be fit as their jester. Bye, bearophile
Dec 07 2009
parent Justin Johansson <no spam.com> writes:
bearophile wrote:
 Bill Baxter:
 
 Holy smokes!  You actually file bugs in the LLVM database?!

Don't ask me why. Eleven so far, you can't find five of them because in the beginning another person has filed them for me in a strange way. LLVM devs have asked me so many times, on IRC. One of those performance bugs has already being half-fixed, with nice results: http://llvm.org/bugs/show_bug.cgi?id=5501 I feel dumb, I understand nearly nothing of what they do and how they do it, it's another (higher) level... I may be fit as their jester. Bye, bearophile

Of all the people in this newsgroup, I would have to say that you, bearophile, would have to be one of the most polite writers and most entertaining as well. It's always a pleasure to read your posts :-) Beers, Justin Johansson
Dec 08 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Lars T. Kyllingstad wrote:
 The fundamental reason why I want opPow so badly is in fact not even how 
 often I use it. If that was the case, I'd want a special "writefln" 
 operator as well. The main reason is that exponentiation is such a basic 
 mathematical operation, right up there with addition and multiplication, 
 that it deserves an operator of its own.

Hmmm. Addition, subtraction, multiplication, and division with remainder are all closed over integers. Power isn't. It's not even closed over real numbers. That makes it quite special and quite non-basic. The more I hear, the more I'm convinced ^^ is just not worth it. And again: I initially liked the idea. Andrei
Dec 07 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Bill Baxter wrote:
 On Mon, Dec 7, 2009 at 2:30 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 Lars T. Kyllingstad wrote:
 The fundamental reason why I want opPow so badly is in fact not even how
 often I use it. If that was the case, I'd want a special "writefln" operator
 as well. The main reason is that exponentiation is such a basic mathematical
 operation, right up there with addition and multiplication, that it deserves
 an operator of its own.

all closed over integers. Power isn't. It's not even closed over real numbers. That makes it quite special and quite non-basic.

Uh, but a/b is not a "division with remainder" operator. It's just division-with-a-remainder-silently-ignored.

The result of a/b is the quotient resulting from a division with remainder. If you want the remainder use a%b (the compiler will peephole-optimize that). I don't see anything wrong with what I said.
 If you want to define pow in the same way as a "pow with remainder but
 with the remainder ignored" then there's nothing stopping you.
 
     1^^-1 == 1
     2^^-1 == 0
     4^^(1/2) == 2
     5^^(1/2) == 2
 
 Though I'd rather go the other direction and make the
 remainder-dropping integer division use a different symbol a la
 Python.

You'd need to show that "power with remainder" as you just defined it is useful theoretically and/or practically. The usefulness of integral division is absolutely massive. Anyhow, all I did was to explain that a particular argument that was made is invalid. That doesn't mean other arguments are invalid. All I'd hope is that ^^ doesn't suddenly become a time sink when we have so much other stuff to worry about. Again: ^^ was a lot more attractive to me when it seemed like a slam dunk. Andrei
Dec 07 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Bill Baxter wrote:
 On Mon, Dec 7, 2009 at 2:56 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 Bill Baxter wrote:
 On Mon, Dec 7, 2009 at 2:30 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 Lars T. Kyllingstad wrote:
 The fundamental reason why I want opPow so badly is in fact not even how
 often I use it. If that was the case, I'd want a special "writefln"
 operator
 as well. The main reason is that exponentiation is such a basic
 mathematical
 operation, right up there with addition and multiplication, that it
 deserves
 an operator of its own.

are all closed over integers. Power isn't. It's not even closed over real numbers. That makes it quite special and quite non-basic.

division-with-a-remainder-silently-ignored.

If you want the remainder use a%b (the compiler will peephole-optimize that). I don't see anything wrong with what I said.
 If you want to define pow in the same way as a "pow with remainder but
 with the remainder ignored" then there's nothing stopping you.

    1^^-1 == 1
    2^^-1 == 0
    4^^(1/2) == 2
    5^^(1/2) == 2

 Though I'd rather go the other direction and make the
 remainder-dropping integer division use a different symbol a la
 Python.

useful theoretically and/or practically. The usefulness of integral division is absolutely massive. Anyhow, all I did was to explain that a particular argument that was made is invalid. That doesn't mean other arguments are invalid. All I'd hope is that ^^ doesn't suddenly become a time sink when we have so much other stuff to worry about. Again: ^^ was a lot more attractive to me when it seemed like a slam dunk.

Seriously, I thought the above behavior would be what you'd get using integer arguments with opPow by analogy with how opDiv behaves. I wasn't expecting there would be any debate about it. I think the feeling that 2^^-1 is not 0 is the same gut feeling that tells all programming newbies that 1/2 should not be 0. But truncating down to the nearest int was the decision made long ago, so we stick with it. But languages like python that cater to newbie programmers are now trying to do something about it by making the difference between truncated integer division and division explicit. I don't really think D is going to go down that route at this late date, so we should just try to be self-consistent. Which to me says 1/2 and 2^^-1 should give the same result.

I understand where you're coming from. As an old math teacher would say, "this is true but uninteresting". You'd have to prove that that behavior of ^^ has some interesting math properties. For starters, you'd need a "remainder" for ^^. But then what kind of interesting things can you do with such a definition? Anyway, maybe things could reach an inflection point. Maybe Don will find some type trickery for ^^ that's very ingenious and very compiler-y. In that case, there would be a strong justification to build special rules for ^^ in the compiler instead of building an imperfect approximation of it with pow() overloads. Andrei
Dec 07 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Bill Baxter wrote:
 Negative exponent values are the only ones with an issue.  You can't
 even write square-root etc with pow using only integers.  The argument
 would have to be a float to even express that, so there is no issue.
 int^^float should be a float just like int/float is a float.

But -1^^0.5 is the imaginary constant! Something definitely doesn't add up. Are you sure you meant int^^float to be float? And what's the deal with the ongoing parallel exegesis with division? A division of reals doesn't result in a complex.
 So the only things left are those of the form  x^^-y.  or 1/(x^^y).  I
 don't see a reason to go any further than translating it to exactly
 that.
 And that's just division, so the %-like operator corresponding to that
 is just % itself ( or rather 1%(x^^y) )
 
 I think Don was creating a tempest in a teapot.  I don't think any of
 his proposed alternatives besides treating it as integer division
 really make sense.  They are inconsistent with the rest of D, and so
 don't merit further consideration unless the behavior of 1/2 is also
 on the table.

To quote a living classic, when disagreeing with Don, you better have your ducks in a row. Andrei
Dec 07 2009
prev sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, Dec 7, 2009 at 4:41 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 Bill Baxter wrote:
 Negative exponent values are the only ones with an issue. =A0You can't
 even write square-root etc with pow using only integers. =A0The argument
 would have to be a float to even express that, so there is no issue.
 int^^float should be a float just like int/float is a float.

But -1^^0.5 is the imaginary constant! Something definitely doesn't add u=

 Are you sure you meant int^^float to be float? And what's the deal with t=

 ongoing parallel exegesis with division? A division of reals doesn't resu=

 in a complex.

Don already covered that. Floats have nan, so that would be a nan.
 So the only things left are those of the form =A0x^^-y. =A0or 1/(x^^y). =


 don't see a reason to go any further than translating it to exactly
 that.
 And that's just division, so the %-like operator corresponding to that
 is just % itself ( or rather 1%(x^^y) )

 I think Don was creating a tempest in a teapot. =A0I don't think any of
 his proposed alternatives besides treating it as integer division
 really make sense. =A0They are inconsistent with the rest of D, and so
 don't merit further consideration unless the behavior of 1/2 is also
 on the table.

To quote a living classic, when disagreeing with Don, you better have you=

 ducks in a row.

Doin' my best here. --bb
Dec 07 2009
prev sibling parent reply KennyTM~ <kennytm gmail.com> writes:
On Dec 8, 09 03:03, Lars T. Kyllingstad wrote:
 Andrei Alexandrescu wrote:
 Don wrote:
 As has been mentioned in previous posts, a ^^ b should be right
 associative and have a precedence between multiplication and unary
 operators. That much is clear.


 Operations involving integers are far less obvious (and are actually
 where a major benefit of an operator can come in).

 Using the normal promotion rules, 10^^2 is an integer. The range
 checking already present in D2 could be extended so that the compiler
 knows it'll even fit in a byte. This gets rid of one of the classic
 annoyances of C pow: int x = pow(2, 10); doesn't compile without a cast.

 But the difficult question is, what's the type of 10^^-2 ? Should it
 be an error? (since the result, 0.01, is not representable as an
 integer). Should it return zero? (just as 1/2 doesn't return 0.5).
 For an example of these semantics, see
 http://www.tcl.tk/cgi-bin/tct/tip/123.html).
 Or should it return a double?
 Or should 10^^2 also be a double, but implicitly castable to byte
 because of the range checking rules?

 I currently favour making it an error, so that the normal promotion
 rules apply. It seems reasonable to me to require a cast to floating
 point in there somewhere.
 This is analagous to the similar case f ^^ 0.1; where f is known to
 be negative. This gives a complex result, creating a run-time error
 (returns a NaN). But, there's no standard error and no NaNs for
 integer underflow.

 One could also make int ^^ uint defined (returning an int), but not
 int ^^ int. Again thanks to range checking, int ^^ uint ^^ uint would
 work, because although uint ^^ uint is an int, it's known to be
 positive, so would implicitly convert to int. But would making int ^^
 int illegal, make it too much of an annoying special case?

 I strongly suspect that x^^y, where x and y are integers, and the
 value of y is not known at compile time, is an extremely rare operation.

 Also, should int^^uint generate some kind of overflow error? Although
 other arithmeic integer operators don't, it's fantastically easy to
 hit an overflow with x^^y. Unless x is 1, y must be tiny (< 64 to
 avoid overflowing a ulong).

Nice analysis. IMHO this should lead us to reconsider the necessity of "^^" in the first place. It seems to be adding too little real value compared to the complexity of defining it. Andrei

It adds a lot of value to the ones that actually use it, even though you may not be one of them. Exponentiation is extremely common in numerics. Here are some statistics for you: A Google code search (see below) for FORTRAN code using the power operator **, which until recently didn't have a D equivalent, yields roughly 56100 results. A search for the FORTRAN equivalents of << yield 400 results for ILS() and 276 results for LSHIFT(). Yet, left shift apparently deserves a place in D. (I've used http://www.google.com/codesearch, with the following search strings for **, ILS and LSHIFT, respectively: [0-9a-zA-Z)]\*\*[0-9a-zA-Z(] lang:fortran ils\([0-9a-zA-Z] lang:fortran lshift\([0-9a-zA-Z] lang:fortran As statistics go, this is probably not a prime example, but it is at least an indication.) -Lars

Fortran? I don't think that's D's target audience yet. And let's also compare with Python: A search of "lang:python [\w)]\s*\*\*\s*[\w(]" yields 10,700 results, and the first few actual use cases are: 1: bufferSize = 2**2**2**2 2: n,x = 89 >> 90 + 6 / 7 % x + z << 6 + 2 ** 8 3: def cube(n): return n ** 3 4: v1 = stdev(a)**2 v2 = stdev(b)**2 5: self.val = self.val ** 2 6: self._readerLength = self._readerLength * (10**len(m.group(1))) + long(m.group(1)) 7: rtn.append((1 - (1 - rgb[index]) ** correction) ** (1 / correction)) I don't find any appeal for cases 1 to 5. (Also compare with left-shift (lang:python [\w)]\s*<<\s*[\w(]), giving 9,000 results.)
Dec 07 2009
parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
KennyTM~ wrote:
 On Dec 8, 09 03:03, Lars T. Kyllingstad wrote:
 Andrei Alexandrescu wrote:
 Don wrote:
 As has been mentioned in previous posts, a ^^ b should be right
 associative and have a precedence between multiplication and unary
 operators. That much is clear.


 Operations involving integers are far less obvious (and are actually
 where a major benefit of an operator can come in).

 Using the normal promotion rules, 10^^2 is an integer. The range
 checking already present in D2 could be extended so that the compiler
 knows it'll even fit in a byte. This gets rid of one of the classic
 annoyances of C pow: int x = pow(2, 10); doesn't compile without a 
 cast.

 But the difficult question is, what's the type of 10^^-2 ? Should it
 be an error? (since the result, 0.01, is not representable as an
 integer). Should it return zero? (just as 1/2 doesn't return 0.5).
 For an example of these semantics, see
 http://www.tcl.tk/cgi-bin/tct/tip/123.html).
 Or should it return a double?
 Or should 10^^2 also be a double, but implicitly castable to byte
 because of the range checking rules?

 I currently favour making it an error, so that the normal promotion
 rules apply. It seems reasonable to me to require a cast to floating
 point in there somewhere.
 This is analagous to the similar case f ^^ 0.1; where f is known to
 be negative. This gives a complex result, creating a run-time error
 (returns a NaN). But, there's no standard error and no NaNs for
 integer underflow.

 One could also make int ^^ uint defined (returning an int), but not
 int ^^ int. Again thanks to range checking, int ^^ uint ^^ uint would
 work, because although uint ^^ uint is an int, it's known to be
 positive, so would implicitly convert to int. But would making int ^^
 int illegal, make it too much of an annoying special case?

 I strongly suspect that x^^y, where x and y are integers, and the
 value of y is not known at compile time, is an extremely rare 
 operation.

 Also, should int^^uint generate some kind of overflow error? Although
 other arithmeic integer operators don't, it's fantastically easy to
 hit an overflow with x^^y. Unless x is 1, y must be tiny (< 64 to
 avoid overflowing a ulong).

Nice analysis. IMHO this should lead us to reconsider the necessity of "^^" in the first place. It seems to be adding too little real value compared to the complexity of defining it. Andrei

It adds a lot of value to the ones that actually use it, even though you may not be one of them. Exponentiation is extremely common in numerics. Here are some statistics for you: A Google code search (see below) for FORTRAN code using the power operator **, which until recently didn't have a D equivalent, yields roughly 56100 results. A search for the FORTRAN equivalents of << yield 400 results for ILS() and 276 results for LSHIFT(). Yet, left shift apparently deserves a place in D. (I've used http://www.google.com/codesearch, with the following search strings for **, ILS and LSHIFT, respectively: [0-9a-zA-Z)]\*\*[0-9a-zA-Z(] lang:fortran ils\([0-9a-zA-Z] lang:fortran lshift\([0-9a-zA-Z] lang:fortran As statistics go, this is probably not a prime example, but it is at least an indication.) -Lars

Fortran? I don't think that's D's target audience yet.

I searched for FORTRAN code because that's more or less equivalent to searching for numerical code. And I think D's "target audience" is anyone who needs a fast, close-to-the-metal programming language. This definitely includes the scientific community. (There are several of the regulars on this NG who use D for scientific work.) -Lars
Dec 07 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Lars T. Kyllingstad:

 I searched for FORTRAN code because that's more or less equivalent to 
 searching for numerical code. And I think D's "target audience" is 
 anyone who needs a fast, close-to-the-metal programming language. This 
 definitely includes the scientific community. (There are several of the 
 regulars on this NG who use D for scientific work.)

I agree, if D plays well its cards it can be used by users of the numerical computing group too. I was hoping for the language Fortress to be used for such purposes, because it has several features good for numerical computing, but recently I've seen that for now it's planned to run on the JavaVM (where there are no arrays of structs, this is a significant disadvantage. The structs inside methods are less necessary because recently they have added to HotSpot an escape analysis that works for real), and more importantly I've seen its type system and other things are quite complex, maybe too much complex for the typical programmer scientist. So I think Fortran, Python, and C (and C++) look like the most useful for those purposes. D will have to work a lot to be appreciated more than Python for those purposes, because there are many scientific libs that can be used with Python (NumPy, SciPy, SAGE, MatPlotLib, BioPython, and bindings for almost everything else). Bye, bearophile
Dec 07 2009
parent reply "Joel C. Salomon" <joelcsalomon gmail.com> writes:
On 12/7/2009 5:37 PM, bearophile wrote:
 Lars T. Kyllingstad:
 I searched for FORTRAN code because that's more or less equivalent to 
 searching for numerical code. And I think D's "target audience" is 
 anyone who needs a fast, close-to-the-metal programming language. This 
 definitely includes the scientific community. (There are several of the 
 regulars on this NG who use D for scientific work.)

I agree, if D plays well its cards it can be used by users of the numerical computing group too.

Then we may have to convince Walter not to eliminate the extra comparison operators. —Joel
Dec 09 2009
parent bearophile <bearophileHUGS lycos.com> writes:
Joel C. Salomon:
 Then we may have to convince Walter not to eliminate the extra
 comparison operators.

They don't add that much to the language, while they are not easy to remember and add complexity. So I think that even serious numeric programmers will not miss them too much. But I don't perform that kind of computations all the time, so I can't know, I'm just guessing. If those operators will be needed we can add them back later! This shows what I think is an important design mistake done by D devs: you can't predict all possible usages of a language. So adding everything into it from the beginning is not positive. Serious numerical programmers will develop in D2 if D2 turns out to be fit for such purposes and if D2 is lucky, but it's after that moment and thanks to their work that we'll be able to know what things to add to D2 to help those people in their work. Several details in a language design must come from and after practical need, they can't come from up-front design. Reality is just too much complex for too much up-front design. Bye, bearophile
Dec 09 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, Dec 7, 2009 at 11:59 AM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 Lars T. Kyllingstad wrote:
 Andrei Alexandrescu wrote:
 Nice analysis. IMHO this should lead us to reconsider the necessity of
 "^^" in the first place. It seems to be adding too little real value
 compared to the complexity of defining it.

 Andrei

It adds a lot of value to the ones that actually use it, even though you may not be one of them. Exponentiation is extremely common in numerics.

Well I write numerics and I do use exponentiation occasionally, but never=

 the extent of yearning for ^^. "Extremely common" would be, I think, quit=

 difficult to argue.

 Here are some statistics for you: A Google code search (see below) for
 FORTRAN code using the power operator **, which until recently didn't ha=


 D equivalent, yields roughly 56100 results.

 A search for the FORTRAN equivalents of << yield 400 results for ILS() a=


 276 results for LSHIFT(). Yet, left shift apparently deserves a place in=


 (I've used http://www.google.com/codesearch, with the following search
 strings for **, ILS and LSHIFT, respectively:

 =A0 =A0[0-9a-zA-Z)]\*\*[0-9a-zA-Z(] lang:fortran
 =A0 =A0ils\([0-9a-zA-Z] lang:fortran
 =A0 =A0lshift\([0-9a-zA-Z] lang:fortran

 As statistics go, this is probably not a prime example, but it is at lea=


 an indication.)

Thanks for collecting the evidence. To make it more meaningful, you may w=

 to report it to the total number of lines of code searched. I don't know =

 to do that with codesearch.

 FWIW, this search:

 [0-9a-zA-Z)]\*\*[013456789a-zA-Z(] lang:fortran

 yields 30,300 results, meaning that almost half the uses of exponentiatio=

 is to square things.

 So I'm not sure what this all is supposed to argue for or against. What I
 can say is that Don's analysis suggested to me, let's leave all that
 aggravation to overloads of pow() and call it a day. I was much more in
 favor of ^^ before I saw how quickly it gets complicated. That kind of st=

 just doesn't strike me as the kind of things you put straight in the core
 language.

I get [0-9a-zA-Z)]\*\*[0-9a-zA-Z(] lang:fortran --> 57,900 [0-9a-zA-Z)]\*\*2 lang:fortran --> 81,900 141% of uses are for squaring! (I guess that's why you made yours a search for non-squaring, but still it shows something is odd in Google's counts) --bb
Dec 07 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, Dec 7, 2009 at 2:29 PM, bearophile <bearophileHUGS lycos.com> wrote=
:
 Lars T. Kyllingstad:
 I also seem to remember someone (was it Don or bearophile, perhaps?)
 listing various optimisation possibilities that are more readily
 available if ^^ is a built-in operator.

It was Don, I think. Those optimizations can be done with the pow, ipow and cpow (real, intege=

cases when the exponent is 2 or 3 (that are the most common):
 // C code
 #include "stdio.h"
 #include "math.h"
 #include "stdlib.h"

 int main() {
 =A0 =A0int x =3D atoi("100");
 =A0 =A0printf("%f\n", pow(x, 2));
 =A0 =A0return 0;
 }

 Compiled with:
 gcc version 4.3.3-dw2-tdm-1 (GCC)
 gcc -Wall -S -O3 test2.c -o test2.s

 =A0 =A0...
 =A0 =A0call =A0 =A0_atoi
 =A0 =A0pushl =A0 %eax
 =A0 =A0fildl =A0 (%esp)
 =A0 =A0addl =A0 =A0$4, %esp
 =A0 =A0fmul =A0 =A0%st(0), %st
 =A0 =A0movl =A0 =A0$LC1, (%esp)
 =A0 =A0fstpl =A0 4(%esp)
 =A0 =A0call =A0 =A0_printf
 =A0 =A0...

 Some weeks ago I have filed a bug asking for a similar optimization in LL=

Holy smokes! You actually file bugs in the LLVM database?! --bb
Dec 07 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, Dec 7, 2009 at 2:30 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 Lars T. Kyllingstad wrote:
 The fundamental reason why I want opPow so badly is in fact not even how
 often I use it. If that was the case, I'd want a special "writefln" operator
 as well. The main reason is that exponentiation is such a basic mathematical
 operation, right up there with addition and multiplication, that it deserves
 an operator of its own.

Hmmm. Addition, subtraction, multiplication, and division with remainder are all closed over integers. Power isn't. It's not even closed over real numbers. That makes it quite special and quite non-basic.

Uh, but a/b is not a "division with remainder" operator. It's just division-with-a-remainder-silently-ignored. If you want to define pow in the same way as a "pow with remainder but with the remainder ignored" then there's nothing stopping you. 1^^-1 == 1 2^^-1 == 0 4^^(1/2) == 2 5^^(1/2) == 2 Though I'd rather go the other direction and make the remainder-dropping integer division use a different symbol a la Python. --bb
Dec 07 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, Dec 7, 2009 at 2:56 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 Bill Baxter wrote:
 On Mon, Dec 7, 2009 at 2:30 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 Lars T. Kyllingstad wrote:
 The fundamental reason why I want opPow so badly is in fact not even h=




 often I use it. If that was the case, I'd want a special "writefln"
 operator
 as well. The main reason is that exponentiation is such a basic
 mathematical
 operation, right up there with addition and multiplication, that it
 deserves
 an operator of its own.

Hmmm. Addition, subtraction, multiplication, and division with remainde=



 are
 all closed over integers. Power isn't. It's not even closed over real
 numbers. That makes it quite special and quite non-basic.

Uh, but a/b is not a "division with remainder" operator. =A0It's just division-with-a-remainder-silently-ignored.

The result of a/b is the quotient resulting from a division with remainde=

 If you want the remainder use a%b (the compiler will peephole-optimize
 that). I don't see anything wrong with what I said.

 If you want to define pow in the same way as a "pow with remainder but
 with the remainder ignored" then there's nothing stopping you.

 =A0 =A01^^-1 =3D=3D 1
 =A0 =A02^^-1 =3D=3D 0
 =A0 =A04^^(1/2) =3D=3D 2
 =A0 =A05^^(1/2) =3D=3D 2

 Though I'd rather go the other direction and make the
 remainder-dropping integer division use a different symbol a la
 Python.

You'd need to show that "power with remainder" as you just defined it is useful theoretically and/or practically. The usefulness of integral divis=

 is absolutely massive.

 Anyhow, all I did was to explain that a particular argument that was made=

 invalid. That doesn't mean other arguments are invalid. All I'd hope is t=

 ^^ doesn't suddenly become a time sink when we have so much other stuff t=

 worry about. Again: ^^ was a lot more attractive to me when it seemed lik=

 slam dunk.

Seriously, I thought the above behavior would be what you'd get using integer arguments with opPow by analogy with how opDiv behaves. I wasn't expecting there would be any debate about it. I think the feeling that 2^^-1 is not 0 is the same gut feeling that tells all programming newbies that 1/2 should not be 0. But truncating down to the nearest int was the decision made long ago, so we stick with it. But languages like python that cater to newbie programmers are now trying to do something about it by making the difference between truncated integer division and division explicit. I don't really think D is going to go down that route at this late date, so we should just try to be self-consistent. Which to me says 1/2 and 2^^-1 should give the same result. --bb
Dec 07 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, Dec 7, 2009 at 2:52 PM, bearophile <bearophileHUGS lycos.com> wrote=
:
 Bill Baxter:

 Holy smokes! =A0You actually file bugs in the LLVM database?!

Don't ask me why. Eleven so far, you can't find five of them because in t=

vs have asked me so many times, on IRC. Folks have asked you many times here to submit bugs against dmd and/or phobos too. That's why I was surprised. I thought it was some religious thing, this non-filing of bugs. :-)
 One of those performance bugs has already being half-fixed, with nice res=

 http://llvm.org/bugs/show_bug.cgi?id=3D5501

Nice. Still hoping for the day when LLVM can do exceptions on Windows...
 I feel dumb, I understand nearly nothing of what they do and how they do =

Yeh, that kind of low level compiler tweaking is pretty much a mystery to me too. --bb
Dec 07 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, Dec 7, 2009 at 4:04 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 Bill Baxter wrote:
 On Mon, Dec 7, 2009 at 2:56 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 Bill Baxter wrote:
 On Mon, Dec 7, 2009 at 2:30 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 Lars T. Kyllingstad wrote:
 The fundamental reason why I want opPow so badly is in fact not even
 how
 often I use it. If that was the case, I'd want a special "writefln"
 operator
 as well. The main reason is that exponentiation is such a basic
 mathematical
 operation, right up there with addition and multiplication, that it
 deserves
 an operator of its own.

Hmmm. Addition, subtraction, multiplication, and division with remainder are all closed over integers. Power isn't. It's not even closed over real numbers. That makes it quite special and quite non-basic.

Uh, but a/b is not a "division with remainder" operator. =A0It's just division-with-a-remainder-silently-ignored.

The result of a/b is the quotient resulting from a division with remainder. If you want the remainder use a%b (the compiler will peephole-optimize that). I don't see anything wrong with what I said.
 If you want to define pow in the same way as a "pow with remainder but
 with the remainder ignored" then there's nothing stopping you.

 =A0 1^^-1 =3D=3D 1
 =A0 2^^-1 =3D=3D 0
 =A0 4^^(1/2) =3D=3D 2
 =A0 5^^(1/2) =3D=3D 2

 Though I'd rather go the other direction and make the
 remainder-dropping integer division use a different symbol a la
 Python.

You'd need to show that "power with remainder" as you just defined it i=



 useful theoretically and/or practically. The usefulness of integral
 division
 is absolutely massive.

 Anyhow, all I did was to explain that a particular argument that was ma=



 is
 invalid. That doesn't mean other arguments are invalid. All I'd hope is
 that
 ^^ doesn't suddenly become a time sink when we have so much other stuff
 to
 worry about. Again: ^^ was a lot more attractive to me when it seemed
 like a
 slam dunk.

Seriously, I thought the above behavior would be what you'd get using integer arguments with opPow by analogy with how opDiv behaves. =A0I wasn't expecting there would be any debate about it. =A0I think the feeling that 2^^-1 is not 0 is the same gut feeling that tells all programming newbies that 1/2 should not be 0. =A0But truncating down to the nearest int was the decision made long ago, so we stick with it. But languages like python that cater to newbie programmers are now trying to do something about it by making the difference between truncated integer division and division explicit. =A0I don't really think D is going to go down that route at this late date, so we should just try to be self-consistent. =A0Which to me says =A01/2 and 2^^-1 should give the same result.

I understand where you're coming from. As an old math teacher would say, "this is true but uninteresting". You'd have to prove that that behavior =

 ^^ has some interesting math properties.
 For starters, you'd need a
 "remainder" for ^^. But then what kind of interesting things can you do w=

 such a definition?

Negative exponent values are the only ones with an issue. You can't even write square-root etc with pow using only integers. The argument would have to be a float to even express that, so there is no issue. int^^float should be a float just like int/float is a float. So the only things left are those of the form x^^-y. or 1/(x^^y). I don't see a reason to go any further than translating it to exactly that. And that's just division, so the %-like operator corresponding to that is just % itself ( or rather 1%(x^^y) ) I think Don was creating a tempest in a teapot. I don't think any of his proposed alternatives besides treating it as integer division really make sense. They are inconsistent with the rest of D, and so don't merit further consideration unless the behavior of 1/2 is also on the table. --bb
Dec 07 2009
prev sibling next sibling parent reply Lionello Lunesu <lio lunesu.remove.com> writes:
On 8-12-2009 1:43, Andrei Alexandrescu wrote:
 Nice analysis. IMHO this should lead us to reconsider the necessity of
 "^^" in the first place. It seems to be adding too little real value
 compared to the complexity of defining it.

No, Don's just being awefully thorough. If you'd revisit all existing operators with the same thoroughness you would probably give up the whole idea of writing a language. Apart from the int/int division there's the int<<int, "What if I shift more than 31?" "What if I shift with <0?" and of course int+int "What to do on overflow?" etc.. I think ^^ can be made to work just fine. Let's not get carried away trying to make it perfect. L.
Dec 07 2009
parent reply Don <nospam nospam.com> writes:
Lionello Lunesu wrote:
 On 8-12-2009 1:43, Andrei Alexandrescu wrote:
 Nice analysis. IMHO this should lead us to reconsider the necessity of
 "^^" in the first place. It seems to be adding too little real value
 compared to the complexity of defining it.

No, Don's just being awefully thorough. If you'd revisit all existing operators with the same thoroughness you would probably give up the whole idea of writing a language. Apart from the int/int division there's the int<<int, "What if I shift more than 31?" "What if I shift with <0?" and of course int+int "What to do on overflow?" etc.. I think ^^ can be made to work just fine. Let's not get carried away trying to make it perfect. L.

It's only because I was looking at the range propagation stuff inside the compiler, that I got the idea that we could better than that. But, as Andrei says, maybe it's just not worth any more thought at this stage.
Dec 07 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Don wrote:
 Lionello Lunesu wrote:
 On 8-12-2009 1:43, Andrei Alexandrescu wrote:
 Nice analysis. IMHO this should lead us to reconsider the necessity of
 "^^" in the first place. It seems to be adding too little real value
 compared to the complexity of defining it.

No, Don's just being awefully thorough. If you'd revisit all existing operators with the same thoroughness you would probably give up the whole idea of writing a language. Apart from the int/int division there's the int<<int, "What if I shift more than 31?" "What if I shift with <0?" and of course int+int "What to do on overflow?" etc.. I think ^^ can be made to work just fine. Let's not get carried away trying to make it perfect. L.

It's only because I was looking at the range propagation stuff inside the compiler, that I got the idea that we could better than that. But, as Andrei says, maybe it's just not worth any more thought at this stage.

Walter and I decided to leave the decision of ^^ up to you, Don. You are the best positioned to make it. I hope you will piggyback a decision about ^^= to it, too. What I'd like would be a solid rationale for the choice. Off the top of my head and while my hat is off to your math skills and experience, I have trouble understanding the soundness of making int^^int yield an int, for the following reason: For all negative exponents, the result is zero, except when the base is 1 or -1. So I guess I'd suggest you at least make the exponent unsigned - the result is of zero interest (quite literally) for all negative exponents. If that behavior is interesting, it would be great if you provided a rationale for it. One small nit is that the exponential function is increasing very rapidly, much faster than multiplication. So yielding a long may actually be justified. (Some people would argue 32-bit multiplication is in the same league and ought to yield 64-bit results.) But then again, most uses of ^^ only raise things to small powers such as 2 and 3. Anyhow, the power is yours - again quite literally :o). Andrei
Dec 08 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Bill Baxter wrote:
 On Tue, Dec 8, 2009 at 12:01 AM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 
 What I'd like would be a solid rationale for the choice. Off the top of my
 head and while my hat is off to your math skills and experience, I have
 trouble understanding the soundness of making int^^int yield an int, for the
 following reason:

 For all negative exponents, the result is zero, except when the base is 1 or
 -1. So I guess I'd suggest you at least make the exponent  unsigned - the
 result is of zero interest (quite literally) for all negative exponents. If
 that behavior is interesting, it would be great if you provided a rationale
 for it.

The rationale (exponentiale?) for it is consistency.

Consistency is a good rationale, but math simply doesn't work that way. Matrix multiplication could have been defined to be consistent with matrix addition, but it ain't, because multiplication defined that way is uninteresting.
  Yeh, it's of
 zero interest.  But it's simple and consistent and doesn't require a
 bunch of new rules.  In the world of ints, small positive powers
 really are the only interesting case.  (And not just two and three --
 sometimes you'll see 2**N used to compute buffer sizes in Python.   Or
 at least that's what I observed in the code searches people posted.
 Arguably a more direct expression of intent than 1<<N.)

I agree. Then why not require the exponent to be unsigned during compilation? Don said he'd want negative exponent to throw a runtime exception. Why?
 You seem to be gunning to make some unneccesarily complicated rules up
 to handle a case that's not really important, but then at the same
 time argue that things are getting too complicated so we better axe
 the whole feature.  It doesn't really make sense.

It does. What I said was that we could be in one of two extremes: ^^ is a simple slam dunk, add it for convenience, versus ^^ is hard to type properly, but compiler support can do it. A wishy-washy middle ground where it's there but not doing something principled... that I don't like. But then again I defer the decision to Don.
 To make a comparison, << and >> aren't very useful for floating point
 numbers, does that mean they shouldn't be in the language?

Wrong argument. << and >> are closed over integrals. I see a mistaken argument, I point it out :o).
 In
 contrast  ^^ is useful for both floats and ints with small positive
 powers.  No, not all ints, but that's better versatility than << and
 at least.



I agree. Then at least why not make the type of the exponent unsigned? That gives the type system a fighting chance (via e.g. value range propagation). Give Willy a chance! Andrei
Dec 08 2009
parent reply Don <nospam nospam.com> writes:
Bill Baxter wrote:
 On Tue, Dec 8, 2009 at 10:18 AM, Bill Baxter <wbaxter gmail.com> wrote:
 I agree. Then at least why not make the type of the exponent unsigned? That
 gives the type system a fighting chance (via e.g. value range propagation).
 Give Willy a chance!

propagation. Seems to me that allowing a negative exponent doesn't much expand the range, if a truncation rule is used. The result is either undefined, 0 or 1. The range is much greater with a non-negative exponent. Could be undefined, zero, or most any negative or positive number.

This was meant sincerely, by the way. As in, I am ignorant about this issue (the trouble with range propagation and negative exponents) and would appreciate it if someone could explain it. --bb

I'm bitterly opposed to making int^^negative int return 0. Doing that is making up a new operation. And it does really bad things. Why is 2^^-1 == 0, and not 1 ? If you're evaluating with the floating point unit, it will be 1 when using "round up" mode. It's foul.
Dec 08 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Don wrote:
 Bill Baxter wrote:
 On Tue, Dec 8, 2009 at 10:18 AM, Bill Baxter <wbaxter gmail.com> wrote:
 I agree. Then at least why not make the type of the exponent 
 unsigned? That
 gives the type system a fighting chance (via e.g. value range 
 propagation).
 Give Willy a chance!

propagation. Seems to me that allowing a negative exponent doesn't much expand the range, if a truncation rule is used. The result is either undefined, 0 or 1. The range is much greater with a non-negative exponent. Could be undefined, zero, or most any negative or positive number.

This was meant sincerely, by the way. As in, I am ignorant about this issue (the trouble with range propagation and negative exponents) and would appreciate it if someone could explain it. --bb

I'm bitterly opposed to making int^^negative int return 0. Doing that is making up a new operation. And it does really bad things. Why is 2^^-1 == 0, and not 1 ? If you're evaluating with the floating point unit, it will be 1 when using "round up" mode. It's foul.

Awesome! Don please please require the exponent to be of unsigned type :o). Andrei
Dec 08 2009
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Lars T. Kyllingstad <public kyllingen.nospamnet> wrote:

 The fundamental reason why I want opPow so badly is in fact not even how  
 often I use it. If that was the case, I'd want a special "writefln"  
 operator as well. The main reason is that exponentiation is such a basic  
 mathematical operation, right up there with addition and multiplication,  
 that it deserves an operator of its own.

And now we'll all be wanting postfix ! for factorial as well, right? :p -- Simen
Dec 08 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 8, 2009 at 12:01 AM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

 What I'd like would be a solid rationale for the choice. Off the top of m=

 head and while my hat is off to your math skills and experience, I have
 trouble understanding the soundness of making int^^int yield an int, for =

 following reason:

 For all negative exponents, the result is zero, except when the base is 1=

 -1. So I guess I'd suggest you at least make the exponent =A0unsigned - t=

 result is of zero interest (quite literally) for all negative exponents. =

 that behavior is interesting, it would be great if you provided a rationa=

 for it.

The rationale (exponentiale?) for it is consistency. Yeh, it's of zero interest. But it's simple and consistent and doesn't require a bunch of new rules. In the world of ints, small positive powers really are the only interesting case. (And not just two and three -- sometimes you'll see 2**N used to compute buffer sizes in Python. Or at least that's what I observed in the code searches people posted. Arguably a more direct expression of intent than 1<<N.) You seem to be gunning to make some unneccesarily complicated rules up to handle a case that's not really important, but then at the same time argue that things are getting too complicated so we better axe the whole feature. It doesn't really make sense. To make a comparison, << and >> aren't very useful for floating point numbers, does that mean they shouldn't be in the language? In contrast ^^ is useful for both floats and ints with small positive powers. No, not all ints, but that's better versatility than << and
 at least.


 One small nit is that the exponential function is increasing very rapidly=

 much faster than multiplication. So yielding a long may actually be
 justified. (Some people would argue 32-bit multiplication is in the same
 league and ought to yield 64-bit results.) But then again, most uses of ^=

 only raise things to small powers such as 2 and 3.

Yep, or raising 2 to something < 32. --bb
Dec 08 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 8, 2009 at 9:40 AM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 Bill Baxter wrote:
 On Tue, Dec 8, 2009 at 12:01 AM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 What I'd like would be a solid rationale for the choice. Off the top of
 my
 head and while my hat is off to your math skills and experience, I have
 trouble understanding the soundness of making int^^int yield an int, fo=



 the
 following reason:

 For all negative exponents, the result is zero, except when the base is=



 or
 -1. So I guess I'd suggest you at least make the exponent =A0unsigned -=



 result is of zero interest (quite literally) for all negative exponents=



 If
 that behavior is interesting, it would be great if you provided a
 rationale
 for it.

The rationale (exponentiale?) for it is consistency.

Consistency is a good rationale, but math simply doesn't work that way. Matrix multiplication could have been defined to be consistent with matri=

 addition, but it ain't, because multiplication defined that way is
 uninteresting.

I'm not arguing consistency with math. I'm arguing consistency in the language. You're talking about consistency within math itself.
 =A0Yeh, it's of
 zero interest. =A0But it's simple and consistent and doesn't require a
 bunch of new rules. =A0In the world of ints, small positive powers
 really are the only interesting case. =A0(And not just two and three --
 sometimes you'll see 2**N used to compute buffer sizes in Python. =A0 Or
 at least that's what I observed in the code searches people posted.
 Arguably a more direct expression of intent than 1<<N.)

I agree. Then why not require the exponent to be unsigned during compilation? Don said he'd want negative exponent to throw a runtime exception. Why?

He figures it's usually an error, so he wants to be helpful. But he's killing a useful feature along with it.
 You seem to be gunning to make some unneccesarily complicated rules up
 to handle a case that's not really important, but then at the same
 time argue that things are getting too complicated so we better axe
 the whole feature. =A0It doesn't really make sense.

It does. What I said was that we could be in one of two extremes: ^^ is a simple slam dunk, add it for convenience, versus ^^ is hard to type properly, but compiler support can do it. A wishy-washy middle ground whe=

 it's there but not doing something principled... that I don't like. But t=

 again I defer the decision to Don.

Ok, now I understand your position better. And my position is that we should keep it consistent with how division is treated. No fancy type guessing based on arguments' values. int/int -> int. Doing something more sophisticated with typeof(int^^int) only makes sense to me if we do the same for division. Otherwise you're creating a lopsided an inconsistent language feature.
 To make a comparison, << and >> aren't very useful for floating point
 numbers, does that mean they shouldn't be in the language?

Wrong argument. << and >> are closed over integrals. I see a mistaken argument, I point it out :o).

I have no idea what you mean by that. You said that raising integers to negative powers wasn't useful and so it casts a dubious light over the whole feature. I'm saying the fact that an operator isn't universally useful does not imply it is useless. For another example, the fact that ~ isn't useful for numbers at all hasn't dulled our enthusiasm for it, because it *is* useful in the places where it was intended to be useful. Similarly ^^ is useful for floats, and some subset of integers.
 In
 contrast =A0^^ is useful for both floats and ints with small positive
 powers. =A0No, not all ints, but that's better versatility than << and
 at least.



I agree. Then at least why not make the type of the exponent unsigned? Th=

 gives the type system a fighting chance (via e.g. value range propagation=

 Give Willy a chance!

Honestly, I don't really understand this concern with range propagation. Seems to me that allowing a negative exponent doesn't much expand the range, if a truncation rule is used. The result is either undefined, 0 or 1. The range is much greater with a non-negative exponent. Could be undefined, zero, or most any negative or positive number. --bb
Dec 08 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 8, 2009 at 10:18 AM, Bill Baxter <wbaxter gmail.com> wrote:
 I agree. Then at least why not make the type of the exponent unsigned? T=


 gives the type system a fighting chance (via e.g. value range propagatio=


 Give Willy a chance!

Honestly, I don't really understand this concern with range propagation. =A0 Seems to me that allowing a negative exponent doesn't much expand the range, if a truncation rule is used. =A0The result is either undefined, 0 or 1. =A0The range is much greater with a non-negative exponent. =A0Could be undefined, zero, or most any negative or positive number.

This was meant sincerely, by the way. As in, I am ignorant about this issue (the trouble with range propagation and negative exponents) and would appreciate it if someone could explain it. --bb
Dec 08 2009
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
On Wed, 09 Dec 2009 05:28:23 +0100, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Don wrote:
 Bill Baxter wrote:
 On Tue, Dec 8, 2009 at 10:18 AM, Bill Baxter <wbaxter gmail.com> wrote:
 I agree. Then at least why not make the type of the exponent  
 unsigned? That
 gives the type system a fighting chance (via e.g. value range  
 propagation).
 Give Willy a chance!

propagation. Seems to me that allowing a negative exponent doesn't much expand the range, if a truncation rule is used. The result is either undefined, 0 or 1. The range is much greater with a non-negative exponent. Could be undefined, zero, or most any negative or positive number.

This was meant sincerely, by the way. As in, I am ignorant about this issue (the trouble with range propagation and negative exponents) and would appreciate it if someone could explain it. --bb

is making up a new operation. And it does really bad things. Why is 2^^-1 == 0, and not 1 ? If you're evaluating with the floating point unit, it will be 1 when using "round up" mode. It's foul.

Awesome! Don please please require the exponent to be of unsigned type :o). Andrei

Yeah. Makes no sense allowing it to be signed. -- Simen
Dec 09 2009
prev sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 8, 2009 at 8:07 PM, Don <nospam nospam.com> wrote:
 Bill Baxter wrote:
 On Tue, Dec 8, 2009 at 10:18 AM, Bill Baxter <wbaxter gmail.com> wrote:
 I agree. Then at least why not make the type of the exponent unsigned?
 That
 gives the type system a fighting chance (via e.g. value range
 propagation).
 Give Willy a chance!

Honestly, I don't really understand this concern with range propagation. =A0 Seems to me that allowing a negative exponent doesn't much expand the range, if a truncation rule is used. =A0The result is either undefined, 0 or 1. =A0The range is much greater with a non-negative exponent. =A0Could be undefined, zero, or most any negativ=



 or positive number.

This was meant sincerely, by the way. =A0As in, I am ignorant about this issue (the trouble with range propagation and negative exponents) and would appreciate it if someone could explain it. --bb

I'm bitterly opposed to making int^^negative int return 0. Doing that is making up a new operation. And it does really bad things. Why is 2^^-1 =

 and not 1 ? If you're evaluating with the floating point unit, it will be=

 when using "round up" mode.
 It's foul.

That doesn't really amount to much of an argument I can sink my teeth into, but ok. I think you're picking the greater of two evils, but apparently I'm in the minority. --bb
Dec 09 2009
prev sibling parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Don wrote:
 As has been mentioned in previous posts, a ^^ b should be right 
 associative and have a precedence between multiplication and unary 
 operators. That much is clear.
 
 
 Operations involving integers are far less obvious (and are actually 
 where a major benefit of an operator can come in).
 
 Using the normal promotion rules, 10^^2 is an integer. The range 
 checking already present in D2 could be extended so that the compiler 
 knows it'll even fit in a byte. This gets rid of one of the classic 
 annoyances of C pow:  int x = pow(2, 10); doesn't compile without a cast.
 
 But the difficult question is, what's the type of 10^^-2 ? Should it be 
 an error? (since the result, 0.01, is not representable as an integer). 
 Should it return zero? (just as 1/2 doesn't return 0.5). For an example 
 of these semantics, see http://www.tcl.tk/cgi-bin/tct/tip/123.html).
 Or should it return a double?

I think it should either be an error, or it should return a floating-point value. I'll even go as far as saying that I think 1/2 should either be an error or a floating-point value -- or perhaps even a special rational type. Integer division is not the same as "ordinary" division, and I think it shouldn't use the same symbol. (A backslash would be better: 5\2 == 2) Of course, I'm arguing the mathematician's point of view here. :) -Lars
Dec 07 2009
parent bearophile <bearophileHUGS lycos.com> writes:
Lars T. Kyllingstad:
 I'll even go as far as saying that I think 1/2 should either be an error 
 or a floating-point value -- or perhaps even a special rational type. 
 Integer division is not the same as "ordinary" division, and I think it 
 shouldn't use the same symbol. (A backslash would be better: 5\2 == 2)

In Pascal there's the 'div' operator for the integer division and / for the FP one. In Python they are // and / (even if the semantics is a bit different). Mixing the two is another bad detail of the C design. Bye, bearophile
Dec 07 2009