-
Notifications
You must be signed in to change notification settings - Fork 53
Fix Floating-Point Mantissa Not Including Sign Bit #513
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Fix Floating-Point Mantissa Not Including Sign Bit #513
Conversation
…BV transformation and width comparison
…he type/mantissa with/without sign bit and add sign bit to toString and toSMTLIBString representations
…a with/without sign bit and use those as far as possible to make the code unambiguous for mantissas
…n bit and add some assertions for mantissa/exponent
What is the actual effect of this MR (supposed to be)? Is it purely an API improvement that adds new methods and deprecates some old ones, or does it actually change the behavior in some cases? From your previous off-line explanations and from the title ("Fix") I would assume that there was actually broken behavior that is now fixed. But in the description of the MR I do not find anything related to this and it reads as if there is just new stuff and no behavior changes. Please make clear which is the case, and if no existing behavior is actually broken and needs to be changed, reflect this in the MR title.
This wording doesn't really make sense. The |
The behavior is unchanged. It only improves the API, adds new methods, and improves code readability/maintainability. The main problem is that the standard defines the mantissa to include the sign bit, but our API does not. 4/5 SMT solvers with FP support in JavaSMT handle it the same way. Only some parts of the related API are documented, hence users might assume that our API works like the standard or the majority of the solvers describe it. This PR aims to fix this ambiguity. I improved the wording above. |
For the record: I find it good that you decided to not add |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It think I found several bugs. It seems this strongly highlights the need for more tests covering this.
src/org/sosy_lab/java_smt/basicimpl/AbstractFloatingPointFormulaManager.java
Outdated
Show resolved
Hide resolved
@Override | ||
public String toSMTLIBString() { | ||
return "(_ FloatingPoint " + exponentSize + " " + mantissaSize + ")"; | ||
return "(_ FloatingPoint " + exponentSize + " " + getMantissaSizeWithSignBit() + ")"; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FloatingPointFormulaManager.java
Outdated
Show resolved
Hide resolved
src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FloatingPointFormulaManager.java
Outdated
Show resolved
Hide resolved
src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FloatingPointFormulaManager.java
Outdated
Show resolved
Hide resolved
…Number and use new mantissa API instead of the old
… the mantissa size of FPs when parsing FP types from strings
…ead of calculating it by hand each time
Sorry 😅, i assumed you guys know. My bad. |
…ons as sign bit to "hidden" bit
…to FP sizes and the hidden bit
… there are 2 possible replacements and the user should decide which fits best
… there are 2 possible replacements and the user should decide which fits best
…stead of a const BV
…ng the solver to check equality instead of equals()
… them so that we can remove them from the public API
… as we don't want to use the deprecated public API
I renamed all API referencing the sign bit to reference the hidden bit instead. The total size is easier in my opinion, as the total size always includes the hidden bit. |
I updated the PR text with all the changes and added the reference. |
No, it doesn't. If we want |
…lculation explicit in the code
Fair point, the description was wrong! I fixed the JavaDoc in both Still, i would argue that we need to rename |
If all other methods that do not include the hidden bit are called |
That is a fair point! |
I agree with Philipp and would also assume that |
I see it the same way, but would you rename |
Nobody has argued against this. The current question is what should the relation between |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems there were some mistakes introduced in the change from "sign bit" to "hidden bit". I am not sure whether I found all, somebody else should also review everything in detail.
int mantissaSizeWithoutHiddenBit = pTargetType.getMantissaSizeWithoutHiddenBit(); | ||
int size = pTargetType.getTotalSize(); | ||
assert size == mantissaSize + exponentSize + 1; | ||
// total size = mantissa without hidden bit + hidden bit + exponent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// total size = mantissa without hidden bit + hidden bit + exponent | |
// total size = mantissa without hidden bit + size bit + exponent |
assertThat(msat_get_bv_type_size(env, msat_term_get_type(bvNumber))).isEqualTo(totalBVSize); | ||
|
||
int exponent = 8; | ||
int mantissaWithoutSign = 23; // excluding hidden bit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outdated name.
int expWidth = Integer.parseInt(matcher.group(2)); | ||
int mantWidth = Integer.parseInt(matcher.group(3)); | ||
// The term representation in MathSAT5 does not include the hidden bit | ||
int mantWidthWithoutSignBit = Integer.parseInt(matcher.group(3)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outdated name.
final long signSort = getFormulaCreator().getBitvectorType(1); | ||
final long expoSort = getFormulaCreator().getBitvectorType(type.getExponentSize()); | ||
final long mantSort = getFormulaCreator().getBitvectorType(type.getMantissaSize()); | ||
final long mantSort = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does Z3's mkFpaFp
expect the mantissa to be passed with our without hidden bit? If the former, the bitvector below is also created incorrectly.
mant, | ||
pType.getExponentSize(), | ||
pType.getMantissaSize()); | ||
pType.getMantissaSizeWithSignBit()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even with the current changes, this is still a behavioral change, and it is unclear whether it is a bug fix or breaks something.
I think all changes in Z3FormulaCreator
need to be checked carefully against the Z3 docs to make sure that they really match.
* format, according to the given type. The sum of the sizes of exponent and mantissa (including | ||
* the hidden bit) of the target type needs to be equal to the size of the bitvector. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is wrong, right? It needs to refer to the sign bit, but exclude the hidden bit.
* Create a formula that produces a representation of the given floating-point value as a | ||
* bitvector conforming to the IEEE format. The size of the resulting bitvector is the sum of the | ||
* sizes of the exponent and mantissa of the input formula plus 1 (for the sign bit). | ||
* sizes of the exponent and mantissa (including the hidden bit) of the input formula. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
/** | ||
* 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 hidden bit). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sentence is grammatically wrong now, and it misses the sign bit.
/** | ||
* 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 hidden bit). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
A user might prefer shorter significant names, ... so |
…as it is used when constructing Co-authored-by: Philipp Wendler <[email protected]>
…t users explicitly have to choose one of the 2 successor methods
…() for CVC4/5 to reflect what we do in the method better
While implementing PR 512 i found a problem in our implementation of FloatingPointType and number. Our returned significant precision is off by one, see SMTLib2 standard page for Floating-Points. E.g. for single precision FP, we return significant size 23. But the standard defines exponent and significant as:
Hence it should be 24.
As a consequence, we also return this wrongly for
FormulaType
methodtoSMTLIBString()
.This is fixed in this PR.
We also encode the significant without the hidden bit in
toString()
, and subsequently infromString
.While this is in general not as bad, i changed it to include the hidden bit now (in both), so that it is in-line with the standard.
These behavior changes should be communicated clearly to users!
The solvers generally expect the hidden bit to be part of the significant, hence why we had 4 solvers with the code
type.getMantissaSize() + 1
, and only one solver without the+ 1
(MathSAT5).The general behavior of FP creation/solving is correct IFF you know that the mantissa does not include the sign bit.
Also, we don't communicate any information about our interpretation of FP precisions, hence the users might think that by building
FormulaType.getFloatingPointType(8, 24)
(first input is exponent, second is significant) they get a single precision FP-type, but in reality they get a total size of 33 bits currently. Our static implementation of the single/double precisions is fine however.This PR adds/changes the following:
+-1
FloatingPointType.toSMTLIBString()
.FloatingPointType.toString()
andFloatingPointType.fromString()
to include the hidden bit in the significant.FloatingPointType.toString()
etc.I feel like the API changes reduce the magic
+ 1
and- 1
by a large amount, increasing readability of the code. My guess is that users, especially new users, will benefit from that. The deprecation warning needs to be discussed/done.