Detecting inadvertent use of integer division

Don nospam at nospam.com
Tue Dec 15 01:37:20 PST 2009


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?



More information about the Digitalmars-d mailing list