Strange calculation problem
Steven Schveighoffer
schveiguy at yahoo.com
Tue Aug 25 04:46:42 PDT 2009
On Tue, 25 Aug 2009 05:35:31 -0400, JPF <no at spam.whatever> wrote:
> I've hit a strange problem somewhere in my code and I narowed it down to
> the following testcase:
> ----------------------
> module test;
> import tango.io.Stdout;
>
> const ulong SIZE_IN_B = (1024 * 1024 * 1024 * 2); /*should be
> 2147483648*/
> void main()
> {
> Stdout.formatln("{0}", SIZE_IN_B); /*but is 18446744071562067968*/
> }
> ----------------------
>
> It happens with or without the parenthesis and without the const as well
> . Am I doing something wrong, or did I just hit a bug?
This is expected and well-defined behavior. It's due to the integer
promotion rules.
What happens is this:
1024 * 1024 * 1024 * 2 => 0x8000_0000, as an int, that's -2147483648 (note
the sign bit).
When promoting an int to a ulong, the compiler goes through the following
steps:
int => long => ulong.
So when going from int to long, it sign-extends the value:
0xffff_ffff_8000_0000 is -2147483648 as a long.
And then changes to ulong, so you get that result.
This is not a bug, and will probably not be changed (it's been this way
since C). It is impossible for the compiler to know whether you wanted
sign extension or not, as some code depends on sign extension.
What you do is clarify to the compiler what you want, as Lars suggested,
define one of the terms as unsigned. Promoting from unsigned int to
unsigned long does not go through a sign extension, so I believe it is
enough to do:
1024U * 1024 * 1024 * 2.
However, since your intent is to assign to a ulong, the best solution is
to specify the literal as Lars indicated, this protects against a possible
future modification which requires a long to store your literal.
-Steve
More information about the Digitalmars-d-learn
mailing list