www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - proposed syntax change

reply Paul D. Anderson <paul.d.removethis.anderson comcast.andthis.net> writes:
I was browsing the Python spec yesterday and came across this interesting and
useful syntax:

"/" (one slash) means floating point division, e.g. 5/2 = 2.5 even though 5 and
2 are integers

"//" (two slashes) means integer (floor) division, e.g. 5.0//2.0 = 2.0 even
though 5.0 and 2.0 are floats.

I've always been a little troubled by the standard division operator being
dependent on the types of the operands. (I understand the need for it, I just
didn't like it much.) Now here is an elegant (IMHO) solution.

It seems to me that this could be added to D with very little effort and would
add a feature to the language. 

Oh wait...I think "//" is used elsewhere. Well, we could still use it but mark
it as a breaking change. Then users could simply remove all previous uses of
"//" from their code. If they REALLY need to retain the old "//" functionality
we could replace it with a new symbol. How about "--", like Ada? Oh wait...

I will also throw out (at no cost) a suggestion for the Python people: Why not
make "/%" the divmod operator (returning the quotient and remainder)? It would
return a tuple, but Python is used to that.

Paul
Aug 06 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Paul D. Anderson:
 Oh wait...I think "//" is used elsewhere. Well, we could still use it but mark
it as a breaking change. Then users could simply remove all previous uses of
"//" from their code. If they REALLY need to retain the old "//" functionality
we could replace it with a new symbol. How about "--", like Ada? Oh wait...

Pascal uses the infix "div" operator. In OcalML operators among FPs are followed by a dot. Bye, bearophile
Aug 06 2009
prev sibling next sibling parent Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Paul D. Anderson wrote:

 I was browsing the Python spec yesterday and came across this interesting
 and useful syntax:
 
 "/" (one slash) means floating point division, e.g. 5/2 = 2.5 even though
 5 and 2 are integers
 
 "//" (two slashes) means integer (floor) division, e.g. 5.0//2.0 = 2.0
 even though 5.0 and 2.0 are floats.

Yeah, I love that distinction. As a matter of fact, I've added it to my own language. Same syntax, too, though there was some thought about using the "div" keyword instead.
 I've always been a little troubled by the standard division operator being
 dependent on the types of the operands. (I understand the need for it, I
 just didn't like it much.) Now here is an elegant (IMHO) solution.

I agree. It's one of those C idiosyncrasies the world could do without.
 It seems to me that this could be added to D with very little effort and
 would add a feature to the language.

Seems like trouble to me. If we ignore for the moment the fact that "//" is used for line comments (D could use "div", for example), changing the meaning of "/" for integer operands would probably break many programs.
 Oh wait...I think "//" is used elsewhere. Well, we could still use it but
 mark it as a breaking change. Then users could simply remove all previous
 uses of "//" from their code. If they REALLY need to retain the old "//"
 functionality we could replace it with a new symbol. How about "--", like
 Ada? Oh wait...

Line-comments are very useful. My language uses "|". -- Michiel Helvensteijn
Aug 06 2009
prev sibling next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Aug 06, 2009 at 03:06:49PM -0400, Paul D. Anderson wrote:
 Oh wait...I think "//" is used elsewhere.

Is this a joke? -- Adam D. Ruppe http://arsdnet.net
Aug 06 2009
parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Adam D. Ruppe wrote:
 On Thu, Aug 06, 2009 at 03:06:49PM -0400, Paul D. Anderson wrote:
 Oh wait...I think "//" is used elsewhere.

Is this a joke?

No. When porting C, C++, Java or C# code just search "//" and replace it with "--". Oh wait... I think "--" is used elsewhere.
Aug 06 2009
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Adam D. Ruppe wrote:
 On Thu, Aug 06, 2009 at 04:35:41PM -0300, Ary Borenszweig wrote:
 No. When porting C, C++, Java or C# code just search "//" and replace it 
 with "--".

Problem with this is old habit. I find myself annoyed with languages that don't accept // comments just because I'm so used to typing them that it is my first instinct to comment a line. Doing a find and replace of // with something else is fairly simple (it isn't trivial, since "//" != "--" even if // == --, but that's not too hard to work with), but retraining fingers to type something new is a pain to do.
 Oh wait... I think "--" is used elsewhere.

Secondly, as to why I asked if it was a joke: how can someone use D or C++ and not know that // already has a meaning? I find it very hard to believe that someone can have any real world experience in the language at all and not know that // is in use. If you don't have any real world experience in the language, or at least in its direct predecessor (C++), what business do you have proposing breaking changes to it?

Aww... I intended to sound ironic. Didn't make it. :( Of course I think using "//" for something else is a disaster.
Aug 06 2009
parent ponce <aliloko gmail.com> writes:
Same for me, it breaks compatibility with C.
Also, i found the ocaml floating point operators (./  .+  .-  .*) painful when
i had to use them.
Aug 06 2009
prev sibling next sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
Ary Borenszweig wrote:
 Adam D. Ruppe wrote:
 On Thu, Aug 06, 2009 at 03:06:49PM -0400, Paul D. Anderson wrote:
 Oh wait...I think "//" is used elsewhere.

Is this a joke?

No. When porting C, C++, Java or C# code just search "//" and replace it with "--". Oh wait... I think "--" is used elsewhere.

Why would I as a user want to have two ops that do the same thing?! Python's solution for this is wrong IMHO since the problem is not with the op itself but rather with the way C handles numbers. 5 / 2 should always be the more precise FP division unless the compiler knows or is instructed to do otherwise. int a = 5 / 2; // compiler knows to use integer division auto b = 5 / 2; // b is double, FP division auto c = cast(int)(5/2)); // compiler instructed to use integer division auto d = floor(5 / 2); // FP division floored by a function to int auto f = std.math.div(5, 2); // intristic that does integer division what's the rationale of not doing the above, besides C compatibility?
Aug 06 2009
parent reply Yigal Chripun <yigal100 gmail.com> writes:
Robert Jacques wrote:
 On Thu, 06 Aug 2009 13:34:21 -0700, Yigal Chripun <yigal100 gmail.com> 
 wrote:
 
 Ary Borenszweig wrote:
 Adam D. Ruppe wrote:
 On Thu, Aug 06, 2009 at 03:06:49PM -0400, Paul D. Anderson wrote:
 Oh wait...I think "//" is used elsewhere.

Is this a joke?

replace it with "--". Oh wait... I think "--" is used elsewhere.

Why would I as a user want to have two ops that do the same thing?! Python's solution for this is wrong IMHO since the problem is not with the op itself but rather with the way C handles numbers. 5 / 2 should always be the more precise FP division unless the compiler knows or is instructed to do otherwise. int a = 5 / 2; // compiler knows to use integer division

No, it doesn't. (i.e. Welcome to the limitations of a context-free grammar) The right hand of the expression has to be evaluated before the left, or otherwise function overloads, etc, don't work, so there's no way for the compiler to know the type of the expected result when 5/2 is evaluated.
 auto b = 5 / 2; // b is double, FP division

 auto c = cast(int)(5/2)); // compiler instructed to use integer division

No, the cast would apply to the result of (5/2), not the '/' operator.
 auto d = floor(5 / 2); // FP division floored by a function to int

floor returns a real, not an int. I think you were looking for roundTo!int or roundTo!int(floor(5/2))
 auto f = std.math.div(5, 2); // intristic that does integer division

 what's the rationale of not doing the above, besides C compatibility?

The rationale is that integer division is very common and is usually assigned back into an int, and not a real. The only issue is literals, which were going to be handled with polysemous values (but that got dropped). But 2/5.0 is really not that much overhead.

As you noted yourself, polysemous types help solve this and also the compiler can have special handling (peep hole optimizations) for some of the above cases. in case D roundTo sounds indeed better (and since in the above it's compile time, it should be possible to optimize it. you've ignored case f which seems to me the most important: instead of currently 5/2 == 2 there should be a div intristic function such that div(5, 2) == 2 and that intristic will be the appropriate ASM instruction for integer division. In general, you can always round down a float but you can't get the correct double out of the rounded int, so my question is how much a performance hit is it to use the FP as default and only use the div intristic where performance is really an issue?
Aug 07 2009
parent reply Yigal Chripun <yigal100 gmail.com> writes:
Robert Jacques wrote:
 On Fri, 07 Aug 2009 01:22:31 -0700, Yigal Chripun <yigal100 gmail.com> 
 wrote:
 
 Robert Jacques wrote:
 On Thu, 06 Aug 2009 13:34:21 -0700, Yigal Chripun 
 <yigal100 gmail.com> wrote:

 Ary Borenszweig wrote:
 Adam D. Ruppe wrote:
 On Thu, Aug 06, 2009 at 03:06:49PM -0400, Paul D. Anderson wrote:
 Oh wait...I think "//" is used elsewhere.

Is this a joke?

replace it with "--". Oh wait... I think "--" is used elsewhere.

Why would I as a user want to have two ops that do the same thing?! Python's solution for this is wrong IMHO since the problem is not with the op itself but rather with the way C handles numbers. 5 / 2 should always be the more precise FP division unless the compiler knows or is instructed to do otherwise. int a = 5 / 2; // compiler knows to use integer division

grammar) The right hand of the expression has to be evaluated before the left, or otherwise function overloads, etc, don't work, so there's no way for the compiler to know the type of the expected result when 5/2 is evaluated.
 auto b = 5 / 2; // b is double, FP division

 auto c = cast(int)(5/2)); // compiler instructed to use integer 
 division

 auto d = floor(5 / 2); // FP division floored by a function to int

