www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Detecting inadvertent use of integer division

reply Don <nospam nospam.com> writes:
Consider this notorious piece of code:

assert(x>1);
double y = 1 / x;

This calculates y as the reciprocal of x, if x is a floating-point 
number. But if x is an integer, an integer division is performed instead 
of a floating-point one, and y will be 0.

It's a very common newbie trap, but I find it still catches me 
occasionally, especially when dividing two variables or compile-time 
constants.

In the opPow thread there were a couple of mentions of inadvertent 
integer division, and how Python is removing this error by making / 
always mean floating-point division, and introducing a new operator for 
integer division.

We could largely eliminate this type of bug without doing anything so 
drastic. Most of the problem just comes from C's cavalier attitude to 
implicit casting. All we'd need to do is tighten the implicit conversion 
rules for int->float, in the same way that the int->uint rules have been 
tightened:

"If an integer expression has an inexact result (ie, involves an inexact 
integer divison), that expression cannot be implicitly cast to a 
floating-point type."

(This means that double y = int_val / 1;  is OK, and also:
  double z = 90/3; would be OK. An alternative rule would be:
"If an integer expression involves integer divison, that expression 
cannot be implicitly cast to a floating-point type").

In the very rare cases where the result of an integer division was 
actually intended to be stored in a float, an explicit cast would be 
required. So you'd write:
double y = cast(int)(1/x);

Like the implicit uint->int casts which have recently been disallowed, I 
think this would prevent a lot of bugs, without causing much pain.
Dec 14 2009
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Don wrote:
 Consider this notorious piece of code:
 
 assert(x>1);
 double y = 1 / x;
 
 This calculates y as the reciprocal of x, if x is a floating-point 
 number. But if x is an integer, an integer division is performed instead 
 of a floating-point one, and y will be 0.
 
 It's a very common newbie trap, but I find it still catches me 
 occasionally, especially when dividing two variables or compile-time 
 constants.
 
 In the opPow thread there were a couple of mentions of inadvertent 
 integer division, and how Python is removing this error by making / 
 always mean floating-point division, and introducing a new operator for 
 integer division.
 
 We could largely eliminate this type of bug without doing anything so 
 drastic. Most of the problem just comes from C's cavalier attitude to 
 implicit casting. All we'd need to do is tighten the implicit conversion 
 rules for int->float, in the same way that the int->uint rules have been 
 tightened:
 
 "If an integer expression has an inexact result (ie, involves an inexact 
 integer divison), that expression cannot be implicitly cast to a 
 floating-point type."
But the compiler cannot reliably tell if it will produce an inexact result.
 (This means that double y = int_val / 1;  is OK, and also:
  double z = 90/3; would be OK. An alternative rule would be:
 "If an integer expression involves integer divison, that expression 
 cannot be implicitly cast to a floating-point type").
This is kinda complicated if one has, say: double z = x/y + 3;
 In the very rare cases where the result of an integer division was 
 actually intended to be stored in a float, an explicit cast would be 
 required. So you'd write:
 double y = cast(int)(1/x);
 
 Like the implicit uint->int casts which have recently been disallowed, I 
 think this would prevent a lot of bugs, without causing much pain.
Maybe it's easier to simply disallow 1/x, where x is an int, and the numerator is '1'. But then maybe that will cause problems with generic code. I don't think there's an easy answer here.
Dec 14 2009
parent reply Don <nospam nospam.com> writes:
Walter Bright wrote:
 Don wrote:
 Consider this notorious piece of code:

 assert(x>1);
 double y = 1 / x;

 This calculates y as the reciprocal of x, if x is a floating-point 
 number. But if x is an integer, an integer division is performed 
 instead of a floating-point one, and y will be 0.

 It's a very common newbie trap, but I find it still catches me 
 occasionally, especially when dividing two variables or compile-time 
 constants.

 In the opPow thread there were a couple of mentions of inadvertent 
 integer division, and how Python is removing this error by making / 
 always mean floating-point division, and introducing a new operator 
 for integer division.

 We could largely eliminate this type of bug without doing anything so 
 drastic. Most of the problem just comes from C's cavalier attitude to 
 implicit casting. All we'd need to do is tighten the implicit 
 conversion rules for int->float, in the same way that the int->uint 
 rules have been tightened:

 "If an integer expression has an inexact result (ie, involves an 
 inexact integer divison), that expression cannot be implicitly cast to 
 a floating-point type."
