Christopher Schultz wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
André,
On 1/16/2011 8:41 AM, André Warnier wrote:
Ran Berenfeld wrote:
well ...no... first evaluate, then assign. and constants are int by
default.
I think C/C++ would have the same problem...
Maybe.
FYI they do.
But then why does the fact of specifying just the first
right-hand side constant in the calculation as a long, magically change
the whole result into a long ?
(1000 * 60 * 60 * 24 * 365) --> int
(1000L * 60 * 60 * 24 * 365) --> long
Because it promotes the type of the entire expression to "long" and the
laws change for the expression. The assignment works as usual.
There's nothing magical about the first operand: you can cast any of the
operands to trigger this promotion.
Not quite true I think. See note below.
Here's some C code that demonstrates
it (note that Java's long is 64-bit so we need "long long" which has
spotty ANSI support):
$ cat longtime.c
#include <stdio.h>
int main(int argc, char *argv[]) {
int cacheTime1 = (1000 * 60 * 60 * 24 * 365);
long cacheTime2 = ((long)1000 * 60 * 60 * 24 * 365);
long long cacheTime3 = ((long long)1000 * 60 * 60 * 24 * 365);
long long cacheTime4 = (1000 * 60 * 60 * 24 * (long long)365);
printf("%d\n%ld\n%lld\n%lld\n", cacheTime1, cacheTime2, cacheTime3,
cacheTime4);
return 0;
}
cschultz@dev:~/projects/toys$ cc -ansi -pedantic -Wall -o longtime \
longtime.c && ./longtime
longtime.c: In function `main':
longtime.c:4: warning: integer overflow in expression
longtime.c:5: warning: integer overflow in expression
Well here you see the difference with Java.
Java seems to overflow without even a warning.
(Chuck tried to get a warning at compile time, without success.)
One additional remark about the calculations you show above (which also applies
to Java) :
In (1000 * 60 * 60 * 24 * 365), the overflow occurs at the last step, when
multiplying by 365.
So in this particular case you are right, the fact of setting *any* factor of the
multiplication to be a long "saves the day", because subsequent operations will be done in
"long mode", and it is enough to make the last term a long, to avoid the problem.
However, suppose for the sake of argument that a year would have 300 days, and that
instead the OP had expressed his duration like this :
(1000 * 60 * 60 * 24 * 100 * 3L)
Now the calculation overflows an int at the penultimate step (* 100), and setting the last
term to be a long does not help, it's too late.
I think that what happens is :
- the expression is evaluated from left to right, not in one single step
- multiplying an int by a long (in whatever order), is done in long mode and
generates a long
- so, in the original calculation
1000 * 60 is done in int-mode, and generates an int R1
R1 * 60 is done in int-mode, and generates an int R2
R2 * 24 is done in int-mode, and generates an int R3
R3 * 365 is done in int-mode, overflows, but still generates an int
- while
1000 * 60 is done in int-mode, and generates an int R1
R1 * 60 is done in int-mode, and generates an int R2
R2 * 24 is done in int-mode, and generates an int R3
R3 * 365L is done in long-mode, does not overflow, and generates a
correct long
- but with the revised calculation (1000 * 60 * 60 * 24 * 100 * 3.65L):
1000 * 60 is done in int-mode, and generates an int R1
R1 * 60 is done in int-mode, and generates an int R2
R2 * 24 is done in int-mode, and generates an int R3
R3 * 100 is done in int-mode, generating an int R4 which is already
truncated
R4 * 3L would generate a long, but with the error magnified
...
Most languages' behavior are surprising to Perl programmers :)
See below.
Seriously, though, these are the tradeoffs of a strongly-typed language:
you have to be very precise about the way you want calculations to be
performed. The compiler assumes that if you wanted double-precision
integers, you'd ensure that the calculation is done using "long" and not
"int". Presumably, 64-bit operations are (or were) considered slower
than 32-bit operations and so require the coder to specify that 64-bit
operations are desired.
At the cost of truncating the result and obtaining an incorrect one surrepticiously and
without a warning ?
I would find : (long)(1000 * 60 * 60 * 24 * 365)
more intuitive, if it forced the calculation to be done in Long mode (which I suspect it
does not; it probably just "promotes" the truncated result to long before the assignment).
...
No, the clarity is in the fact that the target identifier should be able
to store a double-precision value. It says nothing about calculations
that are assigned to it.
If you saw this, would the result (0.0) confuse you?
double d = 1 / 2;
It would not confuse me, because by now I am ready for anything. But I would find this
just as unintuitive and wrong, for exactly the same reason. What kind of stupid compiler
is this, which requires me to say
double d = 1.0 / 2;
to get a correct result ?
And even then, if the expression was
double d = 1.0 / 3;
I would probably *still* not get a result with the precision afforded by the double d, and
would have to write
double d = 1.0D / 3;
to get it right, right ?
I maintain what I said : a programming language which produces a wrong result, without
even a warning, for an expression as simple as
Long a = (1000 * 60 * 60 * 24 * 365)
should be consigned to iPods and stuff, not used for serious things like Tomcat.
(No wonder after that, that lunar probes go CFIT.)
Incidentally, and since you mentioned it :
C:\WINDOWS>perl
print (1000 * 60 * 60 * 24 * 365);
^Z
31536000000
and even :
C:\WINDOWS>perl
print ("1000" * 60 * 60 * 24 * 365);
^Z
31536000000
and also
C:\WINDOWS>perl
print ("1000.0" * 60 * 60 * 24 * 365);
^Z
31536000000
That's what I call a smart and intuitive language..
:-)
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org