Detecting inadvertent use of integer division

Lars T. Kyllingstad public at kyllingen.NOSPAMnet
Tue Dec 15 02:05:47 PST 2009


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



More information about the Digitalmars-d mailing list