roundTo!int or roundTo!int(floor(5/2))
 auto f = std.math.div(5, 2); // intristic that does integer division

 what's the rationale of not doing the above, besides C compatibility?

assigned back into an int, and not a real. The only issue is literals, which were going to be handled with polysemous values (but that got dropped). But 2/5.0 is really not that much overhead.

As you noted yourself, polysemous types help solve this and also the compiler can have special handling (peep hole optimizations) for some of the above cases. in case D roundTo sounds indeed better (and since in the above it's compile time, it should be possible to optimize it. you've ignored case f which seems to me the most important: instead of currently 5/2 == 2 there should be a div intristic function such that div(5, 2) == 2 and that intristic will be the appropriate ASM instruction for integer division.

No, I didn't. I just didn't have anything to say.
 In general, you can always round down a float but you can't get the 
 correct double out of the rounded int, so my question is how much a 
 performance hit is it to use the FP as default and only use the div 
 intristic where performance is really an issue?

Now that I think about it, turning integer division into a function is a really bad idea: 1) there's function call overhead and 2) even if inlined, register values and the stack still have to be manipulated (as function call syntax dictates where the inputs and outputs are located) Today, DMD can choose any set of register inputs and outputs. As for the int-float conversion, apperently float-int is somewhat slow and destroys the floating point pipeline From http://mega-nerd.com/FPcast/
 The instruction which causes the real damage in this block is fldcw, 
 (FPU load control word) on lines 8 and 11. Whenever the FPU encounters 
 this instruction it flushes its pipeline and loads the control word 
 before continuing operation. The FPUs of modern CPUs like the Pentium 
 III, Pentium IV and AMD Athlons rely on deep pipelines to achieve 
 higher peak performance. Unfortunately certain pieces of C code can 
 reduce the floating point performance of the CPU to level of a 
 non-pipelined FPU.

 So why is the fldcw instruction used? Unfortunately, it is required to 
 make the calculation meet the ISO C Standard which specifies that 
 casting from floating point to integer is a truncation operation. 
 However, if the fistpl instruction was executed without changing the 
 mode of the FPU, the value would have been rounded instead of 
 truncated. The standard rounding mode is required for all normal 
 operations like addition, subtraction, multiplication etc while 
 truncation mode is required for the float to int cast. Hence if a 
 block of code contains a float to int cast, the FPU will spend a large 
 amount of its time switching between the two modes.


