December 14, 2009 Re: Detecting inadvertent use of integer division | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don | 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
|
December 14, 2009 Re: Detecting inadvertent use of integer division | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don | 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.
|
December 14, 2009 Re: Detecting inadvertent use of integer division | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly Attachments: | 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 |
December 14, 2009 Re: Detecting inadvertent use of integer division | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don | 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 |
December 15, 2009 Re: Detecting inadvertent use of integer division | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don | "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. |
December 15, 2009 Re: Detecting inadvertent use of integer division | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bob Jones | 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
|
December 15, 2009 Re: Detecting inadvertent use of integer division | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don | 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?
|
December 15, 2009 Re: Detecting inadvertent use of integer division | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | "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? |
December 15, 2009 Re: Detecting inadvertent use of integer division | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don | 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)
|
December 15, 2009 Re: Detecting inadvertent use of integer division | ||||
---|---|---|---|---|
| ||||
Posted in reply to Phil Deets | 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.
|
Copyright © 1999-2021 by the D Language Foundation