excelvbasplitintegerdecimal

VBA - Get Fractional Part of a Number, problems with Int()


I am trying to obtain the fractional part of a number in VBA in Excel. Is there a particular method that works best to get the fractional part of a number?

I have tried two different methods. One of these methods gives the expected result of 0.1. The other method gives an unexpected result of 9.99999999999996E-02. Please help me understand why I am receiving this unexpected result. Please refer to the following code:

    Dim DecNumber As Double
    Dim TempSplit() As String
    Dim DecFract As Double
    
    DecNumber = 15.1
    
    'METHOD 1
    'Gives unexpected result of 9.99999999999996E-02
    DecFract = DecNumber - Int(DecNumber)
    
    'METHOD 2
    'Gives expected result of 0.1
    TempSplit() = Split(DecNumber, ".")
    DecFract = TempSplit(1) / (10 ^ Len(CStr(TempSplit(1)))) 

Solution

  • The differences are due to the fact that calculations in Excel are based on the binary system, and the accuracy of calculations with double precision is limited to about 15 significant digits. When subtracting similar numbers, the relative accuracy decreases and inexact digits may appear in the last places of the expansion. But in general, the first method provides better accuracy if the example is not specially chosen.
    You can try to reduce the occurrence of random trailing digits by using rounding, but this is also not 100% effective.
    Compare results for different numbers. You can also use Currency type as proposed by @taller if 4 decimal places accuracy is enough for you.

    Sub Decimals()
        Dim DecNumber As Double
        Dim TempSplit() As String
        Dim DecFract As Double
        Dim fact As Double
        
      '  DecNumber = 15.1
        DecNumber = 145.1 / 7
      '  DecNumber = 15.0625
        
        'METHOD 1
        'Gives unexpected result of 9.99999999999996E-02
        DecFract = DecNumber - Int(DecNumber)
        Debug.Print DecFract
        
        'METHOD 1A
        fact = 1E+17
        DecFract = (Round(DecNumber * fact) - Int(DecNumber) * fact) / fact
        Debug.Print DecFract
        
        'METHOD 2
        'Gives expected result of 0.1
        TempSplit() = Split(DecNumber, ".")
        DecFract = TempSplit(1) / 10 ^ Len(TempSplit(1))
        Debug.Print DecFract
    
       'METHOD 2A
       ' TempSplit() = Split(DecNumber, ".")
       fact = 10 ^ Len(TempSplit(1))
       DecFract = (Round(DecNumber * fact) - Int(DecNumber) * fact) / fact
       Debug.Print DecFract
    End Sub