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