I have had the same scheme for my app checking a server to see if there’s an update for over 10 years. It recently stopped working correctly.
I have a text file on server with version. My app periodically checks for new version by comparing itself to what’s in file. Pretty simple…
// s is string retrieved, in this case “2.35” which matches the major, minor, bug version 2,3,5
// both remoteVersion and myVersion are declared as doubles and then compared like so:
remoteVersion = val(left(s, 4))
myVersion = (app.MajorVersion+app.MinorVersion/10+app.BugVersion/100)
if myVersion < remoteVersion then.... //open a dialog to advise
// in debugger I see:
myVersion = 2.3499999999999996
remoteVersion =2.3500000000000001
If I change to single (in lieu of using double) I get 2.3499999046325684 for both, which is fine, since it doesn’t misinform my user that they have an out of date app.
You can use Double.Equals to mitigate the issue, but as Tim says, Double is really the wrong variable type to use for this. You have simply been lucky the last 10 years.
‘val’ returns a double, which is why I used doubles.
The documentation of ‘val’ shows:
Var n As Double
n = Val(“12345”) // returns 12345
n = Val(“54.25car45”) // returns 54.25
n = Val(“123.25”) // returns 123.25
n = Val(“123 25”) // returns 123
n = Val(“123,456”) // returns 123
n = Val(“auto”) // returns 0
n = Val(“&hFFF”) // returns 4095
n = Val(“&b1111”) // returns 15
Var s As String
s = “12345”
n = s.Val // returns 12345
A Double cannot represent many (most?) fractional values exactly. And as you have discovered, they will not use the same approximation, depending on how you create them. So why not just compare string values instead? You get a string from the server, so create a string from your major, minor, bug versions.
I can figure out other ways to do it and am aware of the difference between doubles, singles, etc, I am just bringing it up because it seems odd that something that was worked going back to RealBasic of 2007 or so, suddenly stopped working with Xojo 2022 v. 3. I searched the forum for something similar and didn’t see it, so thought it was useful to report. Also found it interesting that if using single, both approximations are equal. Maybe this will be useful to someone else…
Take my criticism with all the best intentions, but your scheme is not the best designed one. People store much more digits than 1 for minor and 1 for build/bug. And no one uses floating for such, but…
Here is a proposal to keep the current compatibility:
Var s As string = "2.35" // s receives version as M.IB string (M=Major from 0 to 999, I=Minor 0-9, B=Bug 0-9
If app.MinorVersion>9 Or app.BugVersion>9 Then
MessageBox "Bad version digits. Check them." // Dev error
End
Var remoteIntegerVersion As Integer = s.Trim.Val*100
Var thisIntegerVersion As Integer = app.MajorVersion*100+app.MinorVersion*10+app.BugVersion
If thisIntegerVersion < remoteIntegerVersion Then //open a dialog to advise
Messagebox("Need to update")
End
This is a really bad idea, any of those 3 numbers can become a double or triple digits and your old versions will become unable to compare.
Yes, double precision sucks for this kind of use and xojo dont have Decimal numbers (currency is limited and uses doubles in conversions), doubles are aproximations to the value so it can have many rounding problems.
I have the same system as you, with a text file (Json) with the major, minor and bug versions then asigning them to INTEGER variables and comparing those, first the Major then Minor and Bug…
If not Json, you can parse the version string and still assign the parts to Integer variables for comparing
It is more code but it is future proof, working with any digit size of the versions and dont having the xojo rounding problems in doubles.
I just tried your code in 2019r1.1 and it showed the same issue so I don’t believe its a recent update that’s caused the problem. Maybe you have just been lucky that the two values have landed on similar results all this time?
It’s possible that they switched to a different library, or that some OS upgrade changed it. Either way, it isn’t something that they have a lot of control over.
For this specific example, yes. It doesn’t mean another example will fail. What you’ve done is just reduce the precision of the floating portion. It doesn’t prevent the type of error you encountered. Either use the Equals method or find a better way to compare. It could be as simple as
if Round(myVersion*100) = Round(remoteVersion*100) then
But as others have pointed out, you may want to provide for version numbers that are greater than a single digit. I would go for a string version formated like “002.003.005”. Maybe even 4 digits per value.
I realize that that introduces an incompatibility with your existing installations. You could add an additional value after left(s,4) or you could just store this idea for new projects.
You are correct. I just mocked up a test using RB 2012 I have on an old machine and I see the same thing. Ha ha. Curiously, if I use 2.34 instead of 2.35, both #'s are the same.
If you make your string be mmm.nnn.bbb with any number of digits in each portion, you can get:
Var maj, min, bug as Integer, verStr as String
verStr = "2.3333.77"
maj = verStr.NthField(".", 1).ToInteger
min = verStr.NthField(".", 2).ToInteger
bug = verStr.NthField(".", 3).ToInteger
// and then do your comparison
Thx TimS - used a similar scheme which allows me to have b/w compatibility with what’s up there now, but just test integers. Thanks to others for their input.