// @(#)$Id: JMLFloat.java,v 1.36 2007/02/08 14:05:50 leavens Exp $
// Copyright (C) 2005 Iowa State University
//
// This file is part of the runtime library of the Java Modeling Language.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation; either version 2.1,
// of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with JML; see the file LesserGPL.txt. If not, write to the Free
// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
// 02110-1301 USA.
package org.jmlspecs.models;
/** A reflection of {@link java.lang.Float} that implements {@link JMLType}.
*
* @version $Revision: 1.36 $
* @author Brandon Shilling
* @author Gary T. Leavens
* @author David Cok
* @see java.lang.Float
* @see JMLDouble
*/
//-@ immutable
public /*@ pure @*/ strictfp class JMLFloat implements JMLComparable {
/** The float that is the abstract value of this object.
*/
//@ model public float theFloat;
/*@ spec_public @*/ private float floatValue;
//@ in theFloat;
//@ private represents theFloat <- floatValue;
//@ public invariant owner == null;
/** Initialize this object to contain zero.
*/
/*@ public normal_behavior
@ assignable theFloat,owner;
@ ensures theFloat == 0.0f;
@*/
public JMLFloat ( ) {
floatValue = 0.0f;
//@ set owner = null;
}
/** Initialize this object to contain the given float.
*/
/*@ public normal_behavior
@ requires !Float.isNaN(inFloat);
@ assignable theFloat,owner;
@ ensures theFloat == inFloat;
@ also
@ public normal_behavior
@ requires Float.isNaN(inFloat);
@ assignable theFloat,owner;
@ ensures Float.isNaN(theFloat);
@*/
public JMLFloat (float inFloat) {
floatValue = inFloat;
//@ set owner = null;
}
/** Initialize this object to contain an approximation to the
* given integer.
*/
/*@ public normal_behavior
@ assignable theFloat,owner;
@ ensures theFloat == (float)inInt;
@*/
public JMLFloat (int inInt) {
floatValue = (float)inInt;
//@ set owner = null;
}
/** Initialize this object to contain the value of the given
* Float.
*/
/*@ public normal_behavior
@ requires inFloat != null && !inFloat.isNaN();
@ assignable theFloat,owner;
@ ensures theFloat == inFloat.floatValue();
@ also
@ public normal_behavior
@ requires inFloat != null && inFloat.isNaN();
@ assignable theFloat,owner;
@ ensures Float.isNaN(theFloat);
@*/
public JMLFloat(/*@ non_null */ Float inFloat) {
floatValue = inFloat.floatValue();
//@ set owner = null;
}
/** Initialize this object to contain the value given by the
* string argument.
*/
/*@ public behavior
@ requires s != null;
@ assignable theFloat,owner;
@ ensures (* s is a parseable string that has the format
@ of a floating point literal *)
@ && theFloat == Float.valueOf(s).floatValue();
@ signals_only NumberFormatException;
@ signals (NumberFormatException)
@ !(* s is a parseable string that has the format
@ of a floating point literal *);
@*/
public JMLFloat (/*@ non_null @*/ String s) throws NumberFormatException {
floatValue = Float.valueOf(s).floatValue();
//@ set owner = null;
}
/** Tell if this object contains either positive or negative infinity.
*/
/*@ public normal_behavior
@ ensures \result <==> (theFloat == Float.POSITIVE_INFINITY)
@ || (theFloat == Float.NEGATIVE_INFINITY);
@*/
public boolean isInfinite() {
return (floatValue == Float.POSITIVE_INFINITY)
|| (floatValue == Float.NEGATIVE_INFINITY);
}
/** Tell if this object contains NaN (not a number).
*/
/*@ public normal_behavior
@ ensures \result <==> (theFloat != theFloat);
@*/
public boolean isNaN() {
return (floatValue != floatValue);
}
/** Return a clone of this object.
*/
/*@ also
@ public normal_behavior
@ requires !Float.isNaN(theFloat);
@ ensures \result != null && \result instanceof JMLFloat
@ && ((JMLFloat)\result).theFloat == theFloat;
@ also
@ public normal_behavior
@ requires Float.isNaN(theFloat);
@ ensures \result != null && \result instanceof JMLFloat
@ && ((JMLFloat)\result).isNaN();
@*/
public Object clone() {
return this;
}
/** Compare this to op2, returning a comparison code.
* @param op2 the object this is compared to.
* @exception ClassCastException when o is not a JMLFloat.
*/
public int compareTo(/*@ non_null @*/ Object op2) throws ClassCastException {
return Float.valueOf(floatValue)
.compareTo(Float.valueOf(((JMLFloat)op2) //@ nowarn Cast;
.floatValue));
}
/** Tell if the argument is zero (either positive or negative).
*/
/*@ public normal_behavior
@ ensures \result <==> (f == +0.0f || f == -0.0f);
@*/
public static /*@ pure @*/ boolean isZero(float f) {
return f == +0.0f || f == -0.0f;
}
/** Tell if this object contains zero (either positive or negative).
*/
/*@ public normal_behavior
@ ensures \result <==> (theFloat == +0.0f || theFloat == -0.0f);
@*/
public boolean isZero() {
return floatValue == +0.0f || floatValue == -0.0f;
}
/** Tell whether this object is equal to the argument.
*/
/*@ also
@ public normal_behavior
@ requires (op2 instanceof JMLFloat) && op2 != null;
@ {|
@ requires !Float.isNaN(theFloat) && !isZero();
@ ensures \result <==> theFloat == ((JMLFloat)op2).theFloat;
@ also
@ requires Float.isNaN(theFloat);
@ ensures \result <==> Float.isNaN(((JMLFloat)op2).theFloat);
@ also
@ requires isZero();
@ ensures \result <==> ((JMLFloat)op2).isZero();
@ |}
@ also
@ public normal_behavior
@ requires !(op2 instanceof JMLFloat) || op2 == null;
@ ensures \result <==> false;
@*/
public boolean equals(/*@ nullable @*/ Object op2) {
if (op2 == null || !(op2 instanceof JMLFloat)) {
return false;
}
JMLFloat jmlf2 = (JMLFloat)op2;
float fv2 = jmlf2.floatValue;
if (Float.isNaN(floatValue) && Float.isNaN(fv2)) {
return true;
} else if (isZero() && jmlf2.isZero()) {
return true;
} else {
return floatValue == fv2;
}
}
/** Return a hash code for this object.
*/
public int hashCode() {
return Float.valueOf(floatValue).hashCode();
}
/** Return the float contained in this object.
*/
/*@ public normal_behavior
@ requires !isNaN();
@ ensures \result == floatValue;
@ also
@ requires isNaN();
@ ensures Float.isNaN(\result);
@*/
public float floatValue() {
return floatValue;
}
/** Return a Float containing the float contained in this object.
*/
/*@ public normal_behavior
@ ensures \result != null;
@ ensures !isNaN() ==> theFloat == \result.floatValue();
@ ensures isNaN() ==> \result.isNaN();
@*/
public /*@ non_null @*/ Float getFloat() {
return Float.valueOf(floatValue);
}
/** Return the negation of this.
*/
/*@ public normal_behavior
@ ensures \result != null;
@ ensures \result.equals(new JMLFloat(\nowarn(- theFloat)));
@*/
public /*@ non_null @*/ JMLFloat negated() {
return new JMLFloat(- floatValue);
}
/** Return the sum of this and the given argument.
*/
/*@ public normal_behavior
@ requires f2 != null;
@ ensures \result != null;
@ ensures \result.equals(new JMLFloat(\nowarn(theFloat + f2.theFloat)));
@*/
public /*@ non_null @*/ JMLFloat plus(/*@ non_null */ JMLFloat f2) {
return new JMLFloat(floatValue + f2.floatValue());
}
/** Return the difference between this and the given argument.
*/
/*@ public normal_behavior
@ requires f2 != null;
@ ensures \result != null;
@ ensures \result.equals(new JMLFloat(\nowarn(theFloat - f2.theFloat)));
@*/
public /*@ non_null @*/ JMLFloat minus(/*@ non_null */ JMLFloat f2) {
return new JMLFloat(floatValue - f2.floatValue());
}
/** Return the product of this and the given argument.
*/
/*@ public normal_behavior
@ requires f2 != null;
@ ensures \result != null
@ && \result.equals(new JMLFloat(\nowarn(theFloat * f2.theFloat)));
@ implies_that
@ public normal_behavior
@ requires f2 != null;
@ requires f2.isNaN()
@ || (this.isZero() && f2.isInfinite())
@ || (f2.isZero() && this.isInfinite());
@ ensures \result != null && \result.isNaN();
@*/
public /*@ non_null @*/ JMLFloat times(/*@ non_null */ JMLFloat f2) {
return new JMLFloat(floatValue * f2.floatValue());
}
/** Return the quotient of this divided by the given argument.
*/
/*@ public normal_behavior
@ requires f2 != null;
@ ensures \result != null
@ && \result.equals(new JMLFloat(\nowarn(theFloat / f2.theFloat)));
@ implies_that
@ public normal_behavior
@ requires f2 != null;
@ requires f2.isZero() || f2.isNaN();
@ ensures \result != null && \result.isNaN();
@*/
public /*@ non_null @*/
JMLFloat dividedBy(/*@ non_null */ JMLFloat f2) {
return new JMLFloat(floatValue / f2.floatValue());
}
/** Return the remainder of this divided by the given argument.
*/
/*@ public normal_behavior
@ requires f2 != null;
@ ensures \result != null
@ && \result.equals(new JMLFloat(theFloat % f2.theFloat));
@ implies_that
@ public normal_behavior
@ requires f2 != null;
@ requires f2.isZero() || f2.isNaN();
@ ensures \result != null && \result.isNaN();
@*/
public /*@ non_null @*/
JMLFloat remainderBy(/*@ non_null @*/ JMLFloat f2) {
return new JMLFloat(floatValue % f2.floatValue());
}
/** Tell whether this is strictly greater than the given argument.
*/
/*@ public normal_behavior
@ requires f2 != null;
@ ensures \result <==> this.theFloat > f2.theFloat;
@*/
public boolean greaterThan(/*@ non_null */ JMLFloat f2) {
return (floatValue > f2.floatValue());
}
/** Tell whether this is strictly less than the given argument.
*/
/*@ public normal_behavior
@ requires f2 != null;
@ ensures \result <==> this.theFloat < f2.theFloat;
@*/
public boolean lessThan(/*@ non_null */ JMLFloat f2) {
return (floatValue < f2.floatValue());
}
/** Tell whether this is greater than or equal to the given argument.
*/
/*@ public normal_behavior
@ requires f2 != null;
@ ensures \result <==> this.theFloat >= f2.theFloat;
@*/
public boolean greaterThanOrEqualTo(/*@ non_null */ JMLFloat f2) {
return (floatValue >= f2.floatValue());
}
/** Tell whether this is less than or equal to the given argument.
*/
/*@ public normal_behavior
@ requires f2 != null;
@ ensures \result <==> this.theFloat <= f2.theFloat;
@*/
public boolean lessThanOrEqualTo(/*@ non_null */ JMLFloat f2) {
return (floatValue <= f2.floatValue());
}
/** Return a string representation of this object.
*/
// specification inherited from Object
public String toString() {
return String.valueOf(floatValue);
}
/** Tell whether absolute value of difference of this JMLFloat and the arg
* is within the given epsilon.
*/
/*@ public normal_behavior
@ requires f2 != null;
@ assignable \nothing;
@ ensures \result <==>
@ StrictMath.abs(\nowarn(theFloat - f2.theFloat)) <= epsilon;
@*/
public boolean withinEpsilonOf(/*@ non_null @*/ JMLFloat f2,
float epsilon) {
return StrictMath.abs(floatValue()-f2.floatValue()) <= epsilon;
}
/** Tell whether relative difference of this JMLFloat and the arg is
* within the given epsilon.
* @see #approximatelyEqualTo(float, float, float)
*/
/*@ public normal_behavior
@ requires f2 != null;
@ assignable \nothing;
@ ensures \result
@ <==> approximatelyEqualTo(theFloat, f2.theFloat, epsilon);
@*/
public boolean approximatelyEqualTo(/*@ non_null @*/ JMLFloat f2,
float epsilon) {
return approximatelyEqualTo(floatValue(), f2.floatValue(), epsilon);
}
/** Tell whether absolute value of difference of this JMLFloat and the arg
* is within the given epsilon.
*/
/*@ public normal_behavior
@ requires f2 != null;
@ assignable \nothing;
@ ensures \result <==>
@ StrictMath.abs(\nowarn(theFloat - f2.floatValue())) <= epsilon;
@*/
public boolean withinEpsilonOf(/*@ non_null @*/ Float f2,
float epsilon) {
return StrictMath.abs(floatValue()-f2.floatValue()) <= epsilon;
}
/** Tell whether relative difference of this JMLFloat and the arg is
* within the given epsilon.
* @see #approximatelyEqualTo(float, float, float)
*/
/*@ public normal_behavior
@ requires f2 != null;
@ assignable \nothing;
@ ensures \result
@ <==> approximatelyEqualTo(theFloat, f2.floatValue(), epsilon);
@*/
public boolean approximatelyEqualTo(/*@ non_null @*/ Float f2,
float epsilon) {
return approximatelyEqualTo(floatValue(), f2.floatValue(), epsilon);
}
/** Tell whether absolute value of difference of this JMLFloat and the arg
* is within the given epsilon.
*/
/*@ public normal_behavior
@ assignable \nothing;
@ ensures \result <==>
@ StrictMath.abs(\nowarn(theFloat - f2)) <= epsilon;
@*/
public boolean withinEpsilonOf(float f2, float epsilon) {
return StrictMath.abs(floatValue()-f2) <= epsilon;
}
/** Tell whether relative difference of this JMLFloat and the arg is
* within the given epsilon.
* @see #approximatelyEqualTo(float, float, float)
*/
/*@ public normal_behavior
@ assignable \nothing;
@ ensures \result
@ <==> approximatelyEqualTo(theFloat, f2, epsilon);
@*/
public boolean approximatelyEqualTo(float f2, float epsilon) {
return approximatelyEqualTo(floatValue(), f2, epsilon);
}
/** Tell whether absolute value of difference of the two arguments
* is within the given epsilon.
*/
/*@ public normal_behavior
@ assignable \nothing;
@ ensures \result <==>
@ StrictMath.abs(\nowarn(f1 - f2)) <= epsilon;
@*/
public static /*@ pure @*/ boolean withinEpsilonOf(float f1, float f2,
float epsilon)
{
return StrictMath.abs(f1-f2) <= epsilon;
}
/** Tell whether relative difference of the two arguments is
* within the given epsilon.
*/
/*@ public normal_behavior
@ assignable \nothing;
@ ensures \result <==>
@ f1 == f2
@ || StrictMath.abs(\nowarn(f1 - f2))
@ <= StrictMath.max(StrictMath.abs(f1),
@ StrictMath.abs(f2))
@ * epsilon;
@*/
public static /*@ pure @*/ boolean approximatelyEqualTo(
float f1, float f2, float epsilon)
{
return f1 == f2
|| StrictMath.abs(f1-f2)
<= StrictMath.max(StrictMath.abs(f1),
StrictMath.abs(f2))
* epsilon;
}
/** Tell whether absolute value of difference of this JMLFloat and the arg
* is within the given epsilon.
*/
/*@ public normal_behavior
@ requires f1 != null && f2 != null;
@ assignable \nothing;
@ ensures \result <==>
@ StrictMath.abs(\nowarn(f1.theFloat - f2.theFloat)) <= epsilon;
@*/
public static /*@ pure @*/ boolean withinEpsilonOf(
/*@ non_null @*/ JMLFloat f1,
/*@ non_null @*/ JMLFloat f2,
float epsilon) {
return StrictMath.abs(f1.floatValue()-f2.floatValue()) <= epsilon;
}
/** Tell whether relative difference of this JMLFloat and the arg is
* within the given epsilon.
* @see #approximatelyEqualTo(float, float, float)
*/
/*@ public normal_behavior
@ requires f1 != null && f2 != null;
@ assignable \nothing;
@ ensures \result
@ <==> approximatelyEqualTo(f1.theFloat, f2.theFloat, epsilon);
@*/
public static /*@ pure @*/ boolean approximatelyEqualTo(
/*@ non_null @*/ JMLFloat f1,
/*@ non_null @*/ JMLFloat f2,
float epsilon) {
return approximatelyEqualTo(f1.floatValue(), f2.floatValue(), epsilon);
}
/** Tell whether absolute value of difference of this JMLFloat and the arg
* is within the given epsilon.
*/
/*@ public normal_behavior
@ requires f1 != null && f2 != null;
@ assignable \nothing;
@ ensures \result <==>
@ StrictMath.abs(\nowarn(f1.theFloat - f2.floatValue())) <= epsilon;
@*/
public static /*@ pure @*/ boolean withinEpsilonOf(
/*@ non_null @*/ JMLFloat f1,
/*@ non_null @*/ Float f2,
float epsilon) {
return StrictMath.abs(f1.floatValue()-f2.floatValue()) <= epsilon;
}
/** Tell whether relative difference of this JMLFloat and the arg is
* within the given epsilon.
* @see #approximatelyEqualTo(float, float, float)
*/
/*@ public normal_behavior
@ requires f1 != null && f2 != null;
@ assignable \nothing;
@ ensures \result
@ <==> approximatelyEqualTo(f1.theFloat, f2.floatValue(), epsilon);
@*/
public static /*@ pure @*/ boolean approximatelyEqualTo(
/*@ non_null @*/ JMLFloat f1,
/*@ non_null @*/ Float f2,
float epsilon) {
return approximatelyEqualTo(f1.floatValue(), f2.floatValue(), epsilon);
}
/** Tell whether absolute value of difference of this JMLFloat and the arg
* is within the given epsilon.
*/
/*@ public normal_behavior
@ requires f1 != null;
@ assignable \nothing;
@ ensures \result <==> StrictMath.abs(\nowarn(f1.theFloat - f2)) <= epsilon;
@*/
public static /*@ pure @*/ boolean withinEpsilonOf(
/*@ non_null @*/ JMLFloat f1,
float f2,
float epsilon) {
return StrictMath.abs(f1.floatValue()-f2) <= epsilon;
}
/** Tell whether relative difference of this JMLFloat and the arg is
* within the given epsilon.
* @see #approximatelyEqualTo(float, float, float)
*/
/*@ public normal_behavior
@ requires f1 != null;
@ assignable \nothing;
@ ensures \result
@ <==> approximatelyEqualTo(f1.theFloat, f2, epsilon);
@*/
public static /*@ pure @*/ boolean approximatelyEqualTo(
/*@ non_null @*/ JMLFloat f1,
float f2,
float epsilon) {
return approximatelyEqualTo(f1.floatValue(), f2, epsilon);
}
}