Arithmetic overflow checking

S

supercalifragilisticexpialadiamaticonormalizeringe

or if you think ++ is common enough:
agreeCount.increment();
and generally
agreeCount.add(someOtherAgreeCount)
and if you decide to have your operators return "this"
ac0.mul(ac1).plus(ac2)) // ac0 = ac0*ac1+ac2
or
ac = (new AgreeCount(ac0)).mul(ac1).plus(ac2) // ac = ac0*ac1+ac2

Eww. Mutable number classes.

I think I'm going to throw up.
 
L

lewbloch

lewbloch said:
[about lack of operator overloading for non-primitive arithmetic types]
The problem is not just the keystrokes for typing the expressions.
It is very important to be able to check that a lengthy expression
in a program is a correct translation of the corresponding expression,
in mathematical notation, in a textbook or paper.
Lew?
Yes?

So here are arguments (admittedly not mine) that include ("... not just....")
but also go beyond the complaint about the number of keystrokes. I was just
wondering, if you had any expert-opinion about them, that you'd care to share.

Patricia made excellent points.

I don't think I can improve on them.
 
L

lewbloch

or if you think ++ is common enough:
   agreeCount.increment();
and generally
   agreeCount.add(someOtherAgreeCount)
and if you decide to have your operators return "this"
   ac0.mul(ac1).plus(ac2)) // ac0 = ac0*ac1+ac2
or
   ac = (new AgreeCount(ac0)).mul(ac1).plus(ac2) // ac = ac0*ac1+ac2

While not as compact as operator overloading, this technique provides
a way to ameliorate the matching problem to which Patricia alluded, at
least partially, within the current capabilities of Java.

We also must consider Patricia's other sage advice to consider other
languages for problem domains for which Java is not ideal.
 
D

David Lamb

Eww. Mutable number classes.

I think I'm going to throw up.

It's what happens to ordinary ints in most machine languages. Feel free
to define the less-efficient functional versions that always generate
new objects. The main point was that the method calls aren't necessarily
all that hard to read.
 
L

lewbloch

David said:
It's what happens to ordinary ints in most machine languages. Feel free
to define the less-efficient functional versions that always generate
new objects. The main point was that the method calls aren't necessarily
all that hard to read.

The "Eww" poster seems fond of making tabloid statements devoid of
engineering reasoning.

There's nothing intrinsically wrong with mutable number classes,
particular for the use case under discussion for them, as long as they
aren't used where immutable number classes would be better.

Though the "Eww" poster is free to provide logic and evidence to
support a contrary position, if they so desire and have the
capability.
 
A

Andreas Leitgeb

Patricia Shanahan said:
lewbloch said:
On Jul 22, 10:33 am, Andreas Leitgeb<[email protected]>
wrote:
[about lack of operator overloading for non-primitive arithmetic types]
The problem is not just the keystrokes for typing the expressions.
It is very important to be able to check that a lengthy expression
in a program is a correct translation of the corresponding expression,
in mathematical notation, in a textbook or paper.
Lew?
Yes?
So here are arguments (admittedly not mine) that include ("... not just...")
but also go beyond the complaint about the number of keystrokes. I was just
wondering, if you had any expert-opinion about them, that you'd care to share.
Some of the context has been dropped in editing. My remarks were
specific to the complex, in every sense of the word, expressions I've
seen in scientific and engineering programs.

You meant only complex expressions on complex numbers? (Is that every sense
of "complex", or did I even miss some more?)
If so, then sorry, I obviously understood your remarks as more general than they
were. It's not my intention to misquote contexts and all that. I apologize
if it happened.
 
A

Andreas Leitgeb

David Lamb said:
I have done all of those things, and for me, having to deal with method
calls instead of infix (while annoying) is nowhere near as painful as
the library comparison.

Comparing particular subjective painfulnesses doesn't contribute
much to the discussion.

