INT Function Rounding Problems

I have just spent the last few hours trying to find a problem where applying rounding after adding VAT was coming up with an odd few pence difference. Not that unusual you might think until I tripped over the code that was actually causing the porblem.

I have recreated the problem as an example as follows.....

Private Sub Command1_Click()

Dim TotVal As Currency

Dim VatRate As String

VatRate = "15"

TotVal = 2.1

MsgBox "Total VAT = " & ((TotVal * Val(VatRate)) + 0.5) / 100

MsgBox "Total VAT = " & Int((TotVal * Val(VatRate)) + 0.5) / 100

End Sub

The first message box returns 0.32 as expected (2.1 * 15) = 31.5, +0.5 = 32, /100 = 0.32

However for some unknown reason the second message box using the INT function returns 0.31 !!! Basically according to this code the interger portion of 32 is 31.

Just to complicate matters, if I use a double instead of a currency variable then it returns the right result and if I use CINT again all is fine.

In my original program I am using a string for the VAT rate as it is stored in a flexgrid

I have found a work around by putting the VAT rate into a currency variable as well but I would like to know what is likely to be causing this kind of error.

Re: INT Function Rounding Problems

Integers are used for whole numbers.

I'd actually recommend you stcik with double / currency when dealing with floating point numbers, as they are intended to do so. Currency, IMHO, will give you even more preciseness than double.

Re: INT Function Rounding Problems

Yes, but now wait. This is rather an interesting oservation which I'd like to have explained, too.

This is really weird, in fact, (or I'm suffering from acute blindness).

Look:

We have a string VatRate, which is 15.

**Debug.print int(totval * val(VatRate) + 0.5)** gives you 31 ????? How is that.

If we resolve Val(VatRate) to 15 manually we get

**Debug.Print Int(totval *15 + 0.5)** and we get 32 as expected.

???????????

I tried this up and down now, and still wondering...

Re: INT Function Rounding Problems

It gets weirder still. If **Dim TotVal As Currency** is changed to **Dim TotVal As Double** it does return 32 as expected!

Sorry, missed it in the first post, you have seen the double already.

Re: INT Function Rounding Problems

How about Floor/Ceil?

Code:

`Option Explicit`

Private Sub Form_Load()

MsgBox RoundUp(123.3456, 1)

MsgBox "Ceiling " & Ceil(3.2)

MsgBox "Floor " & Floor(3.2)

End Sub

Public Function RoundUp(dblNbr As Double, intPlaces As Integer) As Double

' When intPlaces is 0 it rounds up to the nearest whole number

' When intPlaces is 1 it rounds up to the nearest tenth

' etc.

Dim intFactor As Integer

intFactor = 10 ^ intPlaces

RoundUp = (Int((dblNbr * intFactor) + 0.5) + 1) / intFactor

End Function

Public Function Ceil(ByVal Number) As Long

If Number >= 0 Then

If Number = Int(Number) Then

Ceil = Number

Else

Ceil = Int(Number) + 1

End If

ElseIf Number < 0 Then

Ceil = Int(Number)

End If

End Function

Public Function Floor(ByVal Number) As Long

Floor = Fix(Number)

End Function

Re: INT Function Rounding Problems

Well, all this is really strange and I never noticed that before.

Your Ceil function does not get to the ground of it, as I see it, David. It is logical and works as expected.

Let's see.

Code:

` Dim tv As Currency`

tv = 2.1

Debug.Print Int(tv * Val("15") + 0.5)

The above code prints 31, which is wrong.

Do I change tv as Double, it prints out 32, which is right.

BUT: Do I change Val("15") against 15 (which is the correct evaluation), the result is 32, too.???

Where is the error?

Re: INT Function Rounding Problems

half wasn't getting the right value. try this.... Prints 32

Code:

`Private Sub Form_Load()`

Dim tv As Currency

tv = 2.1

half = 0.5

Debug.Print Int(tv * Val("15") + half)

End Sub

Re: INT Function Rounding Problems

Are you saying the literal 0.5 is in fact converted to 0 when I use Val("15") and is 0.5 when I use 15 literally???

Really strange.

Hm... I played a little with your suggestion and thought, you have not declared half.

Go and **dim half as currency **and it prints 32. **Dim half as double **and it prints 31. :)

