Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
f99f39c
Add native Mathsat test for mantissa not including the sign bit with …
Sep 1, 2025
737718c
Add note about mantissa und sign bit in FloatingPointNumber.java
Sep 1, 2025
d50ad4c
Add JavaDoc to FormulaType.FloatingPointType and add methods to get t…
Sep 1, 2025
a4240e6
Add JavaDoc to FloatingPointNumber and add methods to get the mantiss…
Sep 1, 2025
c452a8f
Extend FP tests with new mantissa API to be unambiguous about the sig…
Sep 1, 2025
a6f92b7
Update Bitwuzla with new unambiguous FP mantissa size getters
Sep 1, 2025
ca4a3f7
Update CVC4 with new unambiguous FP mantissa size getters
Sep 1, 2025
7bed3f5
Update CVC5 with new unambiguous FP mantissa size getters
Sep 1, 2025
73c1451
Update MathSAT5 with new unambiguous FP mantissa size getters
Sep 1, 2025
1ca40f9
Update Z3 with new unambiguous FP mantissa size getters
Sep 1, 2025
6d80321
Update SolverVisitorTest with new unambiguous FP mantissa size getters
Sep 1, 2025
44310e0
Fix off-by-one FP mantissa bug when casting BV to FP
Sep 2, 2025
475ce68
Remove changes left over from PR 512 (to be added back with PR 512!)
Sep 2, 2025
bb3760d
Fix bug in test using the wrong mantissa size for an FP
Sep 2, 2025
31b0b38
Apply checkstyle naming/grammar suggestions
Sep 2, 2025
4b07b9b
Fix off-by-one error for mantissa for getFloatingPointTypeWithSignBit()
Sep 2, 2025
e444b52
Update naming of mantissa arguments in constructors for FloatingPoint…
Sep 2, 2025
f1ff09f
Fix accidentally added off-by-one bug in CVC4 when building FPs
Sep 2, 2025
eddaf77
Use new FP mantissa getter in CVC4 and remove magic -1 + improve var…
Sep 2, 2025
1dae5d1
Unify constructors of FloatingPointType by delegating to the same met…
Sep 2, 2025
7755fe6
Use the SMTLIB2 standards interpretation of including the sign bit in…
Sep 2, 2025
83cd136
Add method for total type size in FloatingPointNumber and use it inst…
Sep 2, 2025
96a2565
Rename method for total type size in FloatingPointNumber to getTotalS…
Sep 2, 2025
885bb68
Add deprecation of both getMantissaSize() methods with reasoning
Sep 2, 2025
59713fe
Revert CVC4 fromIeeeBitvectorImpl() implementation and use new API ca…
Sep 3, 2025
05b6c40
Revert AbstractFloatingPointFormulaManager toIeeeBitvectorImpl() to p…
Sep 3, 2025
a08a811
Revert CVC4 toIeeeBitvectorImpl() to previous implementation and fix …
Sep 3, 2025
a2a7810
Revert CVC5 toIeeeBitvectorImpl() and fromIeeeBitvectorImpl() to prev…
Sep 3, 2025
f37786e
Fix error in assertion in CVC5 fromIeeeBitvectorImpl()
Sep 3, 2025
0bd0aa7
Fix error in assertion in CVC4 fromIeeeBitvectorImpl()
Sep 3, 2025
7331cd1
Add method to check the availability of native FP to BV in tests
Sep 3, 2025
031a900
Fix CVC4/5 size assertion in fromIeeeBitvectorImpl() again :D
Sep 3, 2025
3d17811
Add FP tests for mantissa size with and without sign bit, as well as …
Sep 3, 2025
55089a0
Improve constructor naming for FormulaType.FloatingPointType to bette…
Sep 3, 2025
d836779
Add total size check to FP checks for single/double precision in Floa…
Sep 3, 2025
0885fd0
Improve JavaDoc of FloatingPointType constructors
Sep 3, 2025
23cdc67
Update variable/const names of mantissas in FloatingPointNumber/Float…
Sep 3, 2025
d67273c
Improve CVC5 documentation in regard to mantissa including the sign b…
Sep 3, 2025
b7b8aff
Update code with "getMantissaSizeWithSignBit() - 1" in MathSAT5 to us…
Sep 3, 2025
225ba7a
Add info about the mantissa size to MathSAT5 native API
Sep 3, 2025
9df8b66
Add inlineMe annotations with replacements to newly deprecated FP met…
Sep 3, 2025
7207b71
Update more deprecated FP API with the new alternatives and simplify …
Sep 3, 2025
5086ae7
Update one more FP type constructor in CVC5 to better include the man…
Sep 3, 2025
6cb15ea
Update a mantissa size variable name to include sign bit in CVC4Float…
Sep 3, 2025
f760eb1
Update a mantissa size variable names to include sign bit in Bitwuzla…
Sep 3, 2025
f7c5916
Update an FP type constructor in Z3 to a better one
Sep 3, 2025
fbea69f
Simplify calculation of total size of FP type
Sep 5, 2025
e043988
Refactor some FP/precision sizes/mantissa code in CVC4
Sep 5, 2025
d9d2b3e
Remove accidentally added class
Sep 5, 2025
1aba81d
Use the correct getter for mantissas in Z3FormulaCreator for FPs
Sep 5, 2025
dd83ed4
Split BV to FP to BV tests and remove solverSupportsNativeFPToBitvect…
Sep 7, 2025
c83f96f
Update all names referencing the hidden bit in Floating-Point precisi…
Sep 7, 2025
e8f44d8
Revert some changes back to sign bit that were accidentally changed
Sep 7, 2025
00dc033
Improve some JavaDoc in FloatingPointFormulaManager.java in relation …
Sep 7, 2025
20a8f48
Add tests for FP type (precision) toString(), fromString(), and toSMT…
Sep 11, 2025
6769850
Remove @InlineMe annotation for deprecated call getMantissaSize(), as…
Sep 12, 2025
015c145
Remove @InlineMe annotation for deprecated call getMantissaSize(), as…
Sep 12, 2025
9aff78a
Disable parts of FP to IEEE BV tests for Z3, as it returns a query in…
Sep 12, 2025
ddac078
Enable FP to IEEE BV precision tests for Z3 and Bitwuzla fully by usi…
Sep 12, 2025
52d6e30
Re-add removed FP single/double mantissa size constants and deprecate…
Sep 12, 2025
5dd10ca
Add FP single/double precision sizes to FloatingPointNumberTest.java,…
Sep 12, 2025
e08a75a
Fix incorrect JavaDoc for FP precision total size API and make the ca…
Sep 12, 2025
bd8c6bd
Explicitly name sign bit in FloatingPointNumber constructor JavaDoc, …
baierd Sep 22, 2025
55901fc
Remove @InlineMe from deprecated method getFloatingPointType() so tha…
Sep 22, 2025
b835125
Rename wrongly named variable in Mathsat5 FP impl
Sep 22, 2025
056ca12
Rename wrongly named variable in CVC4 FP impl
Sep 22, 2025
234452d
Change comment about total FP precision size in fromIeeeBitvectorImpl…
Sep 22, 2025
80c480c
Extend the comments in FormulaType fromString() and FP toString() wit…
Sep 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 37 additions & 13 deletions src/org/sosy_lab/java_smt/api/FloatingPointNumber.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
@AutoValue
public abstract class FloatingPointNumber {

// Mantissas do not include the sign bit
public static final int SINGLE_PRECISION_EXPONENT_SIZE = 8;
public static final int SINGLE_PRECISION_MANTISSA_SIZE = 23;
public static final int DOUBLE_PRECISION_EXPONENT_SIZE = 11;
Expand Down Expand Up @@ -80,8 +81,29 @@ public final boolean getSign() {

public abstract int getExponentSize();

/**
* Returns the size of the mantissa (also called a coefficient or significant), excluding the sign
* bit.
*/
// TODO: mark as soon to be deprecated
public abstract int getMantissaSize();

/**
* Returns the size of the mantissa (also called a coefficient or significant), excluding the sign
* bit.
*/
public int getMantissaSizeWithoutSignBit() {
return getMantissaSize();
}

/**
* Returns the size of the mantissa (also called a coefficient or significant), including the sign
* bit.
*/
public int getMantissaSizeWithSignBit() {
return getMantissaSize() + 1;
}

/**
* Get a floating-point number with the given sign, exponent, and mantissa.
*
Expand All @@ -92,7 +114,7 @@ public final boolean getSign() {
* @param mantissa the mantissa of the floating-point number, given as unsigned (not negative)
* number without hidden bit
* @param exponentSize the (maximum) size of the exponent in bits
* @param mantissaSize the (maximum) size of the mantissa in bits
* @param mantissaSize the (maximum) size of the mantissa in bits (excluding the sign bit)
* @see #of(Sign, BigInteger, BigInteger, int, int)
*/
@Deprecated(
Expand All @@ -119,7 +141,7 @@ public static FloatingPointNumber of(
* @param mantissa the mantissa of the floating-point number, given as unsigned (not negative)
* number without hidden bit
* @param exponentSize the (maximum) size of the exponent in bits
* @param mantissaSize the (maximum) size of the mantissa in bits
* @param mantissaSize the (maximum) size of the mantissa in bits (excluding the sign bit)
*/
public static FloatingPointNumber of(
Sign sign, BigInteger exponent, BigInteger mantissa, int exponentSize, int mantissaSize) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think that documenting this here is enough?

I have already recommend to use FloatingPointType instead of the two ints when this was added, which unfortunately was rejected. I want to renew this recommendation.

Note that even the current state of this PR calls FloatingPointNumber.of() with the wrong values, at least in Z3FormulaCreator, because it is forced to extract the two numbers from a FloatingPointType instance that it already has. If there would have been a way to create a FloatingPointNumber instance based on a FloatingPointType, the code there would have simply used that and would now not have needed to be touched nor would the bug have been introduced.

Same for the other method below.

Expand All @@ -136,7 +158,7 @@ public static FloatingPointNumber of(
* @param bits the bit-representation of the floating-point number, consisting of sign bit,
* exponent (without bias) and mantissa (without hidden bit) in this exact ordering
* @param exponentSize the size of the exponent in bits
* @param mantissaSize the size of the mantissa in bits
* @param mantissaSize the size of the mantissa in bits (excluding the sign bit)
*/
public static FloatingPointNumber of(String bits, int exponentSize, int mantissaSize) {
Preconditions.checkArgument(0 < exponentSize);
Expand All @@ -159,24 +181,26 @@ public static FloatingPointNumber of(String bits, int exponentSize, int mantissa

/**
* Returns true if this floating-point number is an IEEE-754-2008 single precision type with 32
* bits length consisting of an 8 bit exponent, a 23 bit mantissa and a single sign bit.
* bits length consisting of an 8 bit exponent, a 24 bit mantissa (including the sign bit).
*
* @return true for IEEE-754 single precision type, false otherwise.
*/
public boolean isIEEE754SinglePrecision() {
// Mantissa does not include the sign bit
return getExponentSize() == SINGLE_PRECISION_EXPONENT_SIZE
&& getMantissaSize() == SINGLE_PRECISION_MANTISSA_SIZE;
&& getMantissaSizeWithoutSignBit() == SINGLE_PRECISION_MANTISSA_SIZE;
}

/**
* Returns true if this floating-point number is an IEEE-754-2008 double precision type with 64
* bits length consisting of an 11 bit exponent, a 52 bit mantissa and a single sign bit.
* bits length consisting of an 11 bit exponent, a 53 bit mantissa (including the sign bit).
*
* @return true for IEEE-754 double precision type, false otherwise.
*/
public boolean isIEEE754DoublePrecision() {
// Mantissa does not include the sign bit
return getExponentSize() == DOUBLE_PRECISION_EXPONENT_SIZE
&& getMantissaSize() == DOUBLE_PRECISION_MANTISSA_SIZE;
&& getMantissaSizeWithoutSignBit() == DOUBLE_PRECISION_MANTISSA_SIZE;
}

/** compute a representation as Java-based float value, if possible. */
Expand Down Expand Up @@ -204,18 +228,18 @@ public double doubleValue() {
}

private BitSet getBits() {
var mantissaSize = getMantissaSize();
var mantissaSizeWithoutSign = getMantissaSizeWithoutSignBit();
var exponentSize = getExponentSize();
var mantissa = getMantissa();
var exponent = getExponent();
var bits = new BitSet(1 + exponentSize + mantissaSize);
var bits = new BitSet(exponentSize + mantissaSizeWithoutSign + 1);
if (getMathSign().isNegative()) {
bits.set(exponentSize + mantissaSize); // if negative, set first bit to 1
bits.set(exponentSize + mantissaSizeWithoutSign); // if negative, set first bit to 1
}
for (int i = 0; i < exponentSize; i++) {
bits.set(mantissaSize + i, exponent.testBit(i));
bits.set(mantissaSizeWithoutSign + i, exponent.testBit(i));
}
for (int i = 0; i < mantissaSize; i++) {
for (int i = 0; i < mantissaSizeWithoutSign; i++) {
bits.set(i, mantissa.testBit(i));
}
return bits;
Expand All @@ -227,7 +251,7 @@ private BitSet getBits() {
*/
@Override
public final String toString() {
var length = 1 + getExponentSize() + getMantissaSize();
var length = getExponentSize() + getMantissaSizeWithSignBit();
var str = new StringBuilder(length);
var bits = getBits();
for (int i = 0; i < length; i++) {
Expand Down
86 changes: 80 additions & 6 deletions src/org/sosy_lab/java_smt/api/FormulaType.java
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,61 @@ public String toSMTLIBString() {
}
}

public static FloatingPointType getFloatingPointType(int exponentSize, int mantissaSize) {
return new FloatingPointType(exponentSize, mantissaSize);
/**
* Constructs a new IEEE-754 {@link FloatingPointType} with the given exponent and mantissa sizes.
* The mantissa size is expected to not include the sign bit.
*
* @param exponentSize size of the exponent for the base of the floating-point
* @param mantissaSizeWithoutSignBit size of the mantissa (also called a coefficient or
* significant), excluding the sign bit.
* @return the newly constructed {@link FloatingPointType}.
*/
// TODO: mark as soon to be deprecated
public static FloatingPointType getFloatingPointType(
int exponentSize, int mantissaSizeWithoutSignBit) {
return new FloatingPointType(exponentSize, mantissaSizeWithoutSignBit);
}

/**
* Constructs a new IEEE-754 {@link FloatingPointType} with the given exponent and mantissa sizes.
* The mantissa size is expected to not include the sign bit.
*
* @param exponentSize size of the exponent for the base of the floating-point
* @param mantissaSizeWithoutSignBit size of the mantissa (also called a coefficient or
* significant), excluding the sign bit.
* @return the newly constructed {@link FloatingPointType}.
*/
public static FloatingPointType getFloatingPointTypeWithoutSignBit(
int exponentSize, int mantissaSizeWithoutSignBit) {
return new FloatingPointType(exponentSize, mantissaSizeWithoutSignBit);
}

/**
* Constructs a new IEEE-754 {@link FloatingPointType} with the given exponent and mantissa sizes.
* The mantissa size is expected to not include the sign bit.
*
* @param exponentSize size of the exponent for the base of the floating-point
* @param mantissaSizeWithSignBit size of the mantissa (also called a coefficient or significant),
* including the sign bit.
* @return the newly constructed {@link FloatingPointType}.
*/
public static FloatingPointType getFloatingPointTypeWithSignBit(
int exponentSize, int mantissaSizeWithSignBit) {
return new FloatingPointType(exponentSize, mantissaSizeWithSignBit);
}

/**
* @return single precision {@link FloatingPointType} with exponent sized 8, and mantissa sized 24
* (including the sign bit).
*/
public static FloatingPointType getSinglePrecisionFloatingPointType() {
return FloatingPointType.SINGLE_PRECISION_FP_TYPE;
}

/**
* @return double precision {@link FloatingPointType} with exponent sized 11, and mantissa sized
* 53 (including the sign bit).
*/
public static FloatingPointType getDoublePrecisionFloatingPointType() {
return FloatingPointType.DOUBLE_PRECISION_FP_TYPE;
}
Expand All @@ -226,6 +273,8 @@ public static final class FloatingPointType extends FormulaType<FloatingPointFor
new FloatingPointType(DOUBLE_PRECISION_EXPONENT_SIZE, DOUBLE_PRECISION_MANTISSA_SIZE);

private final int exponentSize;
// The SMTLib2 standard defines the mantissa size as including the sign bit. We do not include
// it here though.
private final int mantissaSize;

private FloatingPointType(int pExponentSize, int pMantissaSize) {
Expand All @@ -238,15 +287,40 @@ public boolean isFloatingPointType() {
return true;
}

/** Returns the size of the exponent */
public int getExponentSize() {
return exponentSize;
}

/**
* Returns the size of the mantissa (also called a coefficient or significant), excluding the
* sign bit.
*/
// TODO: mark as soon to be deprecated
public int getMantissaSize() {
return mantissaSize;
}

/** Return the total size of a value of this type in bits. */
/**
* Returns the size of the mantissa (also called a coefficient or significant), excluding the
* sign bit.
*/
public int getMantissaSizeWithoutSignBit() {
return mantissaSize;
}

/**
* Returns the size of the mantissa (also called a coefficient or significant), including the
* sign bit.
*/
public int getMantissaSizeWithSignBit() {
return mantissaSize + 1;
}

/**
* Return the total size of a value of this type in bits. Equal to exponent + mantissa
* (including the sign bit).
*/
public int getTotalSize() {
return exponentSize + mantissaSize + 1;
}
Expand All @@ -270,12 +344,12 @@ public boolean equals(Object obj) {

@Override
public String toString() {
return "FloatingPoint<exp=" + exponentSize + ",mant=" + mantissaSize + ">";
return "FloatingPoint<exp=" + exponentSize + ",mant=" + getMantissaSizeWithSignBit() + ">";
}

@Override
public String toSMTLIBString() {
return "(_ FloatingPoint " + exponentSize + " " + mantissaSize + ")";
return "(_ FloatingPoint " + exponentSize + " " + getMantissaSizeWithSignBit() + ")";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, this seems to be a desired behavior change of this MR, isn't it?

So it would mean that there are not just API improvements but also an actual bug fix. Hopefully this method is rarely used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SMTLIB2 standard says that our previous implementation is wrong here, as statet above As a consequence, we also return this wrongly for toSMTLIBString() etc.. Example from the standard: - Float32 is a synonym for (_ FloatingPoint 8 24). As a consequence i would change it and communicate this to the users.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the initial PR text accordingly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one-line-fix could have been part of a separate PR, which might have been accepted much easier.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where can I find (new or updated) tests for that method?

}
}

Expand Down Expand Up @@ -478,7 +552,7 @@ public static FormulaType<?> fromString(String t) {
} else if (t.startsWith("FloatingPoint<")) {
// FloatingPoint<exp=11,mant=52>
List<String> exman = Splitter.on(',').limit(2).splitToList(t.substring(14, t.length() - 1));
return FormulaType.getFloatingPointType(
return FormulaType.getFloatingPointTypeWithoutSignBit(
Integer.parseInt(exman.get(0).substring(4)), Integer.parseInt(exman.get(1).substring(5)));
} else if (t.startsWith("Bitvector<")) {
// Bitvector<32>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,12 @@ public BitvectorFormula toIeeeBitvector(FloatingPointFormula pNumber) {
return getFormulaCreator().encapsulateBitvector(toIeeeBitvectorImpl(extractInfo(pNumber)));
}

protected abstract TFormulaInfo toIeeeBitvectorImpl(TFormulaInfo pNumber);
@SuppressWarnings("unused")
protected TFormulaInfo toIeeeBitvectorImpl(TFormulaInfo pNumber) {
throw new UnsupportedOperationException(
"Solver does not support transformation from "
+ "floating-point numbers to IEEE bitvector");
}

@Override
public FloatingPointFormula negate(FloatingPointFormula pNumber) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ protected Term makeNumberImpl(
Sort expSort = termManager.mk_bv_sort(type.getExponentSize());
Term expTerm = termManager.mk_bv_value(expSort, exponent.toString(2));

Sort mantissaSort = termManager.mk_bv_sort(type.getMantissaSize());
Sort mantissaSort = termManager.mk_bv_sort(type.getMantissaSizeWithoutSignBit());
Term mantissaTerm = termManager.mk_bv_value(mantissaSort, mantissa.toString(2));

return termManager.mk_fp_value(signTerm, expTerm, mantissaTerm);
Expand Down Expand Up @@ -144,7 +144,7 @@ protected Term castToImpl(
pRoundingMode,
pNumber,
targetType.getExponentSize(),
targetType.getMantissaSize() + 1);
targetType.getMantissaSizeWithSignBit());
} else if (pTargetType.isBitvectorType()) {
FormulaType.BitvectorType targetType = (FormulaType.BitvectorType) pTargetType;
if (pSigned) {
Expand All @@ -171,14 +171,14 @@ protected Term castFromImpl(
roundingMode,
pNumber,
pTargetType.getExponentSize(),
pTargetType.getMantissaSize() + 1);
pTargetType.getMantissaSizeWithSignBit());
} else {
return termManager.mk_term(
Kind.FP_TO_FP_FROM_UBV,
roundingMode,
pNumber,
pTargetType.getExponentSize(),
pTargetType.getMantissaSize() + 1);
pTargetType.getMantissaSizeWithSignBit());
}

} else {
Expand All @@ -193,7 +193,7 @@ protected Term fromIeeeBitvectorImpl(Term pNumber, FloatingPointType pTargetType
Kind.FP_TO_FP_FROM_BV,
pNumber,
pTargetType.getExponentSize(),
pTargetType.getMantissaSize() + 1);
pTargetType.getMantissaSizeWithSignBit());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ assert getFormulaType(pTerm).isBitvectorType()
// system instead use bitwuzla_mk_fp_value_from_real somehow or convert myself
@Override
public Sort getFloatingPointType(FloatingPointType type) {
return termManager.mk_fp_sort(type.getExponentSize(), type.getMantissaSize() + 1);
return termManager.mk_fp_sort(type.getExponentSize(), type.getMantissaSizeWithSignBit());
}

@Override
Expand Down Expand Up @@ -171,7 +171,7 @@ public FormulaType<?> bitwuzlaSortToType(Sort pSort) {
if (pSort.is_fp()) {
int exponent = pSort.fp_exp_size();
int mantissa = pSort.fp_sig_size() - 1;
return FormulaType.getFloatingPointType(exponent, mantissa);
return FormulaType.getFloatingPointTypeWithoutSignBit(exponent, mantissa);
} else if (pSort.is_bv()) {
return FormulaType.getBitvectorTypeWithSize(pSort.bv_size());
} else if (pSort.is_array()) {
Expand Down Expand Up @@ -380,7 +380,7 @@ public <T extends Formula> FormulaType<T> getFormulaType(T pFormula) {
}
int exp = sort.fp_exp_size();
int man = sort.fp_sig_size() - 1;
return (FormulaType<T>) FormulaType.getFloatingPointType(exp, man);
return (FormulaType<T>) FormulaType.getFloatingPointTypeWithoutSignBit(exp, man);
} else if (sort.is_rm()) {
return (FormulaType<T>) FormulaType.FloatingPointRoundingModeType;
}
Expand Down
Loading