Format "00.00" and Round problem

I have this code:

[code]Listbox1.DeleteAllRows
Dim s,r,d As Double
Listbox1.AddRow(“Starting at 1.005”)
For d = 1.005 To 1.155 Step 0.01
r = Round(d * 100) / 100
s = Round((d+0.00001)*100) / 100
listbox1.AddRow(d.ToText,Format(d,“00.00”), Format(r,“00.00”), Format(s,“00.00”))
Next

Listbox1.AddRow(“Starting at 0.905”)
For d = 0.905 To 1.155 Step 0.01
r = Round(d * 100) / 100
s = Round((d+0.00001)*100) / 100
listbox1.AddRow(d.ToText,Format(d,“00.00”), Format(r,“00.00”), Format(s,“00.00”))
Next[/code]

The first listbox entries from the first For…Next are different than the corresponding values on the second For…Next.

  r = Round((d * 100)+0.5) / 100

or

  r =ceil((d * 100)) / 100

Thank you Dave.

I did more tests, it looks like the problem, at least for the Round column is the value for Double. I used a Break statement to see the values directly, even when the double totext = 1.005 the value used is 1.00499999999, that’s why when the for … next statement start with 1.005 it doesn’t round to 1.01

When the for…next start with 0.905 the internal value is also 0.905, that’s why when it reaches 1.005 by adding 0.01 several times the value used is a little above 1.005 and this time the round is done correctly.

If you see the value I assign to s, you will see that I already use your first solution, but with a smaller value:

s = Round((d+0.00001)*100) / 100 is the same as s = Round((d * 100) + 0.001) / 100

The data was just for illustration purposes. I really don’t know what values I’m going to get, so having sometimes 0.005 go up to 0.01 and sometimes down to 0.00 when I use Format “00.00” or other function is something that I have to think how to deal with that.

Maybe I can add an even smaller value.

Do you have this the wrong way round?
Double.totext () is already doing its own rounding.
Doubles are imprecise by definition.

This is why when working with money, many apps use integers and divide at the last minute.

Does this make a difference?

For d = 1005 To 1155 Step 10 r = Round(d * 100) / 100 s = Round((d+0.00001)*100) / 100 listbox1.AddRow(d.ToText,Format(d/1000,"00.00"), Format(r/1000,"00.00"), Format(s/1000,"00.00")) Next

Hey Jeff, thank you but it also has some issues:

When d = 1005…1125
Format(d/1000, “00.00”) = 01.00…01.12

When d = 1135…1155
Format(d/1000, “00.00”) = 01.14…01.16

Btw the same for Format(r/1000, “00.00”) and Format(s/1000, “00.00”)

Sorry Alberto, I didn’t do the whole math for you.

Dave’s example

Is the last hint you need.

1005 rounded is still 1005
1.005 formatted to 00.00 is 1.00

You need 1005 to become 1010 before the division.
So if you want things to round up, add 5

1004 becomes 1009 , divide by 1000 = 1.009 format as 00.00 = 1.00 correct
1005 becomes 1010 divide by 1000 = 1.010 format as 00.00 = 1.01 correct
1999 becomes 2004 divide by 1000 = 2.004 format as 0.00 = 2.00 correct

double is not that precise at all
if you need 2 digits, you can use the currency data type, it will have less rounding errors
you can also use a 64 bits integer, and then divide the result by 100 to get your last number
if you need complete full precision, you can use the decimal plugin : http://delaneyrm.com/DecimalPlugin.html

Doubles are great for science, but not so good for finance or engineering. I would encourage you to use currency data types where accuracy is the goal.

Neither round, nor Currency types work correctly in Xojo
Replacements are available (recent code submitted in https://forum.xojo.com/20531-double-currency/p3#p360693)
Decimal plugin available elsewhere leaks memory
Avoid Currency data type, don’t use round (better to write your own)

Thank you all for your comments.

For the “Should be” column I did this:

s = Round((d+0.00001)*100) / 100

It equals to:

s = Round((d*100)+0.001) / 100

And it works. After thinking much about it, Dave and Jeff are correct, is better to just add 0.5, just in case the value internally is 1.0049899 and adding 0.00001 just make the number 1.0049999

Another interesting information, Format(d, “00.00”) do an Arithmetic Rounding, every exact half gets rounded up to the next value, so 1.05 results in 1.10, but Double.ToText(Xojo.Core.Locale.Raw, “00.00”) will give you a Banker’s Rounding also called half-even, where 1.15 goes to nearest even 1.20 and 1.25 also goes to nearest even 1.20.

More information about this rounding and others:
https://support.microsoft.com/en-us/help/196652/how-to-implement-custom-rounding-procedures

More interesting is that there is no error using this Double.ToText(Xojo.Core.Locale.Raw, “00.00”), at least for this example. No need to add 0.5 to get the correct results (for Banker’s Rounding).

I am looking on using the Decimal Plugin, I think this is the first time I read it leaks memory. Any information on how bad this is? I’m not working on public apps, just personal/private use.

decimal plugin works great - perfect results, except every time it is instantiated it leaks 416 bytes (multiply that by pay input transactions for hundreds/thousands of staff…I’m sure Bob Delaney would fix it with some encouragement (I haven’t reported it to him bad me, but did test it). This should just be fixed in Xojo and we’d all be happier. Maths on Currency is a dismal failure.

Thank you Matthew.

Newbie question, when you say “every time it is instantiated” does it mean like every time I do:
1.- Dim dTest As Decimal
2.- dTest = 15.5 * 18.897
3.- dTest.str
4.- dTest = New Decimal(“3.1415926535897932384626433832795”)
5.- all of the above

I think I can answer my question. I’m using the next code:

For i As Integer = 0 To 10000 // Test code here Next i
and Activity Monitor on Mac to see if the app.debug memory use increase.

I use something like this in a 5 second loop to monitor app leaks (try it with a simple button action that test a currency calc, try it with a WebSegmentedControl which also leaks just by clicking it)

sudo leaks --nostacks --nocontext -q appname|head -2

replace app name with whatever your app is called - it’ll find it automatically in the process list (ps), e.g. gopayroll or myleakyapp

Hope that helps

i got the following. what does it mean

Process 32517: 203453 nodes malloced for 34930 KB
Process 32517: 135 leaks for 17632 total leaked bytes.

Alberto, try using my Class Money, would be something like:

Dim m As New Money Listbox1.DeleteAllRows Dim d As Double Listbox1.AddRow("Starting at 1.005") For d = 1.005 To 1.155 Step 0.01 listbox1.AddRow(d.ToText, Format(d,"00.00"), m.Load(d).Round.ToText("00.00"), "?") Next ....

Found here: https://forum.xojo.com/45734-currency-data-type-wrong-calculations-and-comparison/p1#p371499

Wow. I wrote “Money” to avoid the eternal broken Currency, but didn’t know about “Round”, I use it once in this class, do I need to update it with my own “Round” too? Oh Man… I see… Here is the Round thing proof:

MsgBox(“Round(1.015100)="+Round(1.015100).ToText+” and should be 102.0")

I need to adjust the Money class due to it. :frowning:

Done. Now it uses an internal round() routine

https://drive.google.com/file/d/1gQP7vVvJyIAunBRSkJdJyI2PJJErpPFi/view?usp=sharing

Thank you Rick, I’ll test your “Money”.

It will be interesting to see your code and try to understand what it does.

I guess you are using arithmetic rounding. I wonder how hard it will be (for me) to have the option for banker’s rounding.

Will add a RoundB() to it soon and let you know.