Java Forum / General / April 2007
Am I Crazy? V. simple math question.
MS - 08 Apr 2007 19:05 GMT Hi,
I haven't programmed in Java for a while and just wrote a program to calc the odds of winning the British national lottery. BUT it is giving me the wrong result !!
Here's the relevant bit:
public void DoCalc() { float winOdds = 49 * 48 * 47 * 46 * 45 * 44; System.out.println(winOdds);
float anyOrder = 6 * 5 * 4 * 3 * 2; System.out.println(anyOrder);
float res = winOdds / anyOrder;
System.out.println(res); }
It outputs:
1.47841293E9 720.0 2053351.2
But the result should be:
10,068,347,520 720 13,983,816
Don't believe me? Paste the following into your calc program:
(49 * 48 * 47 * 46 * 45 * 44) / (6 * 5 * 4 * 3 * 2) =
Or let google do it: http://www.google.co.uk/search?hl=en&q=%2849+*+48+*+47+*+46+*+45+*+44%29+%2F+%28 6+*+5+*+4+*+3+*+2%29+%3D+&btnG=Google+Search&meta=
Am I going crazy? Why doesn't my Java program work?
Please help.
MS
Arne Vajhøj - 08 Apr 2007 19:15 GMT > I haven't programmed in Java for a while and just wrote a program to > calc the odds of winning the British national lottery. BUT it is giving [quoted text clipped - 5 lines] > { > float winOdds = 49 * 48 * 47 * 46 * 45 * 44; I am pretty sure you make an integer overflow here.
try:
float winOdds = 49.0 * 48.0 * 47.0 * 46.0 * 45.0 * 44.0;
> System.out.println(winOdds); > [quoted text clipped - 17 lines] > 720 > 13,983,816 Arne
MS - 08 Apr 2007 19:26 GMT Arne Vajhøj emailed this:
>> I haven't programmed in Java for a while and just wrote a program to >> calc the odds of winning the British national lottery. BUT it is [quoted text clipped - 11 lines] > > float winOdds = 49.0 * 48.0 * 47.0 * 46.0 * 45.0 * 44.0; Many thanks. What you suggested gave a 'possible loss of precision' error, when I swapped the floats to doubles I got the correct result.
Strange oversight by the Java designers that Java doesn't assume the .0 at the end of any real number.
Thanks again.
Lew - 08 Apr 2007 19:50 GMT > Arne Vajhøj emailed this: >>> I haven't programmed in Java for a while and just wrote a program to [quoted text clipped - 18 lines] > Strange oversight by the Java designers that Java doesn't assume the .0 > at the end of any real number. Huh? What "real" numbers?
There was absolutely no oversight on the part of the Java designers here. The compiler worked exactly as documented.
49, 48, 47, et al. are /integers/. <http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.10.1>
not float or double literals <http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.10.2>
You did /integer/ calculation.
Arne pointed out that that cause an /integer/ overflow.
After which you converted the incorrect /integer/ value to float. (Why not double?)
How is the compiler suppose to "assume the [sic] .0" in an integer?
 Signature Lew
MS - 08 Apr 2007 20:03 GMT >> Strange oversight by the Java designers that Java doesn't assume the >> .0 at the end of any real number. > > Huh? What "real" numbers? > ...snip... > How is the compiler suppose to "assume the [sic] .0" in an integer? Good point! Oops. (Bows head in shame).
Eric Sosman - 08 Apr 2007 19:52 GMT > Arne Vajhøj emailed this: >>> I haven't programmed in Java for a while and just wrote a program to [quoted text clipped - 18 lines] > Strange oversight by the Java designers that Java doesn't assume the .0 > at the end of any real number. Strange oversight by the Java programmers who can't distinguish between `int' and `double' constants ...
To put it another way: The eventual "target" of an expression does not influence the way the expression is calculated. You wrote `float winOdds =' and apparently expected the right-hand side to somehow magically understand that it should be evaluated in `float' arithmetic. But the original is an expression involving `int' values multiplied together, so it is evaluated according to the rules of `int'. After the evaluation, the result is converted to `float' for the assignment -- but by then it's too late, the overflow has already occurred and the damage has been done.
Perhaps the commonest situation where this misunderstanding crops up is
double fahrenheit = 212; double celsius = 5 / 9 * (fahrenheit - 32);
As a test of your newfound understanding of how expressions are evaluated, can you say what's wrong with this formula? For extra credit, can you explain why
double celsius = (fahrenheit - 32) * 5 / 9;
works as (presumably) intended?
 Signature Eric Sosman esosman@acm-dot-org.invalid
