Am I Crazy? V. simple math question.

S

Stefan Ram

Chris Uppal said:
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 said:
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.
 
C

Chris Uppal

Stefan said:
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.

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
 
C

Chris Uppal

Patricia said:
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...
 
S

Stefan Ram

Chris Uppal said:
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.
 
E

Eric Sosman

Lew wrote On 04/09/07 08:51,:
A preferred programming environment is a jug of wine and a loaf of bread.

.... with "singing in the wilderness" a euphemism for debugging.
 
M

MS

Can you cast in Java --as you can in C-- like this, which would allow
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.

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..
 
J

John W. Kennedy

Patricia said:
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".
 
P

Patricia Shanahan

John said:
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".

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
 
J

Joshua Cranmer

Stefan said:
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.

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.
 
J

John W. Kennedy

Patricia said:
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.

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.

--
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
 
K

Karl Uppiano

Patricia Shanahan said:
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.

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.

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.
 
O

Olle

Eric Sosman emailed this:


MS said:
Eric Sosman emailed this:
MS wrote:
[...]
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;
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'.

Yes, I already understood this, that's why I gave the example.
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.

Horray !!


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.

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.

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
 
M

Martin Gregorie

John said:
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.
 
L

Lew

Karl said:
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.
 
L

Lew

Chris said:
I suppose the canonical example of unwelcome wraparound is

void
withdraw(int amount)
{
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.
 
C

Chris Uppal

Lew said:
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
 
M

Mark Space

Stefan said:
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);
}

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.
 
J

John W. Kennedy

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.
 
J

John W. Kennedy

Karl said:
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.)

--
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
 
P

Piotr Kobzda

Mark said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top