It is my opinion, that operator overloading at least for a certain
limited set of JSL classes (including BigDecimal and BigInteger as
well as some new Complex class in addition to String's +), would
be beneficial. Ditto for a new "strictint" keyword to enable
detection and handling of integer overflows.

There obviously won't be much agreement on how much effort these
might be worth, and some may even claim that adding those would
make Java worse. No consensus is likely to be reached here.
And even if it were reached, chances would be neglectible that Java
would grow a feature just because it reached consensus in c.l.j.p
Plus IMHO getting operator overloading *right* in a language isn't
exactly trivial. It's not horrible, but not trivial either.

That's the kind of argument that made this posting worth answering.

It becomes non-trivial when it comes to mixing types in expressions.
There'd be some rules and maybe some "cannot"s but that wouldn't be
a blocking point.
 
A

Andreas Leitgeb

lewbloch said:
While not as compact as operator overloading, this technique provides
a way to ameliorate the matching problem to which Patricia alluded, at
least partially, within the current capabilities of Java.

a.plus(b).mul(c) (let's assume them all to be non-mutating methods)
might bear some surprises, but geniuses like Lew won't fall for it,
and others aren't supposed to do professional programming in Java,
anyway ;-)
We also must consider Patricia's other sage advice to consider other
languages for problem domains for which Java is not ideal.

I followed that advice long before it was made. I used Tcl (8.5) for
my large-integer tasks.
 
A

Andreas Leitgeb

Andreas Leitgeb said:
a.plus(b).mul(c) (let's assume them all to be non-mutating methods)

PS: yes, it's trivial to correct it to a.plus(b.mul(c)) but the point is,
that with all the parens for the method arguments, such errors happen
more likely than with the standard infix math operators and their
standard (mathematics-inspired) precedence rules.
 
S

supercalifragilisticexpialadiamaticonormalizeringe

The "Eww" poster seems fond of making tabloid statements devoid of
engineering reasoning.

Wrong.

Ordinary ints aren't (in Java, at least, with no "int *" type) subject
to aliasing and other problems that a mutable Integer-analogue would be.
There's nothing intrinsically wrong with mutable number classes,
particular for the use case under discussion for them, as long as they
aren't used where immutable number classes would be better.

See above.
Though the "Eww" poster is free to provide logic and evidence to
support a contrary position, if they so desire and have the
capability.

See above.
 
H

Henderson

It is my opinion, that operator overloading at least for a certain
limited set of JSL classes (including BigDecimal and BigInteger as
well as some new Complex class in addition to String's +), would
be beneficial. Ditto for a new "strictint" keyword to enable
detection and handling of integer overflows.

An obvious suggestion would be to allow it on all java.lang.Number
subclasses, but a + b among these is only defined if a is a Number class
that has an overload of .plus(x) that is applicable to an argument of a
supertype of b, and the most specific such is chosen; and if a is a
primitive, is treated as b + a; a * b analogously; a - b with a
primitive uses (b - a).negate() and expects the return type of minus to
support negate(); and for division we likewise need .reciprocal().

We could go further and rewrite Number.java so that it is Number<T
extends Number<T>> and defines:

public T plus (? super T)
public T plus (int)
public T plus (long)
public T plus (float)
public T plus (double)
public T minus (? super T)
public T minus (int)
....
public T times (? super T)
....
public T dividedBy (? super T)
....
public T negate ()
public T reciprocal ()

or something of the sort. I think short overloads can be left out as
they can just auto-promote to int and use the int version and the int
version won't be less efficient, unlike (on 32 bit hardware) the long
version.

The operator expressions then become shorthands for the method calls
above, and generate compile time type errors if one is needed and
missing, e.g. MyBigInteger.plus(BigInteger) is not defined but
MyBigInteger.plus(MyBigInteger) is and one mixes the two types in a +
expression. (Integer etc. needn't be explicitly supported as
autounboxing can be used to call the primitive plus (int) or whatever if
necessary.)
 
M

markspace

I think it might be better to create a marker interface
java.math.Arithmetic. I do like the idea of a fixed mapping from
operators to method names that are normal identifiers.


I'd be concerned that a marker interface could be abused.

public abstract class BaseNumber extends Number {
public abstract BaseNumber add( Number n );
public abstract BaseNumber subtract( Number n );
public abstract BaseNumber mul( Number n );
public abstract BaseNumber[] div( Number n );
public abstract BaseNumber modulo( Number n );
}

Then restrict operator overloading to a class like BaseNumber and its
subclasses. Some classes in the existing Java API like BigDecimal may
need to also extend BaseNumber.
 
M

markspace

meanwhile complex would be forced to provide a meaningless conversion to
byte.


It could just throw an error. Collections uses this technique to make
unmodifiable Collection's. An unmodifiable List for example throws
UnsupportedOperation if add() is invoked. 'Taint the prettiest but it
works.
 
M

markspace

I still don't see the advantage over a marker interface.


The advantage of a class instead of an interface is that extends is
required. Since Java doesn't support multiple inheritance,
opportunities for abuse are reduced. I also think there is a mental
barrier to is-a abstract class versus just a marker interface. The
former has design implications that many would not wish to break just to
get a little operator overloading.
 
D

David Thompson

[...]
Correct results can be computed without any slowdown,
when the CPU is able to trigger an overflow interupt.

A slowdown would only happen when an overflow occurs.
Computations without overflow would run at full speed.

Well, no. At least, not in any trap-capable architecture I've
seen. Three points:

[snipped nice explanation]

How about an example of such an architecture? A URL would be
fine. I believe that /370 had something like that for floating point,
but not for integer.
S/360 and all successors have masked interrupts for overflows in
'fixed-point' (integer) and decimal (BCD), and unmasked for (original)
floating-point now retronymed 'hex' floating-point. Since IIRC S/390
there is also 'binary' (IEEE) floating-point with its own separate and
more complicated status flags, masks and interrupt causes.

I can't find a usable ref on the IBM site, but if you trust bitsavers:
http://bitsavers.org/pdf/ibm/360/princOps/A22-6821-0_360PrincOps.pdf
page 16 figs 14 and 16, and pp 25 and 33, 35 and 39, 42 and 49.

A few high(er)-performance models of 360, and IIRC 370, did make FP
traps 'imprecise' = not synchronous with the 'right' instruction.
 
H

Henderson

I don't think it would be wise to tie operator overloading to Number.
Number defines a series of conversions that make some sense for those
types that represent subsets of the real line.

I wasn't thinking beyond the real line to the more abstract stuff
mathematicians futz around with and consider to have addition and
multiplication.

But short of giving general operator overloading to the masses (which
the gurus in charge of Java clearly do not want to do), there *is* a
way: introduce an abstract superclass, say, AbstractNumber or
ArithmeticComposable or something for "things that aren't necessarily
normal numbers, but have the basic arithmetic operations".
I think it might be better to create a marker interface
java.math.Arithmetic.

That sneaks in arbitrary operator overloading through the back door, as
people slap "implements java.math.Arithmetic" on
"JFoobarSQLQueryEnumerator" and implement ".plus" for it. ;)

Even as things go, I'd like there to be some compiler magic making the
ArithmeticComposables (or whatever) have automatically final fields,
anything with that as an ancestor, as well. It should be that a += b
changes what math object the reference a points to, but doesn't change a
for anybody else, so all the arithmetic operations should return new
objects (as currently seems to be the case for BigInteger and
BigDecimal), not mutate the original.
I do like the idea of a fixed mapping from
operators to method names that are normal identifiers.

It's also the only way to do it without adding new keywords and syntax
in a probably source-compatibility-breaking way. And do we really want
C++'s "operator+" notation?
I don't think
all arithmetic types should be required to support all operations. For
example, consider negate and an unsigned type, or reciprocal and an
integer type.

There's two approaches to dealing with that.

1. AbstractNumber implements everything, but they all throw
UnsupportedOperationException. You override what you can support.

2. AbstractNumber doesn't even specify some of these, but +, -, etc.
may expand into them anyway, and the compiler will then complain
if the corresponding named method is not found.

One problem with this, though, is that implementing a - b when a is
primitive and b isn't, and likewise a / b, seems to require having
negate and reciprocal, respectively, supported by whatever the return
type of b - a and b / a would be.

There's also a possible precision problem with a/b being computed as
1/(b/a) in these cases.

As an alternative, perhaps boxing transformations can be expected
instead: valueOf(int), etc. methods will be used so if b is of an
ArithmeticComposable type Foo with a valueOf(int) method and a is an
int, or can be widened to int (short, byte), then a + b becomes
Foo.valueOf(a).plus(b).

Of course, valueOf may need to cope with values out of range. What if
Foo is your hypothetical unsigned type and a is -42? RuntimeExceptions
seem indicated in these cases. We already have an ArithmeticException
class, currently used for BigInteger/BigDecimal ops that result in
division by zero or non-representable values (in the case of a BD with
unlimited precision -- another spot where we could sorely use a Rational
class). I'd suggest including an ArithmeticRangeException subclass of
that for use in such valueOf methods.

And once boxing conversions are being included, why not go ahead and
allow any ArithmeticComposable with intValue or similarly-named methods
be autounboxed when used in contexts that expect a primitive? (Though a
+ b and other arithmetic situations will never unbox b instead of boxing
a, presuming that the specialized type of b is desired. Manual unboxing
can be done if the opposite is desired, e.g. a + b.intValue().)
 
A

Arved Sandstrom

Historically, complex numbers were indeed invented by and for
mathematicians for the abstract satisfaction of having solutions for all
quadratic equations. However, as happens surprisingly often when
mathematicians think they have invented something abstract for their own
amusement, scientists and engineers turned them into useful tools for
practical uses.

For example, a complex number can represent both magnitude and phase of
an alternating current. That simplifies some electrical engineering
calculations.

I've seen far too many uses of complex numbers in scientific and
engineering programs to be really comfortable with the fact that Java
lacks a practical way to express anything other than the simplest
complex number expressions.

Patricia

I agree. Unless it were a trivial and very limited use of complex
numbers I'd likely skip Java as a candidate for doing that work. But if
the application had a moderate need for complex numbers, but also a
compelling argument for using Java for most of the logic, I would
consider Scala for the complex numbers bit. Or Jython for that matter.

But for an application that was all about science and engineering
computations my first few choices of programming languages would not
include Java anyway. Nor C#, even though that has much better support
for complex. Just as when I was doing primarily scientific programming
(12 or more years ago) I believe that faced with the same questions
today I'd still look first at what language has got the best built-ins
and libraries for the specific job, including not just data manipulation
but also data visualization.

Another interesting consideration is languages that have type systems
that support the notion of dimension. I've played a bit with that in F#
and Fortress, and I believe that language support for units of measure
is also very important in ensuring program correctness.

AHS
 
A

Andreas Leitgeb

Henderson said:
That sneaks in arbitrary operator overloading through the back door, as
people slap "implements java.math.Arithmetic" on
"JFoobarSQLQueryEnumerator" and implement ".plus" for it. ;)

It's quite likely that the reviewer who inevitably will shoot the
programmer for this, will have the jury's sympathy and not be
punished... ;)