Why is this?

Change **Val("15") **with **15** and it prints 32 again...

It seems you are on the right track. depending on the previous operand the type of "half" or 0.5 is converted. If it is converted to Integer, we lose it, because Int(0.5) is 0.

Re: INT Function Rounding Problems

Well it's nice to see that I am not going completely mad.

WoF's code:

Dim tv As Currency

tv = 2.1

Debug.Print Int(tv * Val("15") + 0.5)

This will indeed return 31 but if you remove the INT then it returns 32! Also CINT returns 32.

This is obviously something weird with the INT function. If I step through my code and debug print any part of the calculation it returns exactly what I expect until the INT gets it's grubby hands on it.

I am trying to avoid using double variables as I know the problems these can have problems with numbers ending up with .0000000001 or .999999999999.

Looks like the 0.5 should be stored as a currency to avoid doubles but then the VAL function will return a double anyway.

Go Figure!

Re: INT Function Rounding Problems

Well, a solution seems to be, not to evaluate Val("15") within the Int() function, but to compute it before to a currency.

(Anyway I donm't understand why you declare VatRate a string.)

If you want VatRate to be a string for some reason, then

Code:

` Dim curVatRate as Currency`

Dim TotVal as Currency

curVatRate = Val(VatRate)

TotVal = 2.1

Debug.Print Int(TotVal * curVatRate + 0.5)

Although this is a solution to your problem, it does not explain (yet) why this happens.

Re: INT Function Rounding Problems

I was using the VAT as a string because in the project that I found this problem the VAT is being stored in a flexgrid. Basically the grid holds details of each individual line of charges of an invoice and each line may be zero or 15% VAT (or indeed 17.5% if it is an older invoice).

This little nugget was buried way down iin the code and it was only after detailed inspection of an entire monthly invoice run that I found out where these odd pennies were disappearing to.

I agree there are a number of possible solutions/workarounds but the problem itself still seems somewhat curious. It would appear that CINT may be the way forward.

I will have to try this on .NET to see if this is unique to VB6.

Re: INT Function Rounding Problems

Yes, please report on your findings.

I'd be curious about the reason of this. I'm quite confident that it has to do with the inherent type conversions of the parts of the entire expression.

If we have the Val("15") within the expressions, the result turns out ot be wrong.

If 15 is given literally, then we get the right result.

Strange.

Re: INT Function Rounding Problems

Well, I've had a little play on this one with vb2008 and it seems to work fine (with these numbers anyway) but then 2008 doesn't have a currency type any more so I was using the decimal data type.

All I can really say on this one is that it definitely looks like a glitch within the INT function which is strange because you would have thought that Microsoft would have got that right by now!

Anyway thankyou all for your input, I think I will find a dark room to sit in for a while.

Re: INT Function Rounding Problems

We have a winner!

**Banker's Rounding**

Quote:

When you add rounded values together, always rounding .5 in the same direction results in a bias that grows with the more numbers you add together. One way to minimize the bias is with banker's rounding.

Banker's rounding rounds .5 up sometimes and down sometimes. The convention is to round to the nearest even number, so that both 1.5 and 2.5 round to 2, and 3.5 and 4.5 both round to 4. Banker's rounding is symmetric.

In Visual Basic for Applications, the following numeric functions perform banker's rounding: CByte(), CInt(), CLng(), CCur(), and Round().

There are no Excel spreadsheet functions that perform banker's rounding.

http://support.microsoft.com/kb/196652

Re: INT Function Rounding Problems

Seems like I completely mis read the entire question :blush:

Sorry Killa, and everyone!

This is indeed very interesting findings :thumb:

Great thread!