Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Counting decimals 3

Status
Not open for further replies.

elHollandes

Programmer
Feb 22, 2004
12
0
0
ES
Hi all,

Here´s a function to find the number of decimals from a number. I don´t like it, but can´t find a better way. The function could be a lot faster if I dont have to convert to a string or at least don´t have to searge for points and comma´s. Since I use this function many times, speed is important. Maybe if I only knew how VB stores a double... Anyone has somthing better?

Thanks, El Holandais


START LISTING

Public Function iDecimals(ByVal iNumber As Double) As Integer
Dim sNumber As String

sNumber = Format(iNumber)
'convert to string
If InStr(sNumber, ".") > 0 Then
'has decimal point
iDecimals = Len(sNumber) - InStr(sNumber, ".")
'numbers after point
ElseIf InStr(sNumber, ",") > 0 Then
'has decimal comma
iDecimals = Len(sNumber) - InStr(sNumber, ",")
'numbers after comma
Else
'has no point or comma
iDecimals = 0
'no decimals
End If
End Function

END LISTING
 
Code:
Public Function basNumDec(ByVal NumIn As Double) As Integer

    basNumDec = Len(str(NumIn - Int(NumIn))) - 2

End Function

Although there is some confusion on my part re the 'rest of the story'.

If the purpose is to "count" the number of digits following the decimal point (per the discussion), then checking for the "Dot" (or comma) seems specious. I've not dealt with varations in the "International" settings, so cannot be sure, but generally, the default settings for VB(S) won't accept a "European" formatted numeric value (comma as decimal seperator), so by desiggnating the input arg type as double, it (seems like) it forves the inputs to conform to the settings for the decimal seperator, greatly simplifying the entire proces (See above).

It is also worth noting that the procedure return the count of SIGNIFICANT 'decimal' characters, so trailing spaces and/or zeroes are not 'counted'.

Then I can't really say that my 'abreviated' funcrtion is any faster than the original, as I haven't generated any test for the actuqal speed.

MichaelRed


 
el,

Approaches not using strings may be unreliable and the answer is related to rounding and chickens and eggs.

Approaches like Michaels will work reliably most of the time however occasionally you may pass a NumIn value which cannot be exactly described by the computer in binary format, thus you may think you are passing a value of n.123 but the value actually in the variable is something like n.123000001. VB6's Round function suffers from similar effects.

I expect you may be examining a group of numbers to find the one with most decimal places and then applying that precision to the result of a statistic eg. average on the group. This is the eggy bit; I would prefer to round the data to a standard number of places before calculating the statistic and then apply that precision to the result.

Hope this makes a little sense.

regards Hugh



regards Hugh
 
Thanks MichaelRed and Hugh for your responce. Your solution is very nice indeed and has the simplicity I was looking for. Since I´ll check only numbers that are direct user input I don´t think I´ll need to worry about numbers that VB can´t display, so I´ll stick to the simple solution. Thanks again,

El Hollandes

 
elHollandes,

Well, then check the result when user enters 20 decimal digits.

VladK
 
elHollandes,

This is a bit more complicated example. You will probably not like it since you could simply restrict the number of characters entered in text box. But it should handle the count correctly.


In form:

Private Sub Command1_Click()
MsgBox NumDecFromText(Text1)
End Sub

Private Function NumDecFromText(ByRef ioobjTextBox As TextBox) As Integer
Dim strText As String
Dim intReturn As Integer
Dim strDecimalSymbol As String
Dim intDecimalSymbolPos As Integer
Dim lngLCID As Long

strText = Trim$(ioobjTextBox.Text)

If IsNumeric(strText) Then
lngLCID = GetSystemDefaultLCID()
strDecimalSymbol = GetUserLocaleInfo(lngLCID, LOCALE_SDECIMAL)
intDecimalSymbolPos = InStr(1, strText, strDecimalSymbol, vbBinaryCompare)
intReturn = IIf(intDecimalSymbolPos = 0, 0, Len(strText) - intDecimalSymbolPos)

Else
intReturn = 0
End If

NumDecFromText = intReturn

End Function

In module:

Public Const LOCALE_SDECIMAL As Long = &HE 'decimal separator
Public Const LOCALE_STHOUSAND As Long = &HF 'thousand separator
Public Const LOCALE_SGROUPING As Long = &H10 'digit grouping
Public Const LOCALE_IDIGITS As Long = &H11 'number of fractional digits
Public Const LOCALE_ILZERO As Long = &H12 'leading zeros for decimal
Public Const LOCALE_INEGNUMBER As Long = &H1010 'negative number mode
Public Const LOCALE_SNATIVEDIGITS As Long = &H13 'native ascii 0-9
Public Const LOCALE_SPOSITIVESIGN As Long = &H50 'positive sign
Public Const LOCALE_SNEGATIVESIGN As Long = &H51 'negative sign

Public Declare Function GetThreadLocale Lib "kernel32" () As Long

Public Declare Function GetSystemDefaultLCID Lib "kernel32" () As Long

Public Declare Function GetLocaleInfo Lib "kernel32" _
Alias "GetLocaleInfoA" _
(ByVal Locale As Long, _
ByVal LCType As Long, _
ByVal lpLCData As String, _
ByVal cchData As Long) As Long


Public Function GetUserLocaleInfo(ByVal dwLocaleID As Long, ByVal dwLCType As Long) As String

Dim strReturn As String
Dim lngReturn As Long

lngReturn = GetLocaleInfo(dwLocaleID, dwLCType, strReturn, Len(strReturn))

If lngReturn Then
strReturn = Space$(lngReturn)
lngReturn = GetLocaleInfo(dwLocaleID, dwLCType, strReturn, Len(strReturn))

If lngReturn Then
GetUserLocaleInfo = Left$(strReturn, lngReturn - 1)
End If

End If

End Function

Vladk
 
vladk,

You can also determine the decimal character from;

Function dpChar$()

dpChar$ = Mid$(Format$(0.1, "fixed"), 2, 1)

End Function

regards Hugh,
 
HughLerwill,

I gave you the star. I tested your code with different decimal symbol settings, and it works.

vladk
 
Just thought of a variation.

num = 11111.0001

MsgBox IIf(InStr(1, num, ".") > 0, Len(num) - InStr(1, num, "."), 0)

------------------------------------------
The faulty interface lies between the chair and the keyboard.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top