But the compiler cannot reliably tell if it will produce an inexact result.
 (This means that double y = int_val / 1;  is OK, and also:
  double z = 90/3; would be OK. An alternative rule would be:
 "If an integer expression involves integer divison, that expression 
 cannot be implicitly cast to a floating-point type").
This is kinda complicated if one has, say: double z = x/y + 3;
Integer expressions remain inexact until there's a cast. (It's very simple to implement, you just use the integer range code, adding an 'inexact' flag. Division sets the flag, casts clear the flag, everything else just propagates it if a unary operation, or ORs the two flags if a binary operation).
Dec 14 2009
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
Don Wrote:

 Walter Bright wrote:
 Don wrote:
 (This means that double y = int_val / 1;  is OK, and also:
  double z = 90/3; would be OK. An alternative rule would be:
 "If an integer expression involves integer divison, that expression 
 cannot be implicitly cast to a floating-point type").
This is kinda complicated if one has, say: double z = x/y + 3;
Integer expressions remain inexact until there's a cast. (It's very simple to implement, you just use the integer range code, adding an 'inexact' flag. Division sets the flag, casts clear the flag, everything else just propagates it if a unary operation, or ORs the two flags if a binary operation).
Assuming it really is this easy, I'd love to see the change. I've run into this bug countless times reviewing code, and it can be a tricky one to find. I tend to be pretty particular about always appending the ".0" for literals involved in floating-point assignments for this reason.
Dec 14 2009
parent div0 <div0 users.sourceforge.net> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Sean Kelly wrote:
 Don Wrote:
 
 Walter Bright wrote:
 Don wrote:
 (This means that double y = int_val / 1;  is OK, and also:
  double z = 90/3; would be OK. An alternative rule would be:
 "If an integer expression involves integer divison, that expression 
 cannot be implicitly cast to a floating-point type").
This is kinda complicated if one has, say: double z = x/y + 3;
Integer expressions remain inexact until there's a cast. (It's very simple to implement, you just use the integer range code, adding an 'inexact' flag. Division sets the flag, casts clear the flag, everything else just propagates it if a unary operation, or ORs the two flags if a binary operation).
Assuming it really is this easy, I'd love to see the change. I've run into this bug countless times reviewing code, and it can be a tricky one to find. I tend to be pretty particular about always appending the ".0" for literals involved in floating-point assignments for this reason.
Ditto. - -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iD8DBQFLJpLwT9LetA9XoXwRAmejAKCcoo9VMgotTyYugy+bLGjyr4iFKgCgvmSH l39YGMF98WLx5gaJ7HtcrZg= =FYgY -----END PGP SIGNATURE-----
Dec 14 2009
prev sibling next sibling parent lws <invalid email.com> writes:
On 2009-12-14 03:16:27 -0800, Don <nospam nospam.com> said:

 Walter Bright wrote:
 Don wrote:
 Consider this notorious piece of code:
 
 assert(x>1);
 double y = 1 / x;
 
 This calculates y as the reciprocal of x, if x is a floating-point 
 number. But if x is an integer, an integer division is performed 
 instead of a floating-point one, and y will be 0.
 
 It's a very common newbie trap, but I find it still catches me 
 occasionally, especially when dividing two variables or compile-time 
 constants.
 
 In the opPow thread there were a couple of mentions of inadvertent 
 integer division, and how Python is removing this error by making / 
 always mean floating-point division, and introducing a new operator for 
 integer division.
 
 We could largely eliminate this type of bug without doing anything so 
 drastic. Most of the problem just comes from C's cavalier attitude to 
 implicit casting. All we'd need to do is tighten the implicit 
 conversion rules for int->float, in the same way that the int->uint 
 rules have been tightened:
 
 "If an integer expression has an inexact result (ie, involves an 
 inexact integer divison), that expression cannot be implicitly cast to 
 a floating-point type."
But the compiler cannot reliably tell if it will produce an inexact result.
 (This means that double y = int_val / 1;  is OK, and also:
  double z = 90/3; would be OK. An alternative rule would be:
 "If an integer expression involves integer divison, that expression 
 cannot be implicitly cast to a floating-point type").
This is kinda complicated if one has, say: double z = x/y + 3;
Integer expressions remain inexact until there's a cast. (It's very simple to implement, you just use the integer range code, adding an 'inexact' flag. Division sets the flag, casts clear the flag, everything else just propagates it if a unary operation, or ORs the two flags if a binary operation).
Seems like when the product of integer devision is cast to a double is when it should produce a warning. -SC
Dec 14 2009
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Don wrote:
 Integer expressions remain inexact until there's a cast.
 
 (It's very simple to implement, you just use the integer range code, 
 adding an 'inexact' flag. Division sets the flag, casts clear the flag, 
 everything else just propagates it if a unary operation, or ORs the two 
 flags if a binary operation).
That sounds like a very good idea.
Dec 14 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Walter Bright wrote:
 Don wrote:
 Integer expressions remain inexact until there's a cast.

 (It's very simple to implement, you just use the integer range code, 
 adding an 'inexact' flag. Division sets the flag, casts clear the 
 flag, everything else just propagates it if a unary operation, or ORs 
 the two flags if a binary operation).
That sounds like a very good idea.
I think the same (though I personally am not liable because it's been burned in my brain to always add ".0" to FP-involved literals). It's an improvement in the same vein as value range propagation. Should we make this part of the language, or as a quality of implementation issue? I prefer the former, because the latter means that code compiles on one machine and doesn't on another. Andrei
Dec 15 2009
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Don:
 In the opPow thread there were a couple of mentions of inadvertent 
 integer division, and how Python is removing this error by making / 
 always mean floating-point division, and introducing a new operator for 
 integer division.
In Pascal too (and OCaML, but the situation is different) they are separated. I think here having two operators is better, Niklaus Wirth was right again (but I don't know if D can grow another division operator, it's unlikely). Bye, bearophile
Dec 14 2009
parent reply Don <nospam nospam.com> writes:
bearophile wrote:
 Don:
 In the opPow thread there were a couple of mentions of inadvertent 
 integer division, and how Python is removing this error by making / 
 always mean floating-point division, and introducing a new operator for 
 integer division.
In Pascal too (and OCaML, but the situation is different) they are separated. I think here having two operators is better,
Why? Niklaus Wirth was right again (but I don't know if D can grow another division operator, it's unlikely).
 
 Bye,
 bearophile
Dec 14 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Don:
 In Pascal too (and OCaML, but the situation is different) they are separated.
I think here having two operators is better, 
Why?
You are intelligent and expert so you must know my answer, so I fear yours is a trick question :-) Two operators allow to reduce the need for casts (and rounding/truncation), and are more explicit, allowing the code to express its meaning better to people that come after the original programmer. You can put them in the middle of a long expression, so you know what it's happening in the middle of it. This is useful for programming newbies too. I know there's a C translation of every usage of those two operators, but this is beside the point: even if the Laws of C language are sometimes explicit, sometimes they are not so natural and easy to remember, because normal people are not computers. Not every part of the C language is designed perfectly, there's space for improvements. Bye, bearophile
Dec 14 2009
next sibling parent "Aelxx" <aelxx yandex.ru> writes:
"bearophile" <bearophileHUGS lycos.com> wrote:
 Don:
 In Pascal too (and OCaML, but the situation is different) they are 
 separated. I think here having two operators is better,