A more fundamental problem with operator overloading for "Arithmetic"
types is, when Arithmetic types can or cannot be mixed for a particular
operation.

Simple example: what would be the sum of
BigInteger("123456789012345678901234567890123456789012") and some
Complex( 0.0 , Math.PI )? Ok, preferences likely go towards
Complex as the result for this particular example, but there must
be some formalism as to how this addition would be actually
calculated: either there would have to be an over*load* of
..plus(...) for each and every other type, or there must be some
bottleneck like "double" through which unknown Arithmetic-
implementations for the right operand are going to be queezed to
perform the actual calculation.

Such cross-type-behaviour can be deliberately defined for a fixed
handful of new types, but not generally among any two implementors
(or subclasses) of some interface (or baseclass). (I anticipate
that someone will now throw up .equals(), but that's of course
a much simpler matter ("just return false") with respect to
unrelated argument types.)

PS:
I have a faible for philosophical discussions of what new features
would or would not improve Java, and what dangers linger behind them.
I do not think, that any of this discussion or outcomes will have an
influence on what may or may not go into a new version of Java.
 
L

Lew Pitcher

On 7/11/2011 5:54 PM, tm wrote:
[...]
Correct results can be computed without any slowdown,
when the CPU is able to trigger an overflow interupt.

A slowdown would only happen when an overflow occurs.
Computations without overflow would run at full speed.