MS - 08 Apr 2007 20:26 GMT Eric Sosman emailed this:
>> Arne Vajhøj emailed this: >>>> I haven't programmed in Java for a while and just wrote a program to [quoted text clipped - 46 lines] > > works as (presumably) intended? Thanks for the explanation, and all I can say in my defense is I assumed that since I was defining a float I assumed the compiler would assume the '.0'. Obviously I was wrong for the reasons explained. But this would have worked, at least I think:
double a = 49; double b = 48; double c = 47; double d = 46; double e = 45; double f = 44; double res = a * b * c * d * e * f;
which isn't all that different from this:
double res = 49 * 48 * 47 * 46 * 45 * 44;
To TRY to answer your questions.
In the first part of your question...
double fahrenheit = 212; double celsius = 5 / 9 * (fahrenheit - 32);
5 / 9 isn't evaluated to a real number because 5 and 9 are integers.
The 2nd part of your question...
double celsius = (fahrenheit - 32) * 5 / 9;
>works as (presumably) intended? The question says the 2nd formula works. fahrenheit is already a double so presumably that's why it works, but I'm not sure of the reasons. Please explain.
Thanks for your help. (I feel like I'm back at university).
Regards,
MS
Eric Sosman - 08 Apr 2007 20:42 GMT > Eric Sosman emailed this: > [...] [quoted text clipped - 14 lines] > > double res = 49 * 48 * 47 * 46 * 45 * 44; The difference is in when the conversion(s) from `int' to `double' occur. In the multi-line form, each `int' number gets converted to `double' and assigned to its variable, and then all the `double' variables are multiplied in `double' arithmetic. In the single-line form, all the `int' constants are multiplied together in `int' arithmetic (overflowing), and the result is then converted to `double'.
> To TRY to answer your questions. > [quoted text clipped - 4 lines] > > 5 / 9 isn't evaluated to a real number because 5 and 9 are integers. Right. In more detail, `5 / 9' is evaluated according to the rules of `int' arithmetic, yielding the `int' value zero. Inside the parentheses, `32' is converted from `int' to `double' and subtracted from fahrenheit, yielding the `double' value 180.0. Then the zero from the division is converted from `int' to `double' and multiplied with the 180.0, yielding 0.0.
> The 2nd part of your question... > [quoted text clipped - 4 lines] > so presumably that's why it works, but I'm not sure of the reasons. > Please explain. Once again, it's the order of operations. The thing in parentheses is evaluated just as before, producing 180.0. Then the `5' is converted from `int' to `double' and multiplied by 180.0 to yield 900.0 -- note that in this version, the multiplication occurs before, not after, the division. Finally, the `9' is converted from `int' to `double' and the division (done in `double' this time) produces 100.0.
Operation order is important! Consider what you get from your camera when you point-and-shoot, versus what you get when you shoot-and-point ...
 Signature Eric Sosman esosman@acm-dot-org.invalid
