-
Notifications
You must be signed in to change notification settings - Fork 4
Handle common floats to string operations in the model and not in the string solver #23
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
Conversation
| public static float doubleToFloat(double d) | ||
| { | ||
| float converted = nondetFloat(); | ||
| CProver.assume(d < Float.MAX_VALUE && d > -Float.MAX_VALUE && d == (double) converted); |
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 makes sense for test generation but not really for verification. Could we change this assume for an assert?
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.
Hmmm. I am not sure what if you suggest is better than the current approach, but I see where you're coming from, at least the user will explicitly see the violated assertion in the output. I've changed this.
| public static float doubleToFloat(double d) | ||
| { | ||
| float converted = nondetFloat(); | ||
| CProver.assume(d < Float.MAX_VALUE && d > -Float.MAX_VALUE && d == (double) converted); |
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.
Isn't the last condition enough to ensure the two first ones?
|
Thanks @romainbrenguier for your comments, this is now ready for re-reviews. |
antlechner
left a comment
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.
Could you explain why you're making these changes? Do they improve performance, or was something changed in the string solver that requires this?
| // DIFFBLUE MODEL LIBRARY This is treated internally in CBMC | ||
| return CProver.nondetWithoutNullForNotModelled(); | ||
| // DIFFBLUE MODEL LIBRARY we cast the number down to float because string solver only knows how to convert floats to string | ||
| return valueOf(CProver.doubleToFloat(d)); |
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.
❓ How is the result of this method call different from just casting d to type float?
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.
In doubleToFloat we're ensuring that there's no loss of precision in the conversion, so that we convert the correct number to string. Say we had double x, then converted it to double y, and then we converted that to String z. z is a string representation of y, but not necessarily of x. After a discussion with @romainbrenguier I went for the doubleToFloat implementation in order to make it more likely that the string representation of x equals the string representation of y.
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 understand the precision problem but I don't understand how doubleToFloat avoids this problem. As float has fewer bits than double, wouldn't there always be a loss of precision? And can we be sure that for every double d, there is actually a float f such that d == (double) f;? Since there are strictly fewer floats than doubles this doesn't look right... and would mean that we sometimes can't get past the assume in doubleToFloat.
Maybe we could briefly discuss this in person? It's possible that I'm just missing something.
In any case, some tests in another repository would be great to see what this actually does/fixes.
src/main/java/java/lang/String.java
Outdated
| public static String valueOf(double d) { | ||
| // DIFFBLUE MODEL LIBRARY This is treated internally in CBMC | ||
| return CProver.nondetWithoutNullForNotModelled(); | ||
| // DIFFBLUE MODEL LIBRARY we cast the number down to float because string solver only knows how to convert floats to string |
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.
⚒️ Could you wrap this line at 80 characters please?
❓ Also, is it a new thing that the string solver only converts floats and not doubles? If not, how did this work before?
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's not a new thing, before we'd either crash completely or not crash and then return a conversion which was likely to be incorrect.
| // super.append(i); | ||
| // return this; | ||
| return CProver.nondetWithoutNullForNotModelled(); | ||
| return append(String.valueOf(i)); |
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 isn't related to floats so should probably be in a separate commit.
❔ Why is this done for int but not long, char etc.?
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.
Good point. It's a follow-up from diffblue/cbmc#4633. I've split this into a separate commit.
Other types should be coming later too, but at the moment I concentrated on the bugs that I've seen in our benchmarks, and am handling them one by one.
4ee1992 to
c842964
Compare
|
@antlechner The reason for the changes is that there are a lot of |
antlechner
left a comment
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.
Thanks for explaining these changes in person, this makes a lot more sense now I know it's a workaround that will be improved in the future.
It would be great if you could add some documentation about this. Tests in at least one repository would be good too to check if this workaround works for most common values of double or if it's very easy to hit the limitations.
romainbrenguier
left a comment
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.
Can you squash the last commit into the relevant one? Otherwise looks good.
src/main/java/java/lang/String.java
Outdated
| public static String valueOf(double d) { | ||
| // DIFFBLUE MODEL LIBRARY This is treated internally in CBMC | ||
| return CProver.nondetWithoutNullForNotModelled(); | ||
| // DIFFBLUE MODEL LIBRARY we cast the number down to float because string solver only knows how to convert floats to string |
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 line is long
| public static float doubleToFloat(double d) | ||
| { | ||
| float converted = nondetFloat(); | ||
| CProver.assume(d == (double) converted); |
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 would say this makes sense in the models-library but in the core models this assumption shouldn't be there because it constrain the behavior too much and for verification we always want an over-approximation of the behavior.
Complements this PR on cbmc: diffblue/cbmc#4633
aefa206 to
24afc75
Compare
No description provided.