Well, no. At least, not in any trap-capable architecture I've
seen. Three points:

[snipped nice explanation]

How about an example of such an architecture? A URL would be
fine. I believe that /370 had something like that for floating point,
but not for integer.
S/360 and all successors have masked interrupts for overflows in
'fixed-point' (integer) and decimal (BCD), and unmasked for (original)
floating-point now retronymed 'hex' floating-point. Since IIRC S/390
there is also 'binary' (IEEE) floating-point with its own separate and
more complicated status flags, masks and interrupt causes.

I can't find a usable ref on the IBM site,

You probably want IBM's documentation site. Here's a link to

z/Architecture Principles of Operations
http://publibfp.dhe.ibm.com/cgi-bin/bookmgr/download/DZ9ZR006.pdf?DT=20080213005418&XKS=dz9zbk08

You want page 6-14 and after for "Program Interruption"; the various Data
Exceptions are documented there, including fixed, floating point, and IEEE
floating point data exceptions.

HTH
 
H

Henderson

It's quite likely that the reviewer who inevitably will shoot the
programmer for this, will have the jury's sympathy and not be
punished... ;)

A more fundamental problem with operator overloading for "Arithmetic"
types is, when Arithmetic types can or cannot be mixed for a particular
operation.

Simple example: what would be the sum of
BigInteger("123456789012345678901234567890123456789012") and some
Complex( 0.0 , Math.PI )?

Ideally, it would be a Complex with bignum components, preserving precision.

This seems to require Complex<BaseType> rather than just Complex.

Of course you also raise a valid point regarding overloading for
conversions. Probably you'd have to create a whole framework, with a
NVector<T> for "things with dimension > 1 over the real numbers" and
NVector<BigDecimal> of appropriate dimensionality as the conversion
intermediary (so as not to lose either precision or dimensions in going
to the intermediary) -- just BigDecimal when one-dimensional. Then
conversion to and from BigDecimal and NVector<BigDecimal> is all that is
required.

Until some enterprising mathematician thinks up something that can be
added and multiplied, but has no sensible correspondence to any subset
of any kind of vectors of real numbers ...

I think you can cram matrices in there, and complex numbers. Numbers mod
something, too -- though do you quietly truncate when converting to
these, or throw an exception? Of course, primitive int is already
actually an integers-mod-2^32 type so that may be considered already
settled.

A quick search of wikipedia for "numbers" and looking at terms in the
results that seem to describe funny kinds of numbers turns up "p-adic
numbers" and "hyperreal numbers" that I'm guessing would still run into
problems here. No operator overloading for those, then. :)
 

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,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top