MS - 08 Apr 2007 21:43 GMT Eric Sosman emailed this:
>> Eric Sosman emailed this: >> [...] [quoted text clipped - 22 lines] > are multiplied together in `int' arithmetic (overflowing), and > the result is then converted to `double'. Yes, I already understood this, that's why I gave the example.
>> To TRY to answer your questions. >> [quoted text clipped - 11 lines] > 180.0. Then the zero from the division is converted from `int' > to `double' and multiplied with the 180.0, yielding 0.0. Horray !!
>> The 2nd part of your question... >> [quoted text clipped - 12 lines] > the `9' is converted from `int' to `double' and the division > (done in `double' this time) produces 100.0. Well, I got that right too, even if I wasn't exactly sure why.
Many thanks for your help, and for taking the time to post a question to make me think about it properly, and for the follow up reply, which has allowed me to fully understand this kind of evaluation process.
As far as my Java programming is concerned, I should be careful when using real numbers and integers together, that the integers are converted to reals, either done explicitly or by their position in the evaluation order. Can you cast in Java --as you can in C-- like this, which would allow the first formula to work?
double celsius = (double) 5 / (double) 9 * (fahrenheit - (double) 32);
Many thanks again.
Patricia Shanahan - 08 Apr 2007 22:01 GMT ...
> As far as my Java programming is concerned, I should be careful when > using real numbers and integers together, that the integers are [quoted text clipped - 3 lines] > > double celsius = (double) 5 / (double) 9 * (fahrenheit - (double) 32); Indeed you can. I would normally only do it for integer variables. (double)5 and 5.0 have the same value. Using the ".0" syntax has the advantage of working for fractions, and for numbers that are too big for int.
Patricia
Eric Sosman - 08 Apr 2007 22:01 GMT > [...] > As far as my Java programming is concerned, I should be careful when > using real numbers and integers together, that the integers are > converted to reals, either done explicitly or by their position in the > evaluation order. More to the point: You should use the kinds of numbers that are suited to the calculation at hand. Sometimes these are integers (of various sizes), sometimes these are reals (of two precisions), sometimes these are things like BigInteger objects. And sometimes a calculation needs to mix the effects of more than one kind of arithmetic: for example, you might use floating-point arithmetic to compute the 0.52617% monthly interest due on your mortgage, but then use integer arithmetic to round the product to a whole number of pennies.
> Can you cast in Java --as you can in C-- like this, > which would allow the first formula to work? > > double celsius = (double) 5 / (double) 9 * (fahrenheit - (double) 32); Yes. It strikes me -- no insult intended -- that if you don't know this sort of thing, you would do well to invest in a Java textbook. Usenet is a poor channel for transmitting large amounts of information in comprehensible form.
 Signature Eric Sosman esosman@acm-dot-org.invalid
MS - 09 Apr 2007 17:00 GMT >> Can you cast in Java --as you can in C-- like this, which would allow >> the first formula to work? [quoted text clipped - 5 lines] > textbook. Usenet is a poor channel for transmitting large amounts > of information in comprehensible form. I was pretty sure you could do that and no insult taken. As I wrote in my original post 'I haven't programmed in Java for a while' nor will I be doing so very regularly (I do have a rather old Java textbook). I shouldn't have posed the cast version of the formula as a question, more it was just to show that I now understood my original problem sufficiently to demonstrate how to make the first formula work.
Thanks for all your help. Regards, etc..
Joshua Cranmer - 09 Apr 2007 01:24 GMT > double celsius = (double) 5 / (double) 9 * (fahrenheit - (double) 32); Should be: double celsius = ((double) 5)/((double) 9) * (fahrenheit - (double) 32);
Casting is right-associative, so this is what the compiler sees: (double) (5 / (double) (9 * (fahreinheit - (double) (32) ) )
If you wonder why, it's because you want (double) (c.foo()) and not ((double)c).foo() generally.
Stefan Ram - 09 Apr 2007 02:01 GMT >Casting is right-associative, so this is what the compiler sees: >(double) (5 / (double) (9 * (fahreinheit - (double) (32) ) ) >If you wonder why, it's because you want (double) (c.foo()) and not >((double)c).foo() generally. It is perfectly legitimate to be ignorant of Java operators or the notion of associativity, but then you should not write unfounded assertions about those topics. Instead you might read about them, ask about them, or just do something completely different, such as watching a movie.
Joshua Cranmer - 09 Apr 2007 22:25 GMT >> Casting is right-associative, so this is what the compiler sees: >> (double) (5 / (double) (9 * (fahreinheit - (double) (32) ) ) [quoted text clipped - 6 lines] > read about them, ask about them, or just do something > completely different, such as watching a movie. I based this off of something I read somewhere along the line; it appears that I was wrong. However, do not claim that my assertions are unfounded -- they were merely founded on incorrect information. I am neither ignorant of Java operators nor the notion of associativity, as well.
Patricia Shanahan - 09 Apr 2007 02:47 GMT >> double celsius = (double) 5 / (double) 9 * (fahrenheit - (double) 32); > [quoted text clipped - 3 lines] > Casting is right-associative, so this is what the compiler sees: > (double) (5 / (double) (9 * (fahreinheit - (double) (32) ) ) Huh? That is not what the JLS says. See http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.16
Casts operate on unary expressions, and 5 / (double) (9 * (fahreinheit - (double) (32) ) is a multiplicative expression, so it could not be the operand of cast.
If you were right, (double)5/9 would be parsed as (double)(9/5), with result 1.0. This program:
public class CastTest { public static void main(String[] args) { System.out.println((double)9/5); } }
prints "1.8". (double)9 is a double expression, so arithmetic promotion is applied, converting the 5 to double, followed by a double divide.
> If you wonder why, it's because you want (double) (c.foo()) and not > ((double)c).foo() generally. The grouping implied by c.foo() has very high effective precedence. That has nothing at all to do with the relative precedence of cast and divide.
Patricia
Olle - 10 Apr 2007 11:33 GMT > Eric Sosman emailed this: > [quoted text clipped - 77 lines] > > Many thanks again. You could also write:
double celsius = 5d / 9d * (fahrenheit - 32d);
or with less precision:
float celsius = 5f / 9f * (fahrenheit - 32f);
Then you don't need the annoying .0 or (double) typecasts
Olle
Tom Hawtin - 08 Apr 2007 20:05 GMT > Arne Vajhøj emailed this:
>> > float winOdds = 49 * 48 * 47 * 46 * 45 * 44; >> >> I am pretty sure you make an integer overflow here.
>> float winOdds = 49.0 * 48.0 * 47.0 * 46.0 * 45.0 * 44.0; > > Many thanks. What you suggested gave a 'possible loss of precision' > error, when I swapped the floats to doubles I got the correct result. A more literal correction would be to use float literals:
float winOdds = 49.0f * 48.0f * 47.0f * 46.0f * 45.0f * 44.0f;
But doubles are almost always a better choice than floats (exception for large memory use and GPU support).
Another way of doing it is:
float winOdds = 49L * 48L * 47L * 46L * 45L * 44L;
> Strange oversight by the Java designers that Java doesn't assume the .0 > at the end of any real number. It's more shortsightedness in this area. Fixed size integers really should be a thing of the past. Automatic conversion from integer to floating point values is dangerous. Implicit overflows of compile-time constants could have been forced to be explicit.
Tom Hawtin
MS - 08 Apr 2007 20:26 GMT Thanks.
Tom Hawtin emailed this:
>> Arne Vajhøj emailed this: > [quoted text clipped - 27 lines] > > Tom Hawtin Mark Space - 08 Apr 2007 20:31 GMT > Arne Vajhøj emailed this: >> I am pretty sure you make an integer overflow here. [quoted text clipped - 5 lines] > Many thanks. What you suggested gave a 'possible loss of precision' > error, when I swapped the floats to doubles I got the correct result. I think it's strange Java doesn't provide for any kind of overflow error. Anyone know if it's possible to get Java to throw an overflow for calculations like this?
Karl Uppiano - 08 Apr 2007 21:16 GMT >> Arne Vajhøj emailed this: >>> I am pretty sure you make an integer overflow here. [quoted text clipped - 9 lines] > Anyone know if it's possible to get Java to throw an overflow for > calculations like this? That's tricky. For a some operations, integer "overflow" or wrap -- is the desired effect, and follows the JLS rules for int. For floats and doubles, the IEEE rules apply, and they are more like what you would expect for real numbers.
Arne Vajhøj - 08 Apr 2007 21:36 GMT > I think it's strange Java doesn't provide for any kind of overflow > error. Anyone know if it's possible to get Java to throw an overflow > for calculations like this? I do not think so.
It is not a trivial thing to do on many processors including x86.
Arne
Lew - 08 Apr 2007 23:08 GMT Mark Space wrote:
>> I think it's strange Java doesn't provide for any kind of overflow >> error. Anyone know if it's possible to get Java to throw an overflow >> for calculations like this?
> I do not think so. > > It is not a trivial thing to do on many processors including x86. tt is, in fact, forbidden.
<http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.18.2>
> If an integer addition overflows, then the result is the low-order bits of the mathematical sum as represented in some sufficiently large two's-complement format. If overflow occurs, then the sign of the result is not the same as the sign of the mathematical sum of the two operand values.
 Signature Lew
Joshua Cranmer - 09 Apr 2007 01:26 GMT >> I think it's strange Java doesn't provide for any kind of overflow >> error. Anyone know if it's possible to get Java to throw an overflow [quoted text clipped - 5 lines] > > Arne Are you sure? I'm pretty sure the x86 has an instruction to jump if the overflow bit is set, but I'm not sure if multiplication sets the overflow bit...
Arne Vajhøj - 09 Apr 2007 01:31 GMT >>> I think it's strange Java doesn't provide for any kind of overflow >>> error. Anyone know if it's possible to get Java to throw an overflow [quoted text clipped - 7 lines] > overflow bit is set, but I'm not sure if multiplication sets the > overflow bit... I think it has.
But setting a test using that instruction in for all integer arithmetic is not trivial.
The nice way of doing is to have a bit somewhere and it it is set then overflow generates the exception.
Arne
Tom Hawtin - 09 Apr 2007 01:44 GMT > Are you sure? I'm pretty sure the x86 has an instruction to jump if the > overflow bit is set, but I'm not sure if multiplication sets the > overflow bit... IIRC, there's no easy way to check if a multiplication overflows, other than actually calculating the extended value. (That's probably stated in Hacker's Delight, but I don't think my copy is in this country.) If a multiplication instruction sets the overflow flag, I don't think it'll have anything particularly meaningful in the result.
Tom Hawtin
Z. - 09 Apr 2007 03:16 GMT > I think it's strange Java doesn't provide for any kind of overflow > error. Anyone know if it's possible to get Java to throw an overflow > for calculations like this? Me, too. It seems there are exceptions for everything else, so why not integer overflow?
Arne Vajhøj - 09 Apr 2007 03:17 GMT >> I think it's strange Java doesn't provide for any kind of overflow >> error. Anyone know if it's possible to get Java to throw an overflow >> for calculations like this? > > Me, too. It seems there are exceptions for everything else, so why not > integer overflow? As I tried to explain earlier then at many platforms it is problematic to implement.
Arne
Stefan Ram - 09 Apr 2007 03:29 GMT >why not integer overflow? What would be an example (an application), where you need to use an integral numeric type with integer arithmetics and need to detect overflow, and which action would be appropriate in this example for the case of non-overflow and overflow, respectively?
Patricia Shanahan - 09 Apr 2007 03:52 GMT >> why not integer overflow? > [quoted text clipped - 3 lines] > this example for the case of non-overflow and overflow, > respectively? The example would be any Java program that uses int arithmetic.
In the non-overflow case the program should continue executing.
An overflow would indicate a serious programming error, and should be handled the same way as NullPointerException. For almost all programs, it should cause an abort with stack trace.
It may be too late to do int overflow in Java because there is no separate signed and unsigned 32 bit int.
However, some sort of range-limited integer type should be possible on any processor that supports Ada.
Patricia
Luc The Perverse - 09 Apr 2007 07:10 GMT > An overflow would indicate a serious programming error, and should be > handled the same way as NullPointerException. For almost all programs, > it should cause an abort with stack trace. You may want to include that an overflow would typically indicate a serious error.
I have seen deliberate uses of overflow.
-- LTP
:) Karl Uppiano - 09 Apr 2007 08:00 GMT >> An overflow would indicate a serious programming error, and should be >> handled the same way as NullPointerException. For almost all programs, [quoted text clipped - 4 lines] > > I have seen deliberate uses of overflow. Yup, given that ints are often used for bit twiddling, I think we would be handling more overflow exceptions than we might like otherwise. If you want real numbers (in the mathematical sense), use the IEEE floating point types.
Patricia Shanahan - 09 Apr 2007 11:40 GMT >>> An overflow would indicate a serious programming error, and should be >>> handled the same way as NullPointerException. For almost all programs, [quoted text clipped - 7 lines] > handling more overflow exceptions than we might like otherwise. If you want > real numbers (in the mathematical sense), use the IEEE floating point types. One of the worst mistakes in the initial design of Fortran was calling floating point numbers "real". It has caused confusion for over 50 years.
Every floating point number is a rational, and a rational with a denominator that is an integer power of a predetermined constant at that. There is no general way to represent the mathematical reals in computer arithmetic. There cannot be, because there are more real numbers in any non-empty interval than there are finite length strings.
IEEE floating point arithmetic has its own rules that commonly result in different answers from the same operation done in real number arithmetic. It lacks several of the nice properties of real number arithmetic, for example:
Associativity: In real number arithmetic, a+(b+c) == (a+b)+c. That is often false in floating point arithmetic.
Reversibility of some operations: (a*b)/b is not necessarily equal to a, even if b is non-zero.
In any case, range limited integer arithmetic and floating point arithmetic are very different things, solving different problems.
Patricia
John W. Kennedy - 09 Apr 2007 18:15 GMT > One of the worst mistakes in the initial design of Fortran was calling > floating point numbers "real". It has caused confusion for over 50 years. It wasn't in the initial design -- not, at least, in the language; that came with FORTRAN IV. It may be that it was used in the documentation, but I was taught to call the two kinds of variable in FORTRAN II "fixed point" and "floating point".
 Signature John W. Kennedy Read the remains of Shakespeare's lost play, now annotated! http://pws.prserv.net/jwkennedy/Double%20Falshood/index.html * TagZilla 0.066 * http://tagzilla.mozdev.org
Patricia Shanahan - 09 Apr 2007 18:51 GMT >> One of the worst mistakes in the initial design of Fortran was calling >> floating point numbers "real". It has caused confusion for over 50 years. [quoted text clipped - 3 lines] > but I was taught to call the two kinds of variable in FORTRAN II "fixed > point" and "floating point". That is certainly more accurate terminology. I thought "real" was in common use before FORTRAN IV embedded it in the language, but I could be wrong.
Patricia
John W. Kennedy - 09 Apr 2007 22:37 GMT >>> One of the worst mistakes in the initial design of Fortran was calling >>> floating point numbers "real". It has caused confusion for over 50 [quoted text clipped - 8 lines] > common use before FORTRAN IV embedded it in the language, but I could be > wrong. Bitsavers has a 1956 FORTRAN spec that uses "fixed point" and "floating point".
Now I bethink myself on't, 'twas ALGOL that introduced REAL as a keyword. FORTRAN IV, for some reason, followed suit, though PL/I tried to recover the situation. (In PL/I, REAL is merely the negation of COMPLEX.)
Of course, using "fixed point" to mean "integer" introduces its own problems; Ada is the only language I know of that recognizes and handles it.
 Signature John W. Kennedy "The pathetic hope that the White House will turn a Caligula into a Marcus Aurelius is as naïve as the fear that ultimate power inevitably corrupts." -- James D. Barber (1930-2004) * TagZilla 0.066 * http://tagzilla.mozdev.org
Martin Gregorie - 10 Apr 2007 11:36 GMT > Of course, using "fixed point" to mean "integer" introduces its own > problems; Ada is the only language I know of that recognizes and handles > it. Fixed point, to me, doesn't mean integer: it means a fixed number of digits to the right of the decimal point as in the COBOL picture S9(6)v99 which defines a signed value with up to eight significant digits of which two are to the right of the decimal point.
 Signature martin@ | Martin Gregorie gregorie. | Essex, UK org |
John W. Kennedy - 10 Apr 2007 23:02 GMT >> Of course, using "fixed point" to mean "integer" introduces its own >> problems; Ada is the only language I know of that recognizes and >> handles it.
> Fixed point, to me, doesn't mean integer: it means a fixed number of > digits to the right of the decimal point as in the COBOL picture > S9(6)v99 which defines a signed value with up to eight significant > digits of which two are to the right of the decimal point. Yes, but COBOL, RPG, PL/I, and Ada are about the only languages that recognize that in the primary language (Java does in BigDecimal). In other languages, there is a history of using "fixed point" to mean "integer".
And of the languages that do handle full fixed point, only Ada (and Java, counting BigDecimal) recognize that integer arithmetic should be handled as a distinct case from fixed point with q=0.
 Signature John W. Kennedy If Bill Gates believes in "intelligent design", why can't he apply it to Windows? * TagZilla 0.066 * http://tagzilla.mozdev.org
Karl Uppiano - 10 Apr 2007 03:57 GMT >>>> An overflow would indicate a serious programming error, and should be >>>> handled the same way as NullPointerException. For almost all programs, [quoted text clipped - 11 lines] > One of the worst mistakes in the initial design of Fortran was calling > floating point numbers "real". It has caused confusion for over 50 years. I think they were actually trying to distinguish between real numbers and imaginary numbers. Fortran was for scientific and mathematical applications. I remember using Fortran to implement an orbital mechanics program for a physics class I was taking in the mid 1970's. We were quite aware of the possible calculation errors, and had to take care to perform the operations in an order that would minimize the effects of limited precision and dynamic range.
> Every floating point number is a rational, and a rational with a > denominator that is an integer power of a predetermined constant at > that. There is no general way to represent the mathematical reals > in computer arithmetic. There cannot be, because there are more real > numbers in any non-empty interval than there are finite length strings. It is an <i>approximation</i> of real numbers, subject to the limitations of the hardware and the algorithms. Virtual reality, if you will.
> IEEE floating point arithmetic has its own rules that commonly result in > different answers from the same operation done in real number [quoted text clipped - 9 lines] > In any case, range limited integer arithmetic and floating point > arithmetic are very different things, solving different problems. That's right, and the OP selected the wrong data type to solve his problem. No offense intended, but that's what happened. Overflow detection might have prevented confusion on his part, but if we were a fly on the wall when the Java spec was written, we might have heard the argument as to why they did not require that feature.
Lew - 10 Apr 2007 14:30 GMT > That's right, and the OP selected the wrong data type to solve his problem. > No offense intended, but that's what happened. Overflow detection might have > prevented confusion on his part, but if we were a fly on the wall when the > Java spec was written, we might have heard the argument as to why they did > not require that feature. Forbade that feature.
 Signature Lew
John W. Kennedy - 10 Apr 2007 23:30 GMT > I think they were actually trying to distinguish between real numbers and > imaginary numbers. That may have been a factor in introducing the term REAL to FORTRAN IV, but A) it was not used in FORTRAN or FORTRAN II, and B) the extended versions of FORTRAN II that supported complex arithmetic did so by putting "I" in column 1 of every affected statement , just as double precision was achieved by putting "D" in column 1, rather than by adding any new keywords to the language.
> That's right, and the OP selected the wrong data type to solve his problem. > No offense intended, but that's what happened. Overflow detection might have > prevented confusion on his part, but if we were a fly on the wall when the > Java spec was written, we might have heard the argument as to why they did > not require that feature. Because Java was originally aimed at low-end processors (running set-top boxes), where overflow detection comes (or came at the time) at a significant cost, and because, unlike PL/I or Ada, the overall scheme of the Java language did not have an available syntax for turning detection on and off. (The annotation facility provides one, today.)
 Signature John W. Kennedy "Give up vows and dogmas, and fixed things, and you may grow like That. ...you may come to think a blow bad, because it hurts, and not because it humiliates. You may come to think murder wrong, because it is violent, and not because it is unjust." -- G. K. Chesterton. "The Ball and the Cross" * TagZilla 0.066 * http://tagzilla.mozdev.org
Eric Sosman - 09 Apr 2007 13:37 GMT >>> An overflow would indicate a serious programming error, and should be >>> handled the same way as NullPointerException. For almost all programs, [quoted text clipped - 7 lines] > handling more overflow exceptions than we might like otherwise. If you want > real numbers (in the mathematical sense), use the IEEE floating point types. This was (I think) what Patricia Shanahan alluded to when she mentioned Java's lack of unsigned integer arithmetic. The language would be pleasanter, IMHO, if "plain" integer arithmetic threw ArithmeticException on overflow. For occasions requiring a "bag of bits" instead of a number you would use another flavor of integer featuring silent wrap-around. (Whether this flavor should be "unsigned" a la C or "signed but modular" would be a matter for debate, were the debate not already over.)
Efficient trapping of overflows is neither rocket science nor new art. In the late 1960's I wrote extensively for IBM S/360 machines (ancestors of today's zSeries), and their ordinary mode of operation generated traps for integer overflow. Nowadays I imagine that the vogue in machine design would avoid "modes" and would instead offer variants of the instructions: You would have a plain ADD instruction that trapped on overflow and an ADDNT instruction that ignored it but was otherwise identical. (C.f. the use of different flavors of floating-point instructions to implement different rounding "modes.")
Anyway: Water under the bridge, horse non-proximal to the barn, "It might have been," the moving finger moves on.
 Signature Eric Sosman esosman@acm-dot-org.invalid
Lew - 09 Apr 2007 13:51 GMT > Anyway: Water under the bridge, horse non-proximal to the > barn, "It might have been," the moving finger moves on. A preferred programming environment is a jug of wine and a loaf of bread.
 Signature Lew
Eric Sosman - 09 Apr 2007 15:43 GMT Lew wrote On 04/09/07 08:51,:
>> Anyway: Water under the bridge, horse non-proximal to the >>barn, "It might have been," the moving finger moves on. > > A preferred programming environment is a jug of wine and a loaf of bread. ... with "singing in the wilderness" a euphemism for debugging.
 Signature Eric.Sosman@sun.com
Patricia Shanahan - 09 Apr 2007 14:29 GMT >>>> An overflow would indicate a serious programming error, and should be >>>> handled the same way as NullPointerException. For almost all programs, [quoted text clipped - 31 lines] > Anyway: Water under the bridge, horse non-proximal to the > barn, "It might have been," the moving finger moves on. Potentially, there is the possibility of building a new barn, with lock on door from the start, right where the horse is now.
How about adding a new type, freely convertible to int and usable in every context that requires int, that represents a checked overflow signed int? The current int would remain as a "signed but modular" integer type.
Patricia
Chris Uppal - 09 Apr 2007 15:13 GMT > > Anyway: Water under the bridge, horse non-proximal to the > > barn, "It might have been," the moving finger moves on. > > Potentially, there is the possibility of building a new barn, with lock > on door from the start, right where the horse is now. Known as dogging a fled horse ;-)
-- chris
P.S. Sadly, not original -- but impossible to resist the temptation...
Chris Uppal - 09 Apr 2007 03:57 GMT > What would be an example (an application), where you need to > use an integral numeric type with integer arithmetics and need > to detect overflow, Any application where the designer or coder has not considered the possibility of arithmetic overflow.
Add in all the cases where the designer or coder /has/ considered the possibility of arithmetic overflow and wishes to detect it, and I don't think there are all that many valid arithmetic examples which don't fall into one camp or the other.
> and which action would be appropriate in > this example for the case of non-overflow and overflow, > respectively? Not sure I'm addressing your question, but the correct (default) action in the case of unexpected arithmetic overflow would be to abort the application (since integer primitives don't have any equivalent of floating point's NaNs and infinities).
Better, of course, not to allow overflow in the first place.
-- chris
Stefan Ram - 09 Apr 2007 14:52 GMT >Not sure I'm addressing your question, but the correct >(default) action in the case of unexpected arithmetic overflow >would be to abort the application (since integer primitives >don't have any equivalent of floating point's NaNs and >infinities). Patricia Shanahan <pats@acm.org> writes:
>An overflow would indicate a serious programming error, and >should be handled the same way as NullPointerException. For >almost all programs, it should cause an abort with stack trace. I see. (Actually, I was looking for a specific example.)
However, in the Web, I also find Java code like » private long randomSeed = 0; «» int random(int range) { randomSeed = randomSeed * 1103515245 + 12345; return (int) ((randomSeed / 65535) % range); } « http://aanthill.free.fr/noframe/fr/World.java_fr.html
One might wonder whether integer overflow indicates a serious programming error here.
Assuming that it always indicates a serious programming error, one can imagine a debugger instrumenting java code or class files so as to detect overflow at least during developement, testing, and debugging.
Chris Uppal - 09 Apr 2007 15:08 GMT > I see. (Actually, I was looking for a specific example.) > [quoted text clipped - 11 lines] > One might wonder whether integer overflow indicates a > serious programming error here. This is one of the (relatively few) examples of code for which overflow checking is irrelevant at best. Such examples are not uncommon in crypto- or crypto-related code such as hashing, but are (I think) very uncommon for arithmetic (as opposed to bitwiddling) use of integers otherwise.
I believe that code would be improved if the commentary made it clear that it depended on the fact that the calculations were taken mod 2**64, and indeed that that /specific/ modulus was part of the algorithm specification.
I suppose the canonical example of unwelcome wraparound is
void withdraw(int amount) { currentBalance -= amount; }
-- chris
Stefan Ram - 09 Apr 2007 15:28 GMT >I believe that code would be improved if the commentary made it >clear that it depended on the fact that the calculations were >taken mod 2**64, and indeed that that /specific/ modulus was >part of the algorithm specification. This was not a random number generator implementation of highest quality anyways.
>I suppose the canonical example of unwelcome wraparound is >void >withdraw(int amount) >{ > currentBalance -= amount; >} I am not sure whether the user would appreciate an abnormal process ending in this case. It might be more helpful to provide specific and specified behavior.
public boolean withdraw( final int amount ) { final boolean done; if( amount <= 0 || currentBalance - amount >= currentBalance ) done = false; else{ currentBalance -= amount; done = true; } return done; }
OK, if the programmer should have written such code, but instead forgot the tests, then an error message during the testing phase will be helpful.
Lew - 10 Apr 2007 14:41 GMT > I suppose the canonical example of unwelcome wraparound is > [quoted text clipped - 3 lines] > currentBalance -= amount; > } If I owe the bank a thousand dollars, I have a problem. If I owe the bank Integer.MAX_VALUE dollars they have a problem.
 Signature Lew
Chris Uppal - 10 Apr 2007 14:55 GMT > If I owe the bank a thousand dollars, I have a problem. If I owe the bank > Integer.MAX_VALUE dollars they have a problem. Even without integer wraparound.
-- chris
Mark Space - 10 Apr 2007 21:58 GMT > However, in the Web, I also find Java code like > » [quoted text clipped - 4 lines] > return (int) ((randomSeed / 65535) % range); > } What I'd like to see is an optional flag to turn on integer range checking:
java -DIntergerException=1 StefansWebCode.class
Then once the developer has decided to use integer range checking, the above could be recoded as:
int random(int range) { try { randomSeed = randomSeed * 1103515245 + 123456; } catch ( ArithmeticException e) {} return (int) ((randomSeed / 65535) % range); }
Obviously the result of the calculation during an overflow would have to be defined as it is now for this to work.
Arne Vajhøj - 09 Apr 2007 03:57 GMT >> why not integer overflow? > [quoted text clipped - 3 lines] > this example for the case of non-overflow and overflow, > respectively? If you Google you will find lots of request for this functionality in C and C++.
I am sure there are plenty of Java programmers who would prefer their program to crash instead of calculating on garbage data (yes - it can in some cases be that they want the current overflow handling, but in most cases it is an error situation).
Arne
Piotr Kobzda - 11 Apr 2007 09:23 GMT > I think it's strange Java doesn't provide for any kind of overflow > error. Anyone know if it's possible to get Java to throw an overflow > for calculations like this? Yes, it's possible in Java.
One way to achieve that is to code it explicitly using your own overflow checking methods, e.g. that way:
int winOdds = multiply(multiply(multiply(multiply(multiply(49, 48), 47), 46), 45), 44);
or using more readable, BigInteger-like fashion:
int winOdds = new OverflowAwareInteger(49) .multiply(48) .multiply(47) .multiply(46) .multiply(45) .multiply(44).intValue();
Another way for overflow checking (limited to non compile-time constant expressions) is the bytecode transformation (using e.g. Java instrumentation support).
Candidate opcodes for such transformation are: -- arithmetic: iadd, iinc, ladd, isub, lsub, imul, lmul, idiv, ldiv, ineg, lneg; -- conversion: i2b, l2b, i2s, l2s, i2c, l2c, l2i, f2i, d2i, f2l, d2l.
The transformer should simply replace all the opcodes listed here with a call to equivalent method supporting overflow checking.
However, if you want overflow support for all Java expressions you should somehow transform the source code before compilation, because Java compiler evaluates all compile-time constant expressions before bytecode generation.
For example the OP's original code:
int winOdds = 49 * 48 * 47 * 46 * 45 * 44;
is evaluated by the compiler to equivalent of:
int winOdds = 1478412928;
In the overflow-aware runtime, it should be more likely compiled into something equivalent to:
int winOdds = OverflowAware.multiply(228826080, 44);
piotr
Tom Hawtin - 08 Apr 2007 19:20 GMT > float winOdds = 49 * 48 * 47 * 46 * 45 * 44;
> 1.47841293E9 > 720.0 [quoted text clipped - 5 lines] > 720 > 13,983,816 What's the value of Integer.MAX_VALUE?
Tom Hawtin
MS - 08 Apr 2007 19:43 GMT > What's the value of Integer.MAX_VALUE? Too low for my needs. Thanks.
Lew - 08 Apr 2007 19:55 GMT Tom Hawtin wrote:
>> What's the value of Integer.MAX_VALUE?
> Too low for my needs. Exactly! That was the problem!
 Signature Lew
Joshua Cranmer - 08 Apr 2007 19:27 GMT > Hi, > [quoted text clipped - 21 lines] > 720 > 13,983,816 No it shouldn't. float refers to single-precision floating point scientific values (base two, of course), so ones-digit accuracy may not possible when working with millions, but the answer would be expressed (if properly calculated) as something with E7.
> Don't believe me? Paste the following into your calc program: > [snip] > Am I going crazy? Why doesn't my Java program work? What Java is doing when it calculates winOdds is it is multiplying the numbers /as integers/ and then converting to a float. The number obviously exceeds 2^31-1, so it is rolling over. There are several ways to avoid this, the easiest being float winOdds = 1.0f * 49 * 48 * 47 * 46 * 45 * 44; or float winOdds = 49.0f * 48 * 47 * 46 * 45 * 44;
The answer is, no, you aren't crazy, but you do need to learn more about when conversions get applied.
MS - 08 Apr 2007 19:44 GMT Joshua Cranmer emailed this:
>> Hi, >> [quoted text clipped - 39 lines] > The answer is, no, you aren't crazy, but you do need to learn more about > when conversions get applied. Many thanks for the explanation.
Cheers.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|