Thanks for the info about the cast. regarding the div() function above, I was thinking about using D's naked asm feature. From what little I know about this, the compiler doesn't generate the usual asm code for this sort of function to handle registers, stack, etc, and you're supposed to do everything yourself in asm. I don't think your comment above about the function call overhead applies if div is implemented in such a way but I'm no expert and someone more knowledgeable can shed more light on this. (Don?) also, div can be implemented in the compiler in the same way c++ style casts have template syntax ( e.g. static_cast<whatever>(thing) ) but are implemented inside the compiler.
Aug 07 2009
parent reply Sergey Gromov <snake.scaly gmail.com> writes:
Fri, 07 Aug 2009 13:47:31 -0700, Robert Jacques wrote:

 On Fri, 07 Aug 2009 12:03:43 -0700, Yigal Chripun <yigal100 gmail.com>  
 wrote:
 
 regarding the div() function above, I was thinking about using D's naked  
 asm feature. From what little I know about this, the compiler doesn't  
 generate the usual asm code for this sort of function to handle  
 registers, stack, etc, and you're supposed to do everything yourself in  
 asm.

IIRC naked asm only works for zero-argument and single arguments of size 1,2 or 4 functions, which div is not.
 I don't think your comment above about the function call overhead  
 applies if div is implemented in such a way but I'm no expert and  
 someone more knowledgeable can shed more light on this. (Don?)

If you check the D ABI, one of the arguments must be passed on the stack, the other in a specific register (EAX). http://www.digitalmars.com/d/2.0/abi.html So the backend can't do things like ECX = EBX / EDX. Instead it has to save/restore whatever's in EAX, ECX and EDX before/after the div call.

Inlined functions become integral part of their outer functions and therefore are not obliged to follow ABI. They don't have prologues, epilogues, call overhead, etc. Moreover compiler intrinsics are functions which compiler recognizes and treats specially, usually by replacing them with a single processor instruction.
Aug 07 2009
parent Sergey Gromov <snake.scaly gmail.com> writes:
Fri, 07 Aug 2009 17:02:33 -0700, Robert Jacques wrote:

 Moreover compiler intrinsics are
 functions which compiler recognizes and treats specially, usually by
 replacing them with a single processor instruction.

We weren't discussing implementation with intrinsics, but as with a standard library function.

Intrinsics were Yigal's point which he made twice: Thu, 06 Aug 2009 23:34:21 +0300, Yigal Chripun wrote:
 auto f = std.math.div(5, 2); // intristic that does integer division

Fri, 07 Aug 2009 11:22:31 +0300, Yigal Chripun wrote:
 you've ignored case f which seems to me the most important: instead of 
 currently 5/2 == 2 there should be a div intristic function such that 
 div(5, 2) == 2  and that intristic will be the appropriate ASM 
 instruction for integer division.

Well, he called them "intristics," bit it's easy to see what he actually wanted to say.
Aug 10 2009
prev sibling parent reply Paul D. Anderson <paul.d.removethis.anderson comcast.andthis.net> writes:
Adam D. Ruppe Wrote:

 On Thu, Aug 06, 2009 at 04:35:41PM -0300, Ary Borenszweig wrote:
 No. When porting C, C++, Java or C# code just search "//" and replace it 
 with "--".

Problem with this is old habit. I find myself annoyed with languages that don't accept // comments just because I'm so used to typing them that it is my first instinct to comment a line. Doing a find and replace of // with something else is fairly simple (it isn't trivial, since "//" != "--" even if // == --, but that's not too hard to work with), but retraining fingers to type something new is a pain to do.
 Oh wait... I think "--" is used elsewhere.

Secondly, as to why I asked if it was a joke: how can someone use D or C++ and not know that // already has a meaning? I find it very hard to believe that someone can have any real world experience in the language at all and not know that // is in use. If you don't have any real world experience in the language, or at least in its direct predecessor (C++), what business do you have proposing breaking changes to it? -- Adam D. Ruppe http://arsdnet.net

Two words: "whoooooosh!"
Aug 06 2009
parent Paul D. Anderson <paul.d.removethis.anderson comcast.andthis.net> writes:
Adam D. Ruppe Wrote:

 On Thu, Aug 06, 2009 at 04:48:40PM -0400, Paul D. Anderson wrote:
 Two words: "whoooooosh!"
 

