Detecting inadvertent use of integer division

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Tue Dec 15 08:52:11 PST 2009


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



More information about the Digitalmars-d mailing list