Re: Exceptions vs NaN/NaI
Ok. I thought a little how "ComparablePlusNaN" could look like.
It seems that it is not necessary to invent new interface.
It is possible to extend a liitle the specification of existing "Comparble" and "Comparator" interfaces.
They method "int Comparator.compare(T x1, T x2)" will continue to return -1,+0,+1 when lt(x1,x2), eq(x1,x2), gt(x1,x2).
The extension is that this method may "throw new UnorderedExcpetion();" when x1 and x2 are unordered.
There is a form to "ask the architects of the JVM".
It is Java Enhanced Proposal (JEP) http://openjdk.java.net/jeps/1 .
I attach a draft of a proposal, that enables interoperability between different subclasses
of java.lang.Number . I beleive that this JEP (if accepted) will help to future JVM implementations of
IEEE 754 number formats (like Binary128) and P1788 Intervals.
Does anybody from P1788 wants to discuss this JEP and to work an its editing before submission to Java architects ?
-Dima
----- Исходное сообщение -----
От: j.d.pryce@xxxxxxxxxxxx
Кому: stds-1788@xxxxxxxxxxxxxxxxx
Отправленные: Вторник, 8 Май 2012 г 13:11:43 GMT +04:00 Абу-Даби, Маскат
Тема: Re: Exceptions vs NaN/NaI
Dmitri, Michel, P1788
On 8 May 2012, at 04:32, Michel Hack wrote:
> Dmitri Nadezhin wrote:
>> Unfortunately, such compareTo is inconsistent
>> with comparison operations "==", "<", ">", "<=", ">=" :
>> d == Double.NaN is always false;
>> d < Double.NaN is always false;
>> but
>> compare(Double.NaN, Double.NaN) == 0;
>> compare(0.0, Double.NaN) == -1 .
>> This inconsistence is unavoidable with 754-types.
>
> This is not an inconsistency or flaw with 754 -- it is quite
> deliberate, if "compare()" is indeed defined to be TotalOrder.
> You should also have
> compare(-0.0, +0.0) == -1
> but
> -0.0 == +0.0
>
> The fact that NaN compares Unequal to anything, including itself,
> is a deliberate FEATURE of 754...
Michel knows more than I about these things, but FWIW I agree with everything he says here, in particular about the advantages of NaN in parallel computations.
Making an interval type fully conforming lets it be plugged into an arbitrary interval program, in place of some other interval type, with the knowledge that the program will still run and produce valid results. Dmitri, is that not worth while? It means that your package, instead of belonging to a limited "rational intervals community", with maybe limited life span, would become usable worldwide as long as the 1788 standard lasts.
Would it be possible to ask the architects of the JVM to provide a "ComparablePlusNaN" interface? It would, I guess, not be hard to design, as the NaN aspect would conform to the 754 spec.
John
A draft of JDK Enhancement Proposal (JEP) for interoperability between java.lang.Number subclasses .
JDK Enhancement Proposal (JEP) is a document that specify a possible enhancement of JDK:
http://openjdk.java.net/jeps/1
This is a draft JEP that suggests support for interoperability between subclasses of java.lang.Number .
Developers may write subclasses of Number. Values of each subclass represent real (usually rational) numbers from particular value set.
For example, The need for these subclasess comes from implementations of IEEE 754-2008 formats.
The IEEE 754-2008 standard defines a few basic floating-point numbers
binary32, binary64, binary128, decimal64, decimal128 .
Also it defines two families of extended presision formats:
binary{k} (k >= 128 and k is multiple of 32)
decimal{k} (k >= 32 and k is multiple of 32).
Some other developers write subclasses that represent fractions.
Yet another developers write subclasses that represent mathematical object other than real numbers,
for example complex numbers or real intervals.
Suppose that two developers wrote independently two subclasses Number1 and Number2 of java.lang.Number .
java.lang.Number API suggests very limited support to compare objects of Number1 and Number2 or to convert them
from one subclass to another.
java.lang.Number API defines abstact methods that approximate Number objects by primitive types like "double doubleValue();" method.
We can use "number1.doubleValue() < number2.doubleValue()" for comparison.
However, this expression gives false for those "number1 < number2" that rounds to the same double value.
Similarly, the expression "new Number2(number1.doubleValue())" may loose precision when Number1 and Numebr2 are
more precise than doubles.
The interoperability between Number1 and Number2 can be achieved if JDK contains some Universal Numbers.
Each subclass will have methods to convert to Universal Number and from Universal Number.
The conversion should be exact. If the value of Number subclass doesn't fit into Universal Number,
the conversion method should fail but not round or trancate.
The goal of Universal Number is unachievable in absolute sense.
Whatever precision of Universal number is, the developer can write a yet another subclass of Number
that can't be exactly represented by this Universal number.
But we can try to achive this goal in practical sense. We can give initial list of Universable Number types
which is enough for most practical needs, and we can make this list extendable in the future.
Universal Number should not expose much implementation details. So it is interface, not class.
Below are items taht the JEP suggests.
1) Add interface java.math.Universal
public interface Universal {}
2) Add new method universalValue() to java.lang.Number.
The default implementation returns a dummy Universal object.
The subclasses should override this.
public class Number {
...
public Universal universalValue() {
return new java.math.Universal() {}
}
...
}
3) The interface java.math.Universal contains a few subinterfaces.
Each of them represents some mathematical set . Subinterfaces may extends each other.
I1 extends I2 when value set represented by I1 is a subset of value set represented by I2.
The initial set of subinterfaces could be:
Universal.Integer - arbitrary precision integer numbers with magnitude upto 2^(2^63 - 1) .
Universal.Rational - rational number with optional floating-point-like factor (p/q * r^e).
Universal.PositiveInfinity - positive infinity from extended real set
Universal.NegativeInfinity - negative infinity from extended real set
Universal.ExtendedRational - either rational number or positive/negative infinity (subset of extended real).
Universal.Infinity - marker for infinity values
Universal.NaN - marker for Not-a-Numbers.
The list of subinterface may be extended in future.
Here is the draft of initial Universal interface with its subinterfaces.
public interface Universal {
publuc interface Integer extends Universal.Rational {
public int signum();
public long getMagnitudeBitLength();
public boolean testMagnitudeBit(long n);
public void getMagnitudeBits(long startBit, long nBits, long[] result, int dstOffset);
}
public interface Rational extends Universal.ExtendedRational { // numerator/denominator * radix^exponent
public Universal.Integer getNumerator();
public Universal.Integer getDenominator();
public int getRadix();
public Universal.Integer getExponent();
}
public interface PositiveInfinity extends Universal.Infinity, Universal.ExtendedRational {}
public interface NegativeInfinity extends Universal.Infinity, Universal.ExtendedRational {}
public interface ExtendedRational extends Universal {}
public interface Infinity extends Universal {}
public interface NaN extendes Universal {}
}
4) Each JDK subclass of java.lang.Number overrides method universalValue().
The overriden method returns an object that implements proper subinterfaces of java.math.Universal .
For example, Double.universalValue() will return:
a) An object that implements Universal.NaN when d.value is NaN;
b) An object that implements Universal.Infinity when d.value is infinity
c) An object that implements both Universal.Integer and Universal.Rational when d.value is an integer number
d) An object that implements Universal.Rational when d.value is finite fractional floating-point number,
For example, class BigInteger can implement Universal.Integer if we add proper methods ti it. In this case
BigInteger.universalValue will return itself.
5) Add new constructors and/or factory methods to JDK subclasses of java.lang.Number
with the argument of type java.math.Universal . They will recognize some subinterfaces of
java.math.Universal and construct new object with value specified by the argument.
If the argument is of unknown subinterface of java.math.Universal, the constructor fails.
6) Add exception java.math.UnorderedException
public class UnorderedException extends ArithmeticException {}
7) Write in javadocs of Comparator#compare that the method may throw UnorderedException/
8) Add static field to java.lang.Number :
public static final Comparator<Number> RATIONAL_ORDER = ... ;
The method "int RATIONAL_ORDER.compare(Number x, Number y);"
compares x and y of any subclass of Number if they both represent extended rational numbers.
Extended rational number is either rational number or negative infinity or positive infinity.
The order is total order of extended rational numbers known from mathematics.
This methods throws UnorderedException if x or y is not extended rational number
(examples: Float.NaN, Double.NaN, sqrt(2) from a computer algebra library, I from Complex library, [1,2] from Interval library).
When "x" or "y" is of Number subclasses from OpenJDK (Byte,Short,Integer,Long,Float,Double,BigInteger,BigDecimal)
the methods may use fastpath algorithm
9) Predicted extensions of subinterface list: finite complex numbers.
public iterface Universal {
. . .
public class Complex extends Universal { // finit complex number with rational real and imaginary parts
public Universal.Rational getReal();
public Universal.Rational getImag();
}
public class Rational extends Universal.ExtendedRational, Universal.Complex {
. . .
}
}
Suppose that an implementator writes a subclass "MyComplex" of Number.
Its universalValue() will return an object that implements Universal.Rational when imaginary part is zero
and an obkect taht implements Universal.Complex otherwise
10) Predicted extensions of subinterface list: real interval with extended rational bounds.
public iterface Universal {
. . .
public class NonemptyInterval extends Universal.Interval { // finit complex number with rational real and imaginary parts
public Universal.ExtendedRational getInf();
public Universal.ExtendedRational getSup();
}
public class EmptyInterval extends Universal.Interval {}
public class Interval extends Universal {}
public class Rational extends Universal.ExtendedRational, Universal.Interval {
. . .
}
}
Suppose that an implementator writes a subclass "MyInterval" of Number.
Its universalValue() will return an object that implements Universal.Rational when interval
is singleton (consists of one rational number)
and an object that implements Universal.EmptyInterval when interval is empty
and an object that implements Universal.NoneptyInterval otherwise .