VBcoders Guest



Don't have an account yet? Register
 


Forgot Password?



Provided simple conversion between different number bases, including fractional parts. One function

by Richard Deeming (1 Submission)
Category: Math/Dates
Compatability: Visual Basic 5.0
Difficulty: Unknown Difficulty
Originally Published: Thu 17th August 2000
Date Added: Mon 8th February 2021
Rating: (1 Votes)

Provided simple conversion between different number bases, including fractional parts. One function will convert between any specified bases.

API Declarations



Private Const ERROR_NUMBER = 13&

Private Const HexChars = "0123456789ABCDEF"
Private Const AlphaChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

Public Enum Bases
ebBinary = 2&
ebOctal = 8&
ebDecimal = 10&
ebHexadecimal = 16&
ebAlphabet = 26&
ebSexagesimal = 60& 'Base 60, e.g. time
End Enum

Rate Provided simple conversion between different number bases, including fractional parts. One function



'Return the length of a digit in a given base
    Select Case Base
        Case ebSexagesimal:
            DigitLength = 3
        
        'Add other special cases here
        
        Case Else   'ebBinary, ebOctal, ebDecimal, ebHexadecimal
            DigitLength = 1
    End Select
End Function

Private Function Floor(ByVal Number As Double) As Double
'Return the floor of the number
'(the highest whole number less than or equal to the number)
    If Int(Number) > Number Then
        Floor = Int(Number) - 1
    Else
        Floor = Int(Number)
    End If
End Function

Private Function GetNumDec(dblTemp As Double, PadTo As Long, Base As Bases) As Long
'Return the number of digits required to represent
'the number dblTemp in the specified base, padded
'to the nearest multiple of PadTo

Dim lTemp As Long, lTempPad As Double
    
    If dblTemp = 0 Then
        lTemp = 1
    Else
        lTemp = Floor(Log(dblTemp) / Log(Base)) + 1
    End If
    If PadTo > 1 Then
        lTempPad = lTemp / CDbl(PadTo)
        If lTempPad > Floor(lTempPad) Then
            lTempPad = 1 + Floor(lTempPad) - lTempPad
            lTempPad = lTempPad * PadTo
            
            lTemp = lTemp + lTempPad
        End If
    End If
    GetNumDec = lTemp
End Function

Private Function ConvertDigit(lngDigit As Long, Base As Bases) As String
'Convert a single digit to the specified base
    If lngDigit >= Base Then
        Err.Raise ERROR_NUMBER, "ConvertDigit", "Invalid digit for base"
    Else
        Select Case Base
            Case ebBinary, ebOctal, ebDecimal:
                ConvertDigit = CStr(lngDigit)
            
            Case ebHexadecimal:
                ConvertDigit = Mid$(HexChars, lngDigit + 1, 1)
           
           Case ebAlphabet:
               ConvertDigit = Mid$(AlphaChars, lngDigit + 1, 1)
            
            Case ebSexagesimal:
                ConvertDigit = Right$("00" & CStr(lngDigit), 2) & ":"
                
            'Add other bases here
            Case Else: Err.Raise ERROR_NUMBER, "ConvertDigit", "Unknown base"
        End Select
    End If
End Function

Private Function DeconvertDigit(strDigit As String, Base As Bases) As Long
'Convert a single digit from the specified base to decimal
Dim lngTemp As Long
    Select Case Base
        Case ebBinary, ebOctal, ebDecimal:
            If IsNumeric(strDigit) Then
                lngTemp = CLng(strDigit)
                If lngTemp < Base Then
                    DeconvertDigit = lngTemp
                Else
                    Err.Raise ERROR_NUMBER, "DeconvertDigit", "Invalid digit for base"
                End If
            Else
                Err.Raise ERROR_NUMBER, "DeconvertDigit", "Invalid character"
            End If
            
        Case ebHexadecimal:
            lngTemp = InStr(1, HexChars, UCase$(strDigit))
            If lngTemp = 0 Then
                Err.Raise ERROR_NUMBER, "DeconvertDigit", "Invalid digit for base"
            Else
                DeconvertDigit = lngTemp - 1
            End If
            
       Case ebAlphabet:
           lngTemp = InStr(1, AlphaChars, UCase$(strDigit))
           If lngTemp = 0 Then
               Err.Raise ERROR_NUMBER, "DeconvertDigit", "Invalid Alpha Character"
           Else
               DeconvertDigit = lngTemp - 1
           End If
            
        Case ebSexagesimal:
            If Len(strDigit) = 3 Then
                If Right$(strDigit, 1) = ":" And IsNumeric(Left$(strDigit, 2)) Then
                    lngTemp = CLng(Left$(strDigit, 2))
                    If lngTemp < Base Then
                        DeconvertDigit = lngTemp
                    Else
                        Err.Raise ERROR_NUMBER, "DeconvertDigit", "Invalid digit for base"
                    End If
                Else
                    Err.Raise ERROR_NUMBER, "DeconvertDigit", "Invalid digit for base"
                End If
            Else
                Err.Raise ERROR_NUMBER, "DeconvertDigit", "Invalid digit for base"
            End If
        
        'Add other bases here
        
        Case Else:
            Err.Raise ERROR_NUMBER, "DeconvertDigit", "Unknown base"
    End Select
End Function

Private Function ConvertDec2Base(ByVal Number, ByVal Base As Bases, Optional NumDecimals As Long = -1, Optional Tolerance As Double = 1E-27, Optional PadTo As Long = 0) As String
'Convert Number from decimal to the specified base,
'with NumDecimals fractional digits (or to within tolerance),
'padded to the nearest multiple of PadTo

