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

Reply via email to