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