B4J Question Float numbers - Again, sorry

LucaMs

Expert
Licensed User
Longtime User
I opened a thread over an year ago, about Float numbers.
See: https://www.b4x.com/android/forum/threads/float-type-is-wrong.42820/

Today I tried a very small project which seemed devoid of logical errors. I am attaching the project.

In summary, at each Tick of a timer, every 50 milliseconds, the value of a ProgressBar is increased by 0.1. Reached the maximum value, ie 1, the timer is disabled.
B4X:
Sub tmr_Tick
    ProgressBar1.Progress = ProgressBar1.Progress + .1
    If ProgressBar1.Progress = 1 Then
        tmr.Enabled = False
    End If
End Sub

This does not happen, because the values are never accurate.

I thought about the fact that maybe the timer is not accurate to the thousandth, so I added a variable Float to take a test, but I get even worse results.

Now I wonder: there is no logic error in the project (this does not happen in other languages/ S.O.).
What to do?!?!

(I know that I could write:
If ProgressBar1.Progress >= 1 Then
of course; this is not the problem)


[P.S. to check the error, it is useful to add a Log after: tmrEnabled = False]
 

Attachments

  • DueForm.zip
    2.6 KB · Views: 320
Last edited:

LucaMs

Expert
Licensed User
Longtime User
Tested: I get the same behavior using VB.Net!

(I remembered an accurate result using VB.Net, maybe I wrote this in the old thread and that was a different example. Well, good night )

Think that a calculator that costs 50 cents (china shop? ) does not have these problems!
 
Upvote 0

Roycefer

Well-Known Member
Licensed User
Longtime User
Why do you think this doesn't happen in other languages? Direct equality comparisons of floating point numbers (be they 32 bit like Float or 64 bit like Double) is almost always a bad idea. This is true in C/C++ just as it is true in Java (and therefore B4J). Standard practice for comparison of floating point numbers is to decide on a tolerance and see if the tested value is within +/- tolerance of the target value.
B4X:
Sub FloatingPointValueWithinTolerance(test As Double, target As Double, tolerance As Double) as Boolean
    Return test<=target + tolerance And test>=target - tolerance
End Sub

But in your specific example, equality (even within tolerance) is most likely too restrictive of a criterion, anyhow. I think you should be using "greater than or equal to":
B4X:
If ProgressBar1.Progress>=.99 Then tmr.Enabled = False
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
If you know how many digits you want to be accurate to, just use
B4X:
ProgressBar1.Progress = NumberFormat(ProgressBar1.Progress + 0.1d,1,1)

Remembering, ProgressBar wants a Double value not a float, hence the 0.1d
 
Upvote 0

Ed Brown

Active Member
Licensed User
Longtime User
Another approach is to use an Int.

I know, before you say something like "that's crazy and not going to work" let me further explain

Using an Int allows you to check for the accuracy and then by dividing it by 100 will also give the progressbar the 'double' value that it needs. A simple example follows:

B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private tmr1 As Timer
    Private progCount As Int
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    progCount = 0
    tmr1.Initialize("tmr1", 250)
    tmr1.Enabled = True
End Sub

Sub tmr1_Tick
    progCount = progCount + 1 ' Int used for accuracy
    Log(progCount / 100) ' divide by 100 to get double
    If progCount = 100 Then ' do your test and action here
        progCount = 0
    End If
End Sub
 
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…