Dim dblTemp As Double
Dim lCDec As Long
Dim lDigit As Long
Dim dblPwr As Double
Dim strTemp As String

    If Not IsNumeric(Number) Then
        Err.Raise ERROR_NUMBER, "ConvertDec2Base", "Number must be decimal"
    ElseIf Base < 2 Then
        Err.Raise ERROR_NUMBER, "ConvertDec2Base", "Invalid base"
    Else
        'Negative tolerance could cause loops
        Tolerance = Abs(Tolerance)
        
        dblTemp = CDbl(Number)
        If dblTemp < 0 Then
            strTemp = "-"
            dblTemp = -dblTemp
        End If
        
        lCDec = GetNumDec(dblTemp, PadTo, Base)
        
        'Integer part
        If lCDec = 0 Then
            strTemp = strTemp & "0"
        Else
            Do Until lCDec = 0
                lCDec = lCDec - 1
                dblPwr = Base ^ lCDec
                lDigit = 0
                Do While dblTemp >= dblPwr
                    lDigit = lDigit + 1
                    dblTemp = dblTemp - dblPwr
                Loop
                strTemp = strTemp & ConvertDigit(lDigit, Base)
            Loop
        End If
        
        'Fractional part
        If dblTemp > Tolerance And (NumDecimals > 0 Or (NumDecimals = -1 And Tolerance > 0)) Then
            strTemp = strTemp & "."
            Do While dblTemp > Tolerance And (lCDec > (-NumDecimals) Or NumDecimals = -1)
                lCDec = lCDec - 1
                dblPwr = Base ^ lCDec
                lDigit = 0
                Do While dblTemp >= dblPwr
                    lDigit = lDigit + 1
                    dblTemp = dblTemp - dblPwr
                Loop
                strTemp = strTemp & ConvertDigit(lDigit, Base)
            Loop
        End If
        ConvertDec2Base = strTemp
    End If
End Function

Private Function ConvertBase2Dec(ByVal Number As String, ByVal Base As Bases) As Double
'Convert the number from the specified base to decimal
Dim dblTemp As Double
Dim strDigit As String, lngDigit As Long, i As Long
Dim lngPwr As Long, lngSign As Long, lngDigitSize
    
    If Base < 2 Then
        Err.Raise ERROR_NUMBER, "ConvertBase2Dec", "Invalid Base"
    Else
        lngDigitSize = DigitLength(Base)
        lngPwr = 0
        lngSign = 1
        i = 1
        Do Until i > Len(Number)
            strDigit = Mid$(Number, i, lngDigitSize)
            If Left$(strDigit, 1) = "." Then
                i = i + 1
                If lngPwr = 0 Then
                    lngPwr = 1
                Else
                    Err.Raise ERROR_NUMBER, "ConvertBase2Dec", "More than one decimal point"
                End If
            ElseIf Left$(strDigit, 1) = "-" Then
                i = i + 1
                If lngPwr = 0 And dblTemp = 0 Then
                    lngSign = -lngSign
                Else
                    Err.Raise ERROR_NUMBER, "ConvertBase2Dec", "Invalid negation"
                End If
            Else
                i = i + lngDigitSize
                lngDigit = DeconvertDigit(strDigit, Base)
                dblTemp = dblTemp * Base + lngDigit
                lngPwr = lngPwr * Base
            End If
        Loop
        If lngPwr > 1 Then
            ConvertBase2Dec = CDbl(lngSign) * (dblTemp / CDbl(lngPwr))
        Else
            ConvertBase2Dec = CDbl(lngSign) * dblTemp
        End If
    End If
End Function

Public Function ConvertBase(ByVal Number, ByVal FromBASE As Bases, Optional ByVal ToBASE As Bases = ebDecimal, Optional NumDecimals As Long = -1, Optional Tolerance As Double = 1E-27, Optional PadTo As Long = 0) As Variant
'Convert a number from one base to another.
'Parameters:
'       Number      A numeric value (when FromBASE = ebDecimal) or
'                   a string representing the number to convert
'
'       FromBASE    The base to convert from (enumeration)
'
'       ToBASE      (Optional) The base to convert to. Default = Decimal
'
'       NumDecimals (Optional) The number of decimal places to include
'                   when converting a fractional number to a non-decimal
'                   Specify 0 for integer only, or -1 to use tolerance.
'                   (This prevents problems with infinte loops)
'
'       Tolerance   (Optional) The value at which to terminate the
'                   fractional representation. If NumDecimals = -1
'                   and Tolerance = 0, no attempt will be made, to
'                   avoid an infinite loop. The sign of the tolerance
'                   is ignored.
'
'       PadTo       (Optional) Used to pad the non-decimal number
'                   to a given length. EG, binary numbers are
'                   normally shown with a multiple of 8 digits, so
'                   you would specify 8. Use 0 to avoid padding.
'
'Returns:
'       Either a double (if ToBASE = ebDecimal) or a string representing
'       the converted number.

Dim dblDec As Double
    If FromBASE = ebDecimal Then
        If IsNumeric(Number) Then
            dblDec = CDbl(Number)
        Else
            Err.Raise ERROR_NUMBER, "ConvertBase", "Not a decimal number"
        End If
    Else
        dblDec = ConvertBase2Dec(CStr(Number), FromBASE)
    End If
    If ToBASE = ebDecimal Then
        ConvertBase = dblDec
    Else
        ConvertBase = ConvertDec2Base(dblDec, ToBASE, NumDecimals, Tolerance, PadTo)
    End If
End Function


Download this snippet    Add to My Saved Code

Provided simple conversion between different number bases, including fractional parts. One function Comments

No comments have been posted about Provided simple conversion between different number bases, including fractional parts. One function. Why not be the first to post a comment about Provided simple conversion between different number bases, including fractional parts. One function.

Post your comment

Subject:
Message:
0/1000 characters