Reputation: 6050
We have a .net visual basic project that uses the function Strings.formatnumber
this is used because of its flexibility, namely the number of decimal places allowed with a dynamic variable. However I have come across a nasty bug in that this function seems to round everything to 15 digits
so
? Strings.FormatNumber("123456789012345.66", 2,Microsoft.VisualBasic.TriState.True,Microsoft.VisualBasic.TriState.False,Microsoft.VisualBasic.TriState.False)
Results 123456789012345.00
? Strings.FormatNumber("12345678901234.66", 2,Microsoft.VisualBasic.TriState.True,Microsoft.VisualBasic.TriState.False,Microsoft.VisualBasic.TriState.False)
Results 12345678901234.60
? Strings.FormatNumber("1234567890123.66", 2,Microsoft.VisualBasic.TriState.True,Microsoft.VisualBasic.TriState.False,Microsoft.VisualBasic.TriState.False)
Results 1234567890123.66
? Strings.FormatNumber("1234567890123456666.66", 2,Microsoft.VisualBasic.TriState.True,Microsoft.VisualBasic.TriState.False,Microsoft.VisualBasic.TriState.False)
Results 1234567890123460000.00
So two questions
Upvotes: 2
Views: 544
Reputation: 6948
Is there a .net function that we can use that will turn strings into numbers and return a string and where the number of decimals can be dynamic?
Here's a simple wrapper for the FormatNumber method that allows you to specify, the maximum length with padding for integral portion, decimal places, thousands separator and negative parentheses:
Private Function MyFormatNumber(input As String, MaxLength As Integer, Optional RightDecimal As Integer = 2, Optional Thousands As TriState = TriState.UseDefault, Optional Negative As TriState = TriState.UseDefault) As String
Dim TempNumber As Decimal = Decimal.Parse(input)
Dim DecimalIndex As Integer = Decimal.Truncate(Math.Abs(TempNumber)).ToString.Length
Dim LeftPad As Integer = (MaxLength - RightDecimal) - DecimalIndex
MyFormatNumber = Strings.FormatNumber(TempNumber, RightDecimal, TriState.True, Negative, Thousands)
If MyFormatNumber.StartsWith("(") Then
MyFormatNumber = "(" + MyFormatNumber.Substring(1).PadLeft((MyFormatNumber.Length - 1) + LeftPad, "0"c)
Else
MyFormatNumber = MyFormatNumber.PadLeft(MyFormatNumber.Length + LeftPad, "0"c)
End If
End Function
Call it like this:
Dim numberstr As String = ("-12345678901234566.12347", 22, 4, TriState.True, TriState.True)
The output is:
?numberstr
"(012,345,678,901,234,566.1235)"
This assumes that you are validating the strings to be a number type. If not you can use the TryParse method instead.
Upvotes: 1
Reputation: 354734
double
only has 15–16 decimal digits of precision. While there can be more digits, they are mostly garbage. Some languages/environments opt to show you the complete number if you want to, but that's of little use because all those digits aren't meaningful; they're unreliable in calculations, don't really behave like you would expect numbers to do, etc. They are artifacts of conversion of binary to decimal, essentially. .NET therefore rounds to double's decimal precision automatically for display purposes. It doesn't deceive you into thinking that the number is more precise than it actually is.
Mind you, there are instances when you want those digits to be displayed (e.g. when demonstrating to someone that there's really 50 digits following), but that's not possible in .NET.
Upvotes: 0
Reputation: 172558
Double is defined with 15-16 digit precision.
Try Decimal instead.
The decimal keyword indicates a 128-bit data type. Compared to floating-point types, the decimal type has more precision and a smaller range, which makes it appropriate for financial and monetary calculations. The approximate range and precision for the decimal type are shown in the following table.
Upvotes: 2