Why?
You are intelligent and expert so you must know my answer, so I fear yours is a trick question :-) Two operators allow to reduce the need for casts (and rounding/truncation), and are more explicit, allowing the code to express its meaning better to people that come after the original programmer. You can put them in the middle of a long expression, so you know what it's happening in the middle of it. This is useful for programming newbies too. I know there's a C translation of every usage of those two operators, but this is beside the point: even if the Laws of C language are sometimes explicit, sometimes they are not so natural and easy to remember, because normal people are not computers. Not every part of the C language is designed perfectly, there's space for improvements. Bye, bearophile
I like Pascal having / for floating-point and div for integers. It's rather intuiteve that 1/2 = 0.5 and 1 div 2 = 0. Or worse - what newbies use to input things like : const int b=1, a=0, n = 10 ; double h = (b-a)/n ; // haha who expect it be 0.0 As fact integer division is very different operation then floating point one. IMHO giving them one is a little like giving < and > operators second usage for templates. But besides that all it's only a convenience issue. Having enough expierience and making explicit casting is rather quick thing.
Dec 14 2009
prev sibling parent reply Don <nospam nospam.com> writes:
bearophile wrote:
 Don:
 In Pascal too (and OCaML, but the situation is different) they are separated.
I think here having two operators is better, 
Why?
You are intelligent and expert so you must know my answer, so I fear yours is a trick question :-)
No, it's not a trick question. You've used Python extensively, I haven't.
 Two operators allow to reduce the need for casts (and rounding/truncation),
and are more explicit, allowing the code to express its meaning better to
people that come after the original programmer.
OK. I'm trying to get most of the benefits without needing an extra operator. What I wonder is, in what contexts is / ambiguous or difficult to read? My feeling is that intentionally mixing integer division and floating-point in the same expression is extremely rare. The effect of my rule would be, that if you see an int anywhere, it's an integer division; and if you see a floating point number anywhere, it's a floating point division. BTW, does Python allow integer division of floating point numbers? eg, int_a = float_b // float_c; ? (meaning cast(int)float_b / (cast(int)float_c); ). My idea fails if: * I'm completely wrong about the frequency of mixing integer division with floating point. So the cost is high. OR * Inadvertant integer division commonly occurs in things like int a = b/c; (which would mean that I'm wrong in assuming it's primarily an implicit casting problem). If the benefit is low, it's not much use. OR * There's something I didn't think of. Which is quite probable <g>.
 You can put them in the middle of a long expression, so you know what it's
happening in the middle of it. This is useful for programming newbies too. 
I know there's a C translation of every usage of those two operators, but this
is beside the point: even if the Laws of C language are sometimes explicit,
sometimes they are not so natural and easy to remember, because normal people
are not computers.
Yeah, I agree. C never errs on the side of caution <g>. Much of D involves tightening things up considerably.
Dec 14 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Don:

You've used Python extensively, I haven't.<
The situation with Python isn't the same of D because Python has dynamic typing, so your operations must always know what they return (and their return type can change when necessary).
in what contexts is / ambiguous or difficult to read?<
A silly example, maybe useless for you: auto x = 5 / foo();
BTW, does Python allow integer division of floating point numbers?<
This is how Python2.x used to work:
 5 / 2
2
 -5 / 2
-3
 5.0 / 2
2.5
 5 / 2.0
2.5
 -5.0 / 2
-2.5 This is how Python3.x now works:
 from __future__ import division
 5 / 2
2.5
 -5 / 2
-2.5
 5.0 / 2
2.5
 5 / 2.0
2.5
 -5.0 / 2
-2.5
 5 // 2
2
 -5 // 2
-3
 5.0 // 2
2.0
 5 // 2.0
2.0
 -5.0 // 2
-3.0 I am not saying that Python behaviour is the best possible :-) I think I'd like // to always return a int. In Pascal: int / int => float float / int => float int / float => float float / float => float int div int => int float div int => idontremember int div float => idontremember Bye, bearophile
Dec 14 2009
prev sibling next sibling parent reply "Bob Jones" <me not.com> writes:
"Don" <nospam nospam.com> wrote in message 
news:hg5nkk$1n37$1 digitalmars.com...
 bearophile wrote:
 Don:
 In Pascal too (and OCaML, but the situation is different) they are 
 separated. I think here having two operators is better,
Why?
You are intelligent and expert so you must know my answer, so I fear yours is a trick question :-)
No, it's not a trick question. You've used Python extensively, I haven't.
 Two operators allow to reduce the need for casts (and 
 rounding/truncation), and are more explicit, allowing the code to express 
 its meaning better to people that come after the original programmer.
OK. I'm trying to get most of the benefits without needing an extra operator.
Having made the switch from Delphi to C++ a few years ago I ran into this alot. I dislike that I have to litter my arithmetic expresions with casts in order to get the division operator to do what I want it to. And I suspect all of those who are used to having seperate intdiv & fltdiv operators will agree. So using cast(int) to mean "actualy I did intend the integer division inside the following expression" instead of it's usual "convert this to" makes an ugly situation even more so imo. The fact that adding a specific intdiv operator would not only avoid more casting, but remove the the need for casting in a lot of existing cases should count pretty well against the "no more operator/keywords" argument. Imo it should count enough to override it. But i guess cheap&ugly is more likely to make it in than expensive&expresive&ellegant.
Dec 14 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Bob Jones:
 The fact that adding a specific intdiv operator would not only avoid more 
 casting, but remove the the need for casting in a lot of existing cases 
 should count pretty well against the "no more operator/keywords" argument.