it is even harder in plain text :S -- Adam D. Ruppe http://arsdnet.net

Sorry -- I'd hoped I was being obtuse enough to make it obvious. I will admit (quietly) that when I first saw the // operator I really did think it might be a good idea for D. But only for a second or so. And even then I didn't realize changing the meaning of / would also break a lot of code. Paul
Aug 06 2009
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Aug 06, 2009 at 04:35:41PM -0300, Ary Borenszweig wrote:
 No. When porting C, C++, Java or C# code just search "//" and replace it 
 with "--".

Problem with this is old habit. I find myself annoyed with languages that don't accept // comments just because I'm so used to typing them that it is my first instinct to comment a line. Doing a find and replace of // with something else is fairly simple (it isn't trivial, since "//" != "--" even if // == --, but that's not too hard to work with), but retraining fingers to type something new is a pain to do.
 Oh wait... I think "--" is used elsewhere.

Secondly, as to why I asked if it was a joke: how can someone use D or C++ and not know that // already has a meaning? I find it very hard to believe that someone can have any real world experience in the language at all and not know that // is in use. If you don't have any real world experience in the language, or at least in its direct predecessor (C++), what business do you have proposing breaking changes to it? -- Adam D. Ruppe http://arsdnet.net
Aug 06 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Thu, Aug 6, 2009 at 3:06 PM, Paul D.
Anderson<paul.d.removethis.anderson comcast.andthis.net> wrote:
 I was browsing the Python spec yesterday and came across this interesting=

 "/" (one slash) means floating point division, e.g. 5/2 =3D 2.5 even thou=

 "//" (two slashes) means integer (floor) division, e.g. 5.0//2.0 =3D 2.0 =

 I've always been a little troubled by the standard division operator bein=

just didn't like it much.) Now here is an elegant (IMHO) solution.
 It seems to me that this could be added to D with very little effort and =

*snort* Nevermind breaking *all comments ever written*. Yes, it would add a feature to the language. Lots of things would. Thanks for stating the obvious.
 Oh wait...I think "//" is used elsewhere. Well, we could still use it but=

uses of "//" from their code. If they REALLY need to retain the old "//" fu= nctionality we could replace it with a new symbol. How about "--", like Ada= ? Oh wait... It's at this point I really think you're joking.
Aug 06 2009
prev sibling next sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Paul D. Anderson wrote:
 I was browsing the Python spec yesterday and came across this interesting and
useful syntax:
 
 "/" (one slash) means floating point division, e.g. 5/2 = 2.5 even though 5
and 2 are integers
 
 "//" (two slashes) means integer (floor) division, e.g. 5.0//2.0 = 2.0 even
though 5.0 and 2.0 are floats.
 
 I've always been a little troubled by the standard division operator being
dependent on the types of the operands. (I understand the need for it, I just
didn't like it much.) Now here is an elegant (IMHO) solution.

I like the idea of adding a "floating point division", but I think it should be a *new* feature while the current / and // are left as they are. How about "./"? 5 / 2 = 2 // Current behavior 5.0 / 2.0 = 2.5 // Current behavior 5 ./ 2 = 2.5 // New behavior 5.0 ./ 2.0 = 2.5 // It always floating-point divides IOW, ./ is short for "cast operands to double and divide". If ./ proves too hard to parse (I think it might require some lookahead), then /^ might work.
Aug 06 2009
parent Paul D. Anderson <paul.d.removethis.anderson comcast.andthis.net> writes:
Robert Fraser Wrote:

 Paul D. Anderson wrote:
 I was browsing the Python spec yesterday and came across this interesting and
useful syntax:
 
 "/" (one slash) means floating point division, e.g. 5/2 = 2.5 even though 5
and 2 are integers
 
 "//" (two slashes) means integer (floor) division, e.g. 5.0//2.0 = 2.0 even
though 5.0 and 2.0 are floats.
 
 I've always been a little troubled by the standard division operator being
dependent on the types of the operands. (I understand the need for it, I just
didn't like it much.) Now here is an elegant (IMHO) solution.

I like the idea of adding a "floating point division", but I think it should be a *new* feature while the current / and // are left as they are. How about "./"? 5 / 2 = 2 // Current behavior 5.0 / 2.0 = 2.5 // Current behavior 5 ./ 2 = 2.5 // New behavior 5.0 ./ 2.0 = 2.5 // It always floating-point divides IOW, ./ is short for "cast operands to double and divide". If ./ proves too hard to parse (I think it might require some lookahead), then /^ might work.

To the extent that this was a serious proposal (that is, to a very, very small extent) I would rather reserve the ./ operator for element-wise array division, along with .*, etc., since I'm used to that in other languages. (And the whole point of proposing syntax is to make one's own self comfortable, right?) Paul
Aug 06 2009
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Aug 06, 2009 at 04:48:40PM -0400, Paul D. Anderson wrote:
 Two words: "whoooooosh!"
 

it is even harder in plain text :S -- Adam D. Ruppe http://arsdnet.net
Aug 06 2009
prev sibling next sibling parent language_fan <foo bar.com.invalid> writes:
Thu, 06 Aug 2009 17:06:40 -0300, Ary Borenszweig thusly wrote:

 Of course I think using "//" for something else is a disaster.

The -- token may look too functional to many of us. I am pretty sure that a great deal of D users would choose a buggy, badly optimizing compiler and an incomplete spec over a perfectly working D 3.0 compiler and spec if the latter one used -- for one line comments. It's a serious step towards unknown if you try to stay compatible with C.
Aug 06 2009
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 06 Aug 2009 13:34:21 -0700, Yigal Chripun <yigal100 gmail.com>  
wrote:

 Ary Borenszweig wrote:
 Adam D. Ruppe wrote:
 On Thu, Aug 06, 2009 at 03:06:49PM -0400, Paul D. Anderson wrote:
 Oh wait...I think "//" is used elsewhere.

Is this a joke?

it with "--". Oh wait... I think "--" is used elsewhere.

Why would I as a user want to have two ops that do the same thing?! Python's solution for this is wrong IMHO since the problem is not with the op itself but rather with the way C handles numbers. 5 / 2 should always be the more precise FP division unless the compiler knows or is instructed to do otherwise. int a = 5 / 2; // compiler knows to use integer division

No, it doesn't. (i.e. Welcome to the limitations of a context-free grammar) The right hand of the expression has to be evaluated before the left, or otherwise function overloads, etc, don't work, so there's no way for the compiler to know the type of the expected result when 5/2 is evaluated.
 auto b = 5 / 2; // b is double, FP division

 auto c = cast(int)(5/2)); // compiler instructed to use integer division

