Issue 12452 - To mitigate unwanted integer division precision loss
Summary: To mitigate unwanted integer division precision loss
Status: ASSIGNED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P4 enhancement
Assignee: Don
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-03-24 07:14 UTC by bearophile_hugs
Modified: 2022-12-17 10:42 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description bearophile_hugs 2014-03-24 07:14:56 UTC
This kind of code sometimes is wrong, because you forget to cast x to double before the division and you lose precision (note that here the compiler knows that the result of the division will go in a floating point variable):


void main() {
    int x = 15;
    double y = x / 10;
}

(The cause is that unfortunately in D the integer division uses the same operator as the FP division. In Python there is the / and // operators. In OcaML there are the / and /., in Delphi there are the / and div operators, in Ada the two operands need to be of the same type).

Seasoned C/C++/D programmers watch for the types every time they perform a division, to avoid that trap, and they often use explicit casts in that kind of code (this uses a recently introduce syntax that avoids the use of a cast()):

double y = double(x) / 10;

But less experienced programmers introduce bugs with divisions. Can D help the programmers reduce the frequency of similar bugs?

- - - - - - - - - - - -

A comment by Daniel Murphy:

> Newbies have to realize that integers aren't real numbers eventually.

I have seen that even programmers with some experience once in a while create this bug. Because you have to keep attention to the types of each division usage, and once in a while your attention slips (or perhaps some bugs of this kind are created by successive type changes).


An example of this possible code found in real code:

Search for "GetTransmission()" in this page:
http://www.viva64.com/en/b/0242/

The possible bug:

int SpectralLMM5Interface::GetTransmission(....,
                                           double& transmission)
{
  ....
  int16_t tr = 0;
  memcpy(&tr, answer + 1, 2);
  tr = ntohs(tr);
  transmission = tr/10;
  ....
}

- - - - - - - - - - - -

Don suggests:

> It is indeed a common floating-point bug.
>
> I came up with a solution for this a couple of years ago, never
> got around to doing a pull request, but it's on the newsgroup
> somewhere. It's a little extension to the range propagation
> implementation. You add a boolean flag to the range, which
> indicates 'a fractional part has been discarded'. This flag gets
> set whenever you perform an integer division (or integer
> exponentiation with a negative power), and is cleared whenever
> there is a cast or a bitwise operation.
>
> Then, disallow implicit casting from integer to floating point
> whenever the fractional bit is set. Catches all these kinds of
> bugs, doesn't require any changes to the language.

- - - - - - - - - - - -
Comment 1 Nick Treleaven 2021-05-26 10:02:20 UTC
> I came up with a solution for this a couple of years ago, never
> got around to doing a pull request, but it's on the newsgroup
> somewhere.

https://forum.dlang.org/post/hg5291$fas$1@digitalmars.com