In D you can't use // used in Python, because it's used to denote comments and this will not change. You probably can't use "div" beause that adds another keyword, and people don't like that. And it goes against the C usage of using symbols for operators (so for example D devs don't like 'or' and 'and' as boolean operators, even if they can avoid some of the bugs caused by writing & instead of && or the other way). You can't use \ (it's also not different enough to tell them apart well). I don't know if you can use \\. Even if you find a fitting operator, how can you restrict \ to just floating point division and keep some compatibility with C code? Bye, bearophile
Dec 14 2009
parent "Bob Jones" <me not.com> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:hg6rns$ta6$1 digitalmars.com...
 Even if you find a fitting operator, how can you restrict \ to just 
 floating point division
 and keep some compatibility with C code?
Isnt compatibility with C already broken anyway? But yeah if C compatibility is a condition then I dont see how to get around it. Weird thing is I get the impression that breaking compatibility between D and C is more of a sin than breaking compatibility between versions D. Is source compatibility with C really that important? Surely link compatibility should be enough?
Dec 14 2009
prev sibling parent reply Don <nospam nospam.com> writes:
Bob Jones wrote:
 "Don" <nospam nospam.com> wrote in message 
 news:hg5nkk$1n37$1 digitalmars.com...
 bearophile wrote:
 Don:
 In Pascal too (and OCaML, but the situation is different) they are 
 separated. I think here having two operators is better,
Why?
You are intelligent and expert so you must know my answer, so I fear yours is a trick question :-)
No, it's not a trick question. You've used Python extensively, I haven't.
 Two operators allow to reduce the need for casts (and 
 rounding/truncation), and are more explicit, allowing the code to express 
 its meaning better to people that come after the original programmer.
OK. I'm trying to get most of the benefits without needing an extra operator.
Having made the switch from Delphi to C++ a few years ago I ran into this alot. I dislike that I have to litter my arithmetic expresions with casts in order to get the division operator to do what I want it to. And I suspect all of those who are used to having seperate intdiv & fltdiv operators will agree.
Your arithmetic expressions would only become "littered with casts" if you regularly use integer division inside floating-point expressions. Personally, I cannot recall *ever* having intentionally used integer division inside a floating point expression. (I've seen inadvertent uses of it, plenty of times).
 So using cast(int) to mean "actualy I did intend the integer division inside 
 the following expression" instead of it's usual "convert this to" makes an 
 ugly situation even more so imo.
Well, it's really a bizarre situation. It's a very strange thing to be doing.
 The fact that adding a specific intdiv operator would not only avoid more 
 casting, but remove the the need for casting in a lot of existing cases 
I bet there are negligible cases where casting is required.
 should count pretty well against the "no more operator/keywords" argument. 
 Imo it should count enough to override it.
 
 But i guess cheap&ugly is more likely to make it in than 
 expensive&expresive&ellegant.
Dec 15 2009
parent reply "Bob Jones" <me not.com> writes:
"Don" <nospam nospam.com> wrote in message 
news:hg7gbm$1vln$1 digitalmars.com...
 Bob Jones wrote:
 "Don" <nospam nospam.com> wrote in message 
 news:hg5nkk$1n37$1 digitalmars.com...
 bearophile wrote:
 Don:
 In Pascal too (and OCaML, but the situation is different) they are 
 separated. I think here having two operators is better,
Why?
You are intelligent and expert so you must know my answer, so I fear yours is a trick question :-)
No, it's not a trick question. You've used Python extensively, I haven't.
 Two operators allow to reduce the need for casts (and 
 rounding/truncation), and are more explicit, allowing the code to 
 express its meaning better to people that come after the original 
 programmer.
OK. I'm trying to get most of the benefits without needing an extra operator.
Having made the switch from Delphi to C++ a few years ago I ran into this alot. I dislike that I have to litter my arithmetic expresions with casts in order to get the division operator to do what I want it to. And I suspect all of those who are used to having seperate intdiv & fltdiv operators will agree.
Your arithmetic expressions would only become "littered with casts" if you regularly use integer division inside floating-point expressions. Personally, I cannot recall *ever* having intentionally used integer division inside a floating point expression. (I've seen inadvertent uses of it, plenty of times).
I grepped around 60 instances of double y = a / double(b); In my last project. That's what I'm talking about. Where you have to cast either top or bottom to float in order to get the division operator to do float division of two int operands. There's also the (perhaps MSVC specific) issue that I have to cast doubles to floats to get rid of the loss of precision warning message. It's a usuful warning on ints, but for floats it's completely redundant imo.
 The fact that adding a specific intdiv operator would not only avoid more 
 casting, but remove the the need for casting in a lot of existing cases
I bet there are negligible cases where casting is required.
I didnt find any instances of an expresion containg intdiv being assigned to a float, so yeah, that is rare. But not the case where you have two ints and want the actual division done in float.
Dec 15 2009
parent reply Don <nospam nospam.com> writes:
Bob Jones wrote:
 "Don" <nospam nospam.com> wrote in message 
 news:hg7gbm$1vln$1 digitalmars.com...
 Bob Jones wrote:
 "Don" <nospam nospam.com> wrote in message 
 news:hg5nkk$1n37$1 digitalmars.com...
 bearophile wrote:
 Don:
 In Pascal too (and OCaML, but the situation is different) they are 
 separated. I think here having two operators is better,
Why?
You are intelligent and expert so you must know my answer, so I fear yours is a trick question :-)
No, it's not a trick question. You've used Python extensively, I haven't.
 Two operators allow to reduce the need for casts (and 
 rounding/truncation), and are more explicit, allowing the code to 
 express its meaning better to people that come after the original 
 programmer.
OK. I'm trying to get most of the benefits without needing an extra operator.
Having made the switch from Delphi to C++ a few years ago I ran into this alot. I dislike that I have to litter my arithmetic expresions with casts in order to get the division operator to do what I want it to. And I suspect all of those who are used to having seperate intdiv & fltdiv operators will agree.
Your arithmetic expressions would only become "littered with casts" if you regularly use integer division inside floating-point expressions. Personally, I cannot recall *ever* having intentionally used integer division inside a floating point expression. (I've seen inadvertent uses of it, plenty of times).
I grepped around 60 instances of double y = a / double(b); In my last project. That's what I'm talking about. Where you have to cast either top or bottom to float in order to get the division operator to do float division of two int operands.
OK, I misunderstood you. You're completely right. At least my proposal won't let them slip through silently. I don't think we can do anything else without silently breaking C compatibility.
 There's also the (perhaps MSVC specific) issue that I have to cast doubles 
 to floats to get rid of the loss of precision warning message. It's a usuful 
 warning on ints, but for floats it's completely redundant imo.
 
 
 The fact that adding a specific intdiv operator would not only avoid more 
 casting, but remove the the need for casting in a lot of existing cases
I bet there are negligible cases where casting is required.
I didnt find any instances of an expresion containg intdiv being assigned to a float, so yeah, that is rare. But not the case where you have two ints and want the actual division done in float.
Dec 15 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Don:

 Bob Jones:
 double y = a / double(b);
 OK, I misunderstood you. You're completely right. At least my proposal 
 won't let them slip through silently. I don't think we can do anything 
 else without silently breaking C compatibility.
A silly idea that may keep C compatibility and avoid that cast: instead of an integer division operator it can be added a operator that always performs a floating point division, as: int a = 5, b = 7; double y = a \\ b; (I don't like that much, Pascal is better here). Bye, bearophile
Dec 15 2009
next sibling parent reply KennyTM~ <kennytm gmail.com> writes:
On Dec 16, 09 05:14, bearophile wrote:
 Don:

 Bob Jones:
 double y = a / double(b);
 OK, I misunderstood you. You're completely right. At least my proposal
 won't let them slip through silently. I don't think we can do anything
 else without silently breaking C compatibility.
A silly idea that may keep C compatibility and avoid that cast: instead of an integer division operator it can be added a operator that always performs a floating point division, as: int a = 5, b = 7; double y = a \\ b; (I don't like that much, Pascal is better here). Bye, bearophile
Just introduce real fdiv(real, real) (or /fdiv/) if this is the solution. Works right now without changing the language.
Dec 15 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"KennyTM~" <kennytm gmail.com> wrote in message 
news:hg90tu$22od$1 digitalmars.com...
 On Dec 16, 09 05:14, bearophile wrote:
 Don:

 Bob Jones:
 double y = a / double(b);
 OK, I misunderstood you. You're completely right. At least my proposal
 won't let them slip through silently. I don't think we can do anything
 else without silently breaking C compatibility.
A silly idea that may keep C compatibility and avoid that cast: instead of an integer division operator it can be added a operator that always performs a floating point division, as: int a = 5, b = 7; double y = a \\ b; (I don't like that much, Pascal is better here). Bye, bearophile
Just introduce real fdiv(real, real) (or /fdiv/) if this is the solution. Works right now without changing the language.
Reserving the only division operator for intdiv-only for the sake of C compatibility would be terrible design.
Dec 15 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Nick Sabalausky:
 Reserving the only division operator for intdiv-only for the sake of C 
 compatibility would be terrible design.
Well, no, the (silly) idea is: int / int => int int \\ int => float float / int => float float \\ int => float int / float => float int \\ float => float float / float => float float \\ float => float So the / is not just the int division. The only difference between the two operators is when you have (int,int). Bye, bearophile
Dec 15 2009
prev sibling parent KennyTM~ <kennytm gmail.com> writes:
On Dec 16, 09 06:17, Nick Sabalausky wrote:
 "KennyTM~"<kennytm gmail.com>  wrote in message
 news:hg90tu$22od$1 digitalmars.com...
 On Dec 16, 09 05:14, bearophile wrote:
 Don:

 Bob Jones:
 double y = a / double(b);
 OK, I misunderstood you. You're completely right. At least my proposal
 won't let them slip through silently. I don't think we can do anything
 else without silently breaking C compatibility.
A silly idea that may keep C compatibility and avoid that cast: instead of an integer division operator it can be added a operator that always performs a floating point division, as: int a = 5, b = 7; double y = a \\ b; (I don't like that much, Pascal is better here). Bye, bearophile
Just introduce real fdiv(real, real) (or /fdiv/) if this is the solution. Works right now without changing the language.
Reserving the only division operator for intdiv-only for the sake of C compatibility would be terrible design.
Just introduce real fdiv(real, real) (or /fdiv/) **if this is the solution.** One could also force / to return a real and introduce intdiv(). <off-topic>but if C compatibility is to be broken I'd like to see the comma operator be replaced instead.</off-topic>
Dec 15 2009
prev sibling parent Leandro Lucarella <llucax gmail.com> writes:
bearophile, el 15 de diciembre a las 16:14 me escribiste:
 Don:
 
 Bob Jones:
 double y = a / double(b);
 OK, I misunderstood you. You're completely right. At least my proposal 
 won't let them slip through silently. I don't think we can do anything 
 else without silently breaking C compatibility.
A silly idea that may keep C compatibility and avoid that cast: instead of an integer division operator it can be added a operator that always performs a floating point division, as: int a = 5, b = 7; double y = a \\ b; (I don't like that much, Pascal is better here).
What about ./ for floating point division? Maybe it introduces some kind of ambiguity with 1./2, but fortunately the result should be the same if that means 1. / 2 or 1 ./ 2: 0.5 =) -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- He andáu muchos caminos, muchos caminos he andáu, Chile tiene el buen vino y Suecia, el bacalao. Esta'o Unido tiene el hot do', Cuba tiene el mojito, Guatemala, el cornalito y Brasil la feishoada.
Dec 15 2009
prev sibling parent Peter <nospam nospam.org> writes:
Don Wrote:
 BTW, does Python allow integer division of floating point numbers?
 eg, int_a  = float_b // float_c;   ?
 (meaning cast(int)float_b / (cast(int)float_c); ).
Python doesn't have integer division, but floor division, and it's perefctly valid if arguments are floats, as name says it's just floor of true division, also python define modulo on floats, so expression a//b * b + a%b == a is always true for builtin numerc types (except if at least one of arguments being inf, NaN, or b = 0)
Dec 14 2009
prev sibling next sibling parent "Saaa" <empty needmail.com> writes:
Don wrote
 Consider this notorious piece of code:

 assert(x>1);
 double y = 1 / x;

 This calculates y as the reciprocal of x, if x is a floating-point number. 
 But if x is an integer, an integer division is performed instead of a 
 floating-point one, and y will be 0.

 It's a very common newbie trap
Agreed! :(
Dec 14 2009
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Don Wrote:

 Walter Bright wrote:
 Don wrote:
 Consider this notorious piece of code:

 assert(x>1);
 double y = 1 / x;

 This calculates y as the reciprocal of x, if x is a floating-point 
 number. But if x is an integer, an integer division is performed 
 instead of a floating-point one, and y will be 0.

 It's a very common newbie trap, but I find it still catches me 
 occasionally, especially when dividing two variables or compile-time 
 constants.

 In the opPow thread there were a couple of mentions of inadvertent 
 integer division, and how Python is removing this error by making / 
 always mean floating-point division, and introducing a new operator 
 for integer division.

 We could largely eliminate this type of bug without doing anything so 
 drastic. Most of the problem just comes from C's cavalier attitude to 
 implicit casting. All we'd need to do is tighten the implicit 
 conversion rules for int->float, in the same way that the int->uint 
 rules have been tightened:

 "If an integer expression has an inexact result (ie, involves an 
 inexact integer divison), that expression cannot be implicitly cast to 
 a floating-point type."
But the compiler cannot reliably tell if it will produce an inexact result.
 (This means that double y = int_val / 1;  is OK, and also:
  double z = 90/3; would be OK. An alternative rule would be:
 "If an integer expression involves integer divison, that expression 
 cannot be implicitly cast to a floating-point type").
This is kinda complicated if one has, say: double z = x/y + 3;
Integer expressions remain inexact until there's a cast. (It's very simple to implement, you just use the integer range code, adding an 'inexact' flag. Division sets the flag, casts clear the flag, everything else just propagates it if a unary operation, or ORs the two flags if a binary operation).
What about function calls? double z = abs(x/y); Regardless, your proposal is a simple incremental improvement, and I'd love to see it in D. Also, one more thought: should similar rigor be used for implicit float -> double conversions?
Dec 14 2009
parent reply Don <nospam nospam.com> writes:
Jason House wrote:
 Don Wrote:
 
 Walter Bright wrote:
 Don wrote:
 Consider this notorious piece of code:

 assert(x>1);
 double y = 1 / x;

 This calculates y as the reciprocal of x, if x is a floating-point 
 number. But if x is an integer, an integer division is performed 
 instead of a floating-point one, and y will be 0.

 It's a very common newbie trap, but I find it still catches me 
 occasionally, especially when dividing two variables or compile-time 
 constants.

 In the opPow thread there were a couple of mentions of inadvertent 
 integer division, and how Python is removing this error by making / 
 always mean floating-point division, and introducing a new operator 
 for integer division.

 We could largely eliminate this type of bug without doing anything so 
 drastic. Most of the problem just comes from C's cavalier attitude to 
 implicit casting. All we'd need to do is tighten the implicit 
 conversion rules for int->float, in the same way that the int->uint 
 rules have been tightened:

 "If an integer expression has an inexact result (ie, involves an 
 inexact integer divison), that expression cannot be implicitly cast to 
 a floating-point type."
But the compiler cannot reliably tell if it will produce an inexact result.
 (This means that double y = int_val / 1;  is OK, and also:
  double z = 90/3; would be OK. An alternative rule would be:
 "If an integer expression involves integer divison, that expression 
 cannot be implicitly cast to a floating-point type").
This is kinda complicated if one has, say: double z = x/y + 3;
Integer expressions remain inexact until there's a cast. (It's very simple to implement, you just use the integer range code, adding an 'inexact' flag. Division sets the flag, casts clear the flag, everything else just propagates it if a unary operation, or ORs the two flags if a binary operation).
What about function calls? double z = abs(x/y);
Yeah, it won't catch cases where there are both integer and floating-point overloads of the same function. abs() and pow() are the only two I can think of -- and pow() will be covered by ^^. There's probably a few others.
 Regardless, your proposal is a simple incremental improvement, and I'd love to
see it in D.
 
 Also, one more thought: should similar rigor be used for implicit float ->
double conversions?
That would be much more complicated, I think. Fortunately you're much better protected in such conversions. For example, if a double is too large to fit inside a float, double -> float returns float.infinity. But perhaps you can think of specific bugs which could be caught?
Dec 15 2009
parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Don wrote:
 Jason House wrote:
 Don Wrote:

 Walter Bright wrote:
 Don wrote:
 Consider this notorious piece of code:

 assert(x>1);
 double y = 1 / x;

 This calculates y as the reciprocal of x, if x is a floating-point 
 number. But if x is an integer, an integer division is performed 
 instead of a floating-point one, and y will be 0.

 It's a very common newbie trap, but I find it still catches me 
 occasionally, especially when dividing two variables or 
 compile-time constants.

 In the opPow thread there were a couple of mentions of inadvertent 
 integer division, and how Python is removing this error by making / 
 always mean floating-point division, and introducing a new operator 
 for integer division.

 We could largely eliminate this type of bug without doing anything 
 so drastic. Most of the problem just comes from C's cavalier 
 attitude to implicit casting. All we'd need to do is tighten the 
 implicit conversion rules for int->float, in the same way that the 
 int->uint rules have been tightened:

 "If an integer expression has an inexact result (ie, involves an 
 inexact integer divison), that expression cannot be implicitly cast 
 to a floating-point type."
But the compiler cannot reliably tell if it will produce an inexact result.
 (This means that double y = int_val / 1;  is OK, and also:
  double z = 90/3; would be OK. An alternative rule would be:
 "If an integer expression involves integer divison, that expression 
 cannot be implicitly cast to a floating-point type").
This is kinda complicated if one has, say: double z = x/y + 3;
Integer expressions remain inexact until there's a cast. (It's very simple to implement, you just use the integer range code, adding an 'inexact' flag. Division sets the flag, casts clear the flag, everything else just propagates it if a unary operation, or ORs the two flags if a binary operation).
What about function calls? double z = abs(x/y);
Yeah, it won't catch cases where there are both integer and floating-point overloads of the same function. abs() and pow() are the only two I can think of -- and pow() will be covered by ^^. There's probably a few others.
I think the most subtle cases will be calls to max() and min(). If you do x = max(1.2, 3/2); and the 'inexact' flag doesn't survive beyond the function call, there will be a silent conversion to double inside max() and the function will return 1.2. But it's probably not a very common problem. -Lars
Dec 15 2009
parent reply Don <nospam nospam.com> writes:
Lars T. Kyllingstad wrote:
 Don wrote:
 Jason House wrote:
 Don Wrote:

 Walter Bright wrote:
 Don wrote:
 Consider this notorious piece of code:

 assert(x>1);
 double y = 1 / x;

 This calculates y as the reciprocal of x, if x is a floating-point 
 number. But if x is an integer, an integer division is performed 
 instead of a floating-point one, and y will be 0.

 It's a very common newbie trap, but I find it still catches me 
 occasionally, especially when dividing two variables or 
 compile-time constants.

 In the opPow thread there were a couple of mentions of inadvertent 
 integer division, and how Python is removing this error by making 
 / always mean floating-point division, and introducing a new 
 operator for integer division.

 We could largely eliminate this type of bug without doing anything 
 so drastic. Most of the problem just comes from C's cavalier 
 attitude to implicit casting. All we'd need to do is tighten the 
 implicit conversion rules for int->float, in the same way that the 
 int->uint rules have been tightened:

 "If an integer expression has an inexact result (ie, involves an 
 inexact integer divison), that expression cannot be implicitly 
 cast to a floating-point type."
But the compiler cannot reliably tell if it will produce an inexact result.
 (This means that double y = int_val / 1;  is OK, and also:
  double z = 90/3; would be OK. An alternative rule would be:
 "If an integer expression involves integer divison, that 
 expression cannot be implicitly cast to a floating-point type").
This is kinda complicated if one has, say: double z = x/y + 3;
Integer expressions remain inexact until there's a cast. (It's very simple to implement, you just use the integer range code, adding an 'inexact' flag. Division sets the flag, casts clear the flag, everything else just propagates it if a unary operation, or ORs the two flags if a binary operation).
What about function calls? double z = abs(x/y);
Yeah, it won't catch cases where there are both integer and floating-point overloads of the same function. abs() and pow() are the only two I can think of -- and pow() will be covered by ^^. There's probably a few others.
I think the most subtle cases will be calls to max() and min(). If you do x = max(1.2, 3/2); and the 'inexact' flag doesn't survive beyond the function call, there will be a silent conversion to double inside max() and the function will return 1.2.
Note that that wouldn't happen if max had a signature like: max(double a, double b) or max(T)(T a, T b)
 
 But it's probably not a very common problem.
 
 -Lars
Dec 15 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Don wrote:
 Lars T. Kyllingstad wrote:
 Don wrote:
 Jason House wrote:
 Don Wrote:

 Walter Bright wrote:
 Don wrote:
 Consider this notorious piece of code:

 assert(x>1);
 double y = 1 / x;

 This calculates y as the reciprocal of x, if x is a 
 floating-point number. But if x is an integer, an integer 
 division is performed instead of a floating-point one, and y will 
 be 0.

 It's a very common newbie trap, but I find it still catches me 
 occasionally, especially when dividing two variables or 
 compile-time constants.

 In the opPow thread there were a couple of mentions of 
 inadvertent integer division, and how Python is removing this 
 error by making / always mean floating-point division, and 
 introducing a new operator for integer division.

 We could largely eliminate this type of bug without doing 
 anything so drastic. Most of the problem just comes from C's 
 cavalier attitude to implicit casting. All we'd need to do is 
 tighten the implicit conversion rules for int->float, in the same 
 way that the int->uint rules have been tightened:

 "If an integer expression has an inexact result (ie, involves an 
 inexact integer divison), that expression cannot be implicitly 
 cast to a floating-point type."
But the compiler cannot reliably tell if it will produce an inexact result.
 (This means that double y = int_val / 1;  is OK, and also:
  double z = 90/3; would be OK. An alternative rule would be:
 "If an integer expression involves integer divison, that 
 expression cannot be implicitly cast to a floating-point type").
This is kinda complicated if one has, say: double z = x/y + 3;
Integer expressions remain inexact until there's a cast. (It's very simple to implement, you just use the integer range code, adding an 'inexact' flag. Division sets the flag, casts clear the flag, everything else just propagates it if a unary operation, or ORs the two flags if a binary operation).
What about function calls? double z = abs(x/y);
Yeah, it won't catch cases where there are both integer and floating-point overloads of the same function. abs() and pow() are the only two I can think of -- and pow() will be covered by ^^. There's probably a few others.
I think the most subtle cases will be calls to max() and min(). If you do x = max(1.2, 3/2); and the 'inexact' flag doesn't survive beyond the function call, there will be a silent conversion to double inside max() and the function will return 1.2.
Note that that wouldn't happen if max had a signature like: max(double a, double b) or max(T)(T a, T b)
max takes heterogeneous parameters to catch situations like max(a, 0). Andrei
Dec 15 2009
parent reply Don <nospam nospam.com> writes:
Andrei Alexandrescu wrote:
 Don wrote:
 Lars T. Kyllingstad wrote:
 Don wrote:
 Jason House wrote:
 Don Wrote:

 Walter Bright wrote:
 Don wrote:
 Consider this notorious piece of code:

 assert(x>1);
 double y = 1 / x;

 This calculates y as the reciprocal of x, if x is a 
 floating-point number. But if x is an integer, an integer 
 division is performed instead of a floating-point one, and y 
 will be 0.

 It's a very common newbie trap, but I find it still catches me 
 occasionally, especially when dividing two variables or 
 compile-time constants.

 In the opPow thread there were a couple of mentions of 
 inadvertent integer division, and how Python is removing this 
 error by making / always mean floating-point division, and 
 introducing a new operator for integer division.

 We could largely eliminate this type of bug without doing 
 anything so drastic. Most of the problem just comes from C's 
 cavalier attitude to implicit casting. All we'd need to do is 
 tighten the implicit conversion rules for int->float, in the 
 same way that the int->uint rules have been tightened:

 "If an integer expression has an inexact result (ie, involves an 
 inexact integer divison), that expression cannot be implicitly 
 cast to a floating-point type."
But the compiler cannot reliably tell if it will produce an inexact result.
 (This means that double y = int_val / 1;  is OK, and also:
  double z = 90/3; would be OK. An alternative rule would be:
 "If an integer expression involves integer divison, that 
 expression cannot be implicitly cast to a floating-point type").
This is kinda complicated if one has, say: double z = x/y + 3;
Integer expressions remain inexact until there's a cast. (It's very simple to implement, you just use the integer range code, adding an 'inexact' flag. Division sets the flag, casts clear the flag, everything else just propagates it if a unary operation, or ORs the two flags if a binary operation).
What about function calls? double z = abs(x/y);
Yeah, it won't catch cases where there are both integer and floating-point overloads of the same function. abs() and pow() are the only two I can think of -- and pow() will be covered by ^^. There's probably a few others.
I think the most subtle cases will be calls to max() and min(). If you do x = max(1.2, 3/2); and the 'inexact' flag doesn't survive beyond the function call, there will be a silent conversion to double inside max() and the function will return 1.2.
Note that that wouldn't happen if max had a signature like: max(double a, double b) or max(T)(T a, T b)
max takes heterogeneous parameters to catch situations like max(a, 0). Andrei
Yeah. It's a shame we can't use the ?: type rule for common parameters, since max(T, U) only makes sense when T and U have a common type. So we get code bloat, with unnecessary template instantiations. But it'd be too complicated otherwise, I think. C'est la vie.
Dec 15 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Don wrote:
 Andrei Alexandrescu wrote:
 max takes heterogeneous parameters to catch situations like max(a, 0).

 Andrei
Yeah. It's a shame we can't use the ?: type rule for common parameters, since max(T, U) only makes sense when T and U have a common type. So we get code bloat, with unnecessary template instantiations. But it'd be too complicated otherwise, I think. C'est la vie.
La vie n'est pas si mal. Looking through the implementation of max you'll see that it carefully selects the compatible types, and also computes the correct type for the return value. I don't think there's much, if any, code bloat as well. The operations generated are specialized for the respective types as if you wrote things by hand. Andrei
Dec 15 2009
prev sibling parent reply "Phil Deets" <pjdeets2 gmail.com> writes:
On Mon, 14 Dec 2009 04:57:26 -0500, Don <nospam nospam.com> wrote:

 In the very rare cases where the result of an integer division was  
 actually intended to be stored in a float, an explicit cast would be  
 required. So you'd write:
 double y = cast(int)(1/x);
To me, double y = cast(double)(1/x); makes more sense. Why cast to int?
Dec 14 2009
parent reply Don <nospam nospam.com> writes:
Phil Deets wrote:
 On Mon, 14 Dec 2009 04:57:26 -0500, Don <nospam nospam.com> wrote:
 
 In the very rare cases where the result of an integer division was 
 actually intended to be stored in a float, an explicit cast would be 
 required. So you'd write:
 double y = cast(int)(1/x);
To me, double y = cast(double)(1/x); makes more sense. Why cast to int?
That'd compile, too. But, it's pretty confusing to the reader, because that code will only set y == -1.0, +1.0, +0.0, -0.0, or else create a divide by zero error. So I'd recommend a cast to int.
Dec 15 2009
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 15 Dec 2009 03:02:01 -0500, Don <nospam nospam.com> wrote:

 Phil Deets wrote:
 On Mon, 14 Dec 2009 04:57:26 -0500, Don <nospam nospam.com> wrote:

 In the very rare cases where the result of an integer division was  
 actually intended to be stored in a float, an explicit cast would be  
 required. So you'd write:
 double y = cast(int)(1/x);
To me, double y = cast(double)(1/x); makes more sense. Why cast to int?
That'd compile, too. But, it's pretty confusing to the reader, because that code will only set y == -1.0, +1.0, +0.0, -0.0, or else create a divide by zero error. So I'd recommend a cast to int.
I agree with Phil, in no situation that I can think of does: T i, j; T k = i/j; U k = cast(T)i/j; Make sense. I'd expect to see cast(U) there. You can think of it as i/j returns an undisclosed type that implicitly casts to T, but not U, even if T implicitly casts to U. Wow, this is bizarre. I like the idea, but the recommendation to cast to int makes no sense to me. I'd also actually recommend this instead: auto y = cast(double)(1/x); On the idea as a whole, I think it's very sound. Note that the only case where it gets ugly (i.e. requiring casts) is when both operands of division are symbols, since it's trivial to turn an integer literal into a floating point. -Steve
Dec 15 2009
parent Don <nospam nospam.com> writes:
Steven Schveighoffer wrote:
 On Tue, 15 Dec 2009 03:02:01 -0500, Don <nospam nospam.com> wrote:
 
 Phil Deets wrote:
 On Mon, 14 Dec 2009 04:57:26 -0500, Don <nospam nospam.com> wrote:

 In the very rare cases where the result of an integer division was 
 actually intended to be stored in a float, an explicit cast would be 
 required. So you'd write:
 double y = cast(int)(1/x);
To me, double y = cast(double)(1/x); makes more sense. Why cast to int?
That'd compile, too. But, it's pretty confusing to the reader, because that code will only set y == -1.0, +1.0, +0.0, -0.0, or else create a divide by zero error. So I'd recommend a cast to int.
I agree with Phil, in no situation that I can think of does: T i, j; T k = i/j; U k = cast(T)i/j; Make sense. I'd expect to see cast(U) there. You can think of it as i/j returns an undisclosed type that implicitly casts to T, but not U, even if T implicitly casts to U. Wow, this is bizarre.
Yeah. (However, mixing integer division with floating point is bizarre to start with. As I mentioned somewhere, I don't think I've ever actually seen it).
 I like the idea, but the recommendation to cast to int makes no sense to 
 me.  I'd also actually recommend this instead:
 
 auto y = cast(double)(1/x);
Fair enough, you won't see the recommendation to cast to int anywhere. But it doesn't really matter much. The important thing is, that by inserting *some* cast, you've drawn attention to the operation. Hopefully, the fact that you got a compiler error will inspire you to put a comment in the code, as well <g>. Personally, I'd always rewrite such a thing as: int z = 1/x; // Note: integer division!! double y = z; Completely separating the integer and floating-point parts.
 On the idea as a whole, I think it's very sound.  Note that the only 
 case where it gets ugly (i.e. requiring casts) is when both operands of 
 division are symbols, since it's trivial to turn an integer literal into 
 a floating point.
Exactly. And I think that's the situation where it happens in practice. Normally, integer literals can be used as floating point literals. This is the one case where integer and floating-point literals have a completely different meaning.
Dec 15 2009