No, the cast would apply to the result of (5/2), not the '/' operator.
 auto d = floor(5 / 2); // FP division floored by a function to int

floor returns a real, not an int. I think you were looking for roundTo!int or roundTo!int(floor(5/2))
 auto f = std.math.div(5, 2); // intristic that does integer division

 what's the rationale of not doing the above, besides C compatibility?

The rationale is that integer division is very common and is usually assigned back into an int, and not a real. The only issue is literals, which were going to be handled with polysemous values (but that got dropped). But 2/5.0 is really not that much overhead.
Aug 06 2009
prev sibling next sibling parent Moritz Warning <moritzwarning web.de> writes:
On Thu, 06 Aug 2009 15:06:49 -0400, Paul D. Anderson wrote:

 I was browsing the Python spec yesterday and came across this
 interesting and useful syntax:
 
 "/" (one slash) means floating point division, e.g. 5/2 = 2.5 even
 though 5 and 2 are integers
 
 "//" (two slashes) means integer (floor) division, e.g. 5.0//2.0 = 2.0
 even though 5.0 and 2.0 are floats.
 
 I've always been a little troubled by the standard division operator
 being dependent on the types of the operands. (I understand the need for
 it, I just didn't like it much.) Now here is an elegant (IMHO) solution.
 
 It seems to me that this could be added to D with very little effort and
 would add a feature to the language.
 
 Oh wait...I think "//" is used elsewhere. Well, we could still use it
 but mark it as a breaking change. Then users could simply remove all
 previous uses of "//" from their code. If they REALLY need to retain the
 old "//" functionality we could replace it with a new symbol. How about
 "--", like Ada? Oh wait...
 
 I will also throw out (at no cost) a suggestion for the Python people:
 Why not make "/%" the divmod operator (returning the quotient and
 remainder)? It would return a tuple, but Python is used to that.
 
 Paul

// has potential to be useful as an operator. Maybe # would be a nice replacement. Easier to type, used as comment in other languages and no apparent use as operator. Imho, for D, to change the meaning for // might be too much of a breaking change.
Aug 06 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Thu, Aug 6, 2009 at 6:02 PM, Robert Jacques<sandford jhu.edu> wrote:

 int a = 5 / 2; // compiler knows to use integer division

No, it doesn't. (i.e. Welcome to the limitations of a context-free grammar) The right hand of the expression has to be evaluated before the left, or otherwise function overloads, etc, don't work, so there's no way for the compiler to know the type of the expected result when 5/2 is evaluated.

Uh, no. This has literally nothing to do with the grammar. What happens in this line would be determined in the semantic phase, not parsing.
Aug 06 2009
prev sibling next sibling parent Marianne Gagnon <auria.mg gmail.com> writes:
Paul D. Anderson Wrote:

 I was browsing the Python spec yesterday and came across this interesting and
useful syntax:
 
 "/" (one slash) means floating point division, e.g. 5/2 = 2.5 even though 5
and 2 are integers
 
 "//" (two slashes) means integer (floor) division, e.g. 5.0//2.0 = 2.0 even
though 5.0 and 2.0 are floats.
 
 I've always been a little troubled by the standard division operator being
dependent on the types of the operands. (I understand the need for it, I just
didn't like it much.) Now here is an elegant (IMHO) solution.
 

But, in your example it's still dependant on operand types. Division is performed very differently on integers and on IEEE754 floats. So even with your proposal there would be implicit casts. Also you give example 5.0//2.0 = 2.0. Isn't // integer division? But it gives a truncated float? Oh, still more type inference.
Aug 06 2009
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 06 Aug 2009 15:10:27 -0700, Jarrett Billingsley  
<jarrett.billingsley gmail.com> wrote:

 On Thu, Aug 6, 2009 at 6:02 PM, Robert Jacques<sandford jhu.edu> wrote:

 int a = 5 / 2; // compiler knows to use integer division

No, it doesn't. (i.e. Welcome to the limitations of a context-free grammar) The right hand of the expression has to be evaluated before the left, or otherwise function overloads, etc, don't work, so there's no way for the compiler to know the type of the expected result when 5/2 is evaluated.

Uh, no. This has literally nothing to do with the grammar. What happens in this line would be determined in the semantic phase, not parsing.

I used the term context-free as the expression 5/2 must be evaluated free of its context: i.e. 'int a =' or 'real b ='. I apologise if this is an over generalization of the term (it's been too long since my algorithm's class) But the rest of my comment is valid. This came up before while looking at how 'long = int + int' should be evaluated with regard to overflow. Walter explained that currently in DMD, 'int+int' or in this case '5/2' gets evaluated before the assignment statement, so it doesn't know/can't use the type information of the assignment. As I said polysemous values fixes this, but they are rather computationally expensive to support.
Aug 06 2009
prev sibling next sibling parent reply Don <nospam nospam.com> writes:
Paul D. Anderson wrote:
 I was browsing the Python spec yesterday and came across this interesting and
useful syntax:
 
 "/" (one slash) means floating point division, e.g. 5/2 = 2.5 even though 5
and 2 are integers
 
 "//" (two slashes) means integer (floor) division, e.g. 5.0//2.0 = 2.0 even
though 5.0 and 2.0 are floats.
 
 I've always been a little troubled by the standard division operator being
dependent on the types of the operands. 

Division of floats is also dependent on the rounding mode. There's actually no unabiguous "floating point division". float f = ulong.max / 2.0; Can't be represented exactly in a float, so it has to perform rounding. The operator which is REALLY missing is exponentiation.
Aug 07 2009
parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Don wrote:
 The operator which is REALLY missing is exponentiation.

I've been really missing that one. Which operators could be used for exponentiation? I've only ever seen a**b and a^b used, but I think those are out of the question for D. -Lars
Aug 07 2009
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Lars T. Kyllingstad wrote:
 Don wrote:
 The operator which is REALLY missing is exponentiation.

I've been really missing that one. Which operators could be used for exponentiation? I've only ever seen a**b and a^b used, but I think those are out of the question for D. -Lars

How about *^ ^ isn't valid as a unary operator, thus a*^b cannot be mistaken for a*(^b) It's a bit of a cop-out combining the two, but should be unambiguous.
Aug 07 2009
parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Daniel Keep wrote:
 
 Lars T. Kyllingstad wrote:
 Don wrote:
 The operator which is REALLY missing is exponentiation.

I've been really missing that one. Which operators could be used for exponentiation? I've only ever seen a**b and a^b used, but I think those are out of the question for D. -Lars

How about *^ ^ isn't valid as a unary operator, thus a*^b cannot be mistaken for a*(^b) It's a bit of a cop-out combining the two, but should be unambiguous.

Yeah, not too bad. Would a^^b work? -Lars
Aug 07 2009
parent reply Don <nospam nospam.com> writes:
Lars T. Kyllingstad wrote:
 Daniel Keep wrote:
 Lars T. Kyllingstad wrote:
 Don wrote:
 The operator which is REALLY missing is exponentiation.

I've been really missing that one. Which operators could be used for exponentiation? I've only ever seen a**b and a^b used, but I think those are out of the question for D. -Lars

How about *^ ^ isn't valid as a unary operator, thus a*^b cannot be mistaken for a*(^b) It's a bit of a cop-out combining the two, but should be unambiguous.

Yeah, not too bad. Would a^^b work? -Lars

Yes. I think it's the best option. Note that we already have the table: bitwise logical & && | || ^ != so there's nothing else you'd want to use ^^ for. People would get used to it pretty quickly. I think it looks better than Fortran's **, actually. double y = x^^2;
Aug 07 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Don:
 so there's nothing else you'd want to use ^^ for.
 People would get used to it pretty quickly. I think it looks better than 
 Fortran's **, actually.  double y = x^^2;

I have asked for a power operator lot of time ago, in one of my first long lists of suggestions. ^^ isn't standard in other languages (they usually use ** or ^), but it looks nice enough, and it doesn't look hard to understand or learn. I'd like it to perform integral exponentiation if both operands are integral, and double/real exponentiation in the other cases. In mathematics ^^ is sometimes used for Tetration, but it's not a problem, it's not a common operation: http://en.wikipedia.org/wiki/Tetration So this looks like a good idea. The front-end *must* be able to translate x ^^ 2 and x ^^ 3 into x*x and x*x*x, that are faster than any other kind of operation (Python doesn't do this simple operation, and a power operation done in the middle of a critical loop can slow down the code, I have seen this in my Python code). (x ^^ 4 can be simplified into y = x*x; y*y, but this is a less common operation). I guess the way to overload this operator is named opPower(). So for example if A is a user-defined matrix you can write: auto B = A ^^ 2; Bye, bearophile
Aug 07 2009
parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
bearophile wrote:
 Don:
 so there's nothing else you'd want to use ^^ for.
 People would get used to it pretty quickly. I think it looks better than 
 Fortran's **, actually.  double y = x^^2;

I have asked for a power operator lot of time ago, in one of my first long lists of suggestions. ^^ isn't standard in other languages (they usually use ** or ^), but it looks nice enough, and it doesn't look hard to understand or learn. I'd like it to perform integral exponentiation if both operands are integral, and double/real exponentiation in the other cases. In mathematics ^^ is sometimes used for Tetration, but it's not a problem, it's not a common operation: http://en.wikipedia.org/wiki/Tetration So this looks like a good idea. The front-end *must* be able to translate x ^^ 2 and x ^^ 3 into x*x and x*x*x, that are faster than any other kind of operation (Python doesn't do this simple operation, and a power operation done in the middle of a critical loop can slow down the code, I have seen this in my Python code). (x ^^ 4 can be simplified into y = x*x; y*y, but this is a less common operation). I guess the way to overload this operator is named opPower(). So for example if A is a user-defined matrix you can write: auto B = A ^^ 2; Bye, bearophile

This deserves its own thread. I'll create one. -Lars
Aug 07 2009
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Fri, 07 Aug 2009 01:22:31 -0700, Yigal Chripun <yigal100 gmail.com>  
wrote:

 Robert Jacques wrote:
 On Thu, 06 Aug 2009 13:34:21 -0700, Yigal Chripun <yigal100 gmail.com>  
 wrote:

 Ary Borenszweig wrote:
 Adam D. Ruppe wrote:
 On Thu, Aug 06, 2009 at 03:06:49PM -0400, Paul D. Anderson wrote:
 Oh wait...I think "//" is used elsewhere.

Is this a joke?

replace it with "--". Oh wait... I think "--" is used elsewhere.

Why would I as a user want to have two ops that do the same thing?! Python's solution for this is wrong IMHO since the problem is not with the op itself but rather with the way C handles numbers. 5 / 2 should always be the more precise FP division unless the compiler knows or is instructed to do otherwise. int a = 5 / 2; // compiler knows to use integer division

grammar) The right hand of the expression has to be evaluated before the left, or otherwise function overloads, etc, don't work, so there's no way for the compiler to know the type of the expected result when 5/2 is evaluated.
 auto b = 5 / 2; // b is double, FP division

 auto c = cast(int)(5/2)); // compiler instructed to use integer  
 division

 auto d = floor(5 / 2); // FP division floored by a function to int

roundTo!int or roundTo!int(floor(5/2))
 auto f = std.math.div(5, 2); // intristic that does integer division

 what's the rationale of not doing the above, besides C compatibility?

assigned back into an int, and not a real. The only issue is literals, which were going to be handled with polysemous values (but that got dropped). But 2/5.0 is really not that much overhead.

As you noted yourself, polysemous types help solve this and also the compiler can have special handling (peep hole optimizations) for some of the above cases. in case D roundTo sounds indeed better (and since in the above it's compile time, it should be possible to optimize it. you've ignored case f which seems to me the most important: instead of currently 5/2 == 2 there should be a div intristic function such that div(5, 2) == 2 and that intristic will be the appropriate ASM instruction for integer division.

No, I didn't. I just didn't have anything to say.
 In general, you can always round down a float but you can't get the  
 correct double out of the rounded int, so my question is how much a  
 performance hit is it to use the FP as default and only use the div  
 intristic where performance is really an issue?

Now that I think about it, turning integer division into a function is a really bad idea: 1) there's function call overhead and 2) even if inlined, register values and the stack still have to be manipulated (as function call syntax dictates where the inputs and outputs are located) Today, DMD can choose any set of register inputs and outputs. As for the int-float conversion, apperently float-int is somewhat slow and destroys the floating point pipeline From http://mega-nerd.com/FPcast/
 The instruction which causes the real damage in this block is fldcw,  
 (FPU load control word) on lines 8 and 11. Whenever the FPU encounters  
 this instruction it flushes its pipeline and loads the control word  
 before continuing operation. The FPUs of modern CPUs like the Pentium  
 III, Pentium IV and AMD Athlons rely on deep pipelines to achieve higher  
 peak performance. Unfortunately certain pieces of C code can reduce the  
 floating point performance of the CPU to level of a non-pipelined FPU.

 So why is the fldcw instruction used? Unfortunately, it is required to  
 make the calculation meet the ISO C Standard which specifies that  
 casting from floating point to integer is a truncation operation.  
 However, if the fistpl instruction was executed without changing the  
 mode of the FPU, the value would have been rounded instead of truncated.  
 The standard rounding mode is required for all normal operations like  
 addition, subtraction, multiplication etc while truncation mode is  
 required for the float to int cast. Hence if a block of code contains a  
 float to int cast, the FPU will spend a large amount of its time  
 switching between the two modes.

Aug 07 2009
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Fri, 07 Aug 2009 12:03:43 -0700, Yigal Chripun <yigal100 gmail.com>  
wrote:

 Robert Jacques wrote:
 On Fri, 07 Aug 2009 01:22:31 -0700, Yigal Chripun <yigal100 gmail.com>  
 wrote:

 Robert Jacques wrote:
 On Thu, 06 Aug 2009 13:34:21 -0700, Yigal Chripun  
 <yigal100 gmail.com> wrote:

 Ary Borenszweig wrote:
 Adam D. Ruppe wrote:
 On Thu, Aug 06, 2009 at 03:06:49PM -0400, Paul D. Anderson wrote:
 Oh wait...I think "//" is used elsewhere.

Is this a joke?

replace it with "--". Oh wait... I think "--" is used elsewhere.

Why would I as a user want to have two ops that do the same thing?! Python's solution for this is wrong IMHO since the problem is not with the op itself but rather with the way C handles numbers. 5 / 2 should always be the more precise FP division unless the compiler knows or is instructed to do otherwise. int a = 5 / 2; // compiler knows to use integer division

grammar) The right hand of the expression has to be evaluated before the left, or otherwise function overloads, etc, don't work, so there's no way for the compiler to know the type of the expected result when 5/2 is evaluated.
 auto b = 5 / 2; // b is double, FP division

 auto c = cast(int)(5/2)); // compiler instructed to use integer  
 division

operator.
 auto d = floor(5 / 2); // FP division floored by a function to int

roundTo!int or roundTo!int(floor(5/2))
 auto f = std.math.div(5, 2); // intristic that does integer division

 what's the rationale of not doing the above, besides C compatibility?

assigned back into an int, and not a real. The only issue is literals, which were going to be handled with polysemous values (but that got dropped). But 2/5.0 is really not that much overhead.

As you noted yourself, polysemous types help solve this and also the compiler can have special handling (peep hole optimizations) for some of the above cases. in case D roundTo sounds indeed better (and since in the above it's compile time, it should be possible to optimize it. you've ignored case f which seems to me the most important: instead of currently 5/2 == 2 there should be a div intristic function such that div(5, 2) == 2 and that intristic will be the appropriate ASM instruction for integer division.

 In general, you can always round down a float but you can't get the  
 correct double out of the rounded int, so my question is how much a  
 performance hit is it to use the FP as default and only use the div  
 intristic where performance is really an issue?

a really bad idea: 1) there's function call overhead and 2) even if inlined, register values and the stack still have to be manipulated (as function call syntax dictates where the inputs and outputs are located) Today, DMD can choose any set of register inputs and outputs. As for the int-float conversion, apperently float-int is somewhat slow and destroys the floating point pipeline From http://mega-nerd.com/FPcast/
 The instruction which causes the real damage in this block is fldcw,  
 (FPU load control word) on lines 8 and 11. Whenever the FPU encounters  
 this instruction it flushes its pipeline and loads the control word  
 before continuing operation. The FPUs of modern CPUs like the Pentium  
 III, Pentium IV and AMD Athlons rely on deep pipelines to achieve  
 higher peak performance. Unfortunately certain pieces of C code can  
 reduce the floating point performance of the CPU to level of a  
 non-pipelined FPU.

 So why is the fldcw instruction used? Unfortunately, it is required to  
 make the calculation meet the ISO C Standard which specifies that  
 casting from floating point to integer is a truncation operation.  
 However, if the fistpl instruction was executed without changing the  
 mode of the FPU, the value would have been rounded instead of  
 truncated. The standard rounding mode is required for all normal  
 operations like addition, subtraction, multiplication etc while  
 truncation mode is required for the float to int cast. Hence if a  
 block of code contains a float to int cast, the FPU will spend a large  
 amount of its time switching between the two modes.


Thanks for the info about the cast. regarding the div() function above, I was thinking about using D's naked asm feature. From what little I know about this, the compiler doesn't generate the usual asm code for this sort of function to handle registers, stack, etc, and you're supposed to do everything yourself in asm.

IIRC naked asm only works for zero-argument and single arguments of size 1,2 or 4 functions, which div is not.
 I don't think your comment above about the function call overhead  
 applies if div is implemented in such a way but I'm no expert and  
 someone more knowledgeable can shed more light on this. (Don?)

If you check the D ABI, one of the arguments must be passed on the stack, the other in a specific register (EAX). http://www.digitalmars.com/d/2.0/abi.html So the backend can't do things like ECX = EBX / EDX. Instead it has to save/restore whatever's in EAX, ECX and EDX before/after the div call.
 also, div can be implemented in the compiler in the same way c++ style  
 casts have template syntax ( e.g. static_cast<whatever>(thing) ) but are  
   implemented inside the compiler.

Well, technically, static cast isn't a function. Also, div should live in std.object and not std.math.
Aug 07 2009
prev sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Fri, 07 Aug 2009 15:44:04 -0700, Sergey Gromov <snake.scaly gmail.com>  
wrote:

 Fri, 07 Aug 2009 13:47:31 -0700, Robert Jacques wrote:

 On Fri, 07 Aug 2009 12:03:43 -0700, Yigal Chripun <yigal100 gmail.com>
 wrote:

 regarding the div() function above, I was thinking about using D's  
 naked
 asm feature. From what little I know about this, the compiler doesn't
 generate the usual asm code for this sort of function to handle
 registers, stack, etc, and you're supposed to do everything yourself in
 asm.

IIRC naked asm only works for zero-argument and single arguments of size 1,2 or 4 functions, which div is not.
 I don't think your comment above about the function call overhead
 applies if div is implemented in such a way but I'm no expert and
 someone more knowledgeable can shed more light on this. (Don?)

If you check the D ABI, one of the arguments must be passed on the stack, the other in a specific register (EAX). http://www.digitalmars.com/d/2.0/abi.html So the backend can't do things like ECX = EBX / EDX. Instead it has to save/restore whatever's in EAX, ECX and EDX before/after the div call.

Inlined functions become integral part of their outer functions and therefore are not obliged to follow ABI. They don't have prologues, epilogues, call overhead, etc.

Yes and no. This is quite true for normal D functions, but throwing manual asm into the mix does mess up register allocation, etc. Even with naked asm, a minimum three registers must be saved.
 Moreover compiler intrinsics are
 functions which compiler recognizes and treats specially, usually by
 replacing them with a single processor instruction.

We weren't discussing implementation with intrinsics, but as with a standard library function.
Aug 07 2009