vb.net what is a good way of displaying a decimal with a given maximum length - vb.net

I am writing a custom totaling method for a grid view. I am totaling fairly large numbers so I'd like to use a decimal to get the total. The problem is I need to control the maximum length of the total number. To solve this problem I started using float but it doesn't seem to support large enough numbers, I get this in the totals column(1.551538E+07). So is there some formating string I can use in .ToString() to guarentee that I never get more then X characters in the total field? Keep in mind I'm totaling integers and decimals.

If you're fine with all numbers displaying in scientific notation, you could go with "E[numberOfDecimalPlaces]" as your format string.
For example, if you want to cap your strings at, say, 12 characters, then, accounting for the one character for the decimal point and five characters needed to display the exponential part, you could do:
Function FormatDecimal(ByVal value As Decimal) As String
If value >= 0D Then
Return value.ToString("E5")
Else
' negative sign eats up another character '
Return value.ToString("E4")
End If
End Function
Here's a simple demo of this function:
Dim d(5) As Decimal
d(0) = 1.203D
d(1) = 0D
d(2) = 1231234789.432412341239873D
d(3) = 33.3218403820498320498320498234D
d(4) = -0.314453908342094D
d(5) = 000032131231285432940D
For Each value As Decimal in d
Console.WriteLine(FormatDecimal(value))
Next
Output:
1.20300E+000
0.00000E+000
1.23123E+009
3.33218E+001
-3.1445E-001
3.21312E+016

You could use Decimal.Round, but I don't understand the exact question, it sounds like you're saying that if the total adds up to 12345.67, you might only want to show 4 digits and would then show 2345 or do you just mean that you want to remove the decimals?

Related

Formatting a double variable using String Format to add up to 3 zero from the right

I got a price decimal which sometimes can be either 0.00002001 or 0.00002.
I want to display always 3 zeros from the right if the number is like 0.00002 so I'm looking it to be 0.00002000. If the number is 0.00002001 do not add anything.
I came accross some examples and other examplesin msdn and tried with
price.ToString.Format("{0:F4}", price)
but It doesn't actually change anything in the number.
And in the case number is like 123456789 I want it to display 123.456.789 which I've half solved using ToString("N2") but it's displaying also a .00 decimals which I don't want.
Some special cases here between the fractional and whole numbers, so they need to be handled differently.
Private Function formatWithTrailingZeros(number As Double) As String
If number Mod 1 > 0 Then ' has a fractional component
Return $"{number:0.00000000}"
Else
Dim formattedString = $"{number:N2}"
Return formattedString.Substring(0, formattedString.Length - 3)
End If
End Function
Dim price = 0.00002001
Console.WriteLine(formatWithTrailingZeros(price))
price = 0.00002
Console.WriteLine(formatWithTrailingZeros(price))
price = 123456789
Console.WriteLine(formatWithTrailingZeros(price))
price = 123456789.012345
Console.WriteLine(formatWithTrailingZeros(price))
0.00002001
0.00002000
123,456,789
123456789.01234500
If your second case with 123.456.789 is not based on your current culture, then you may need to replace , with . such as
Return formattedString.Substring(0, formattedString.Length - 3).Replace(",", ".")
Since you are using . both as a decimal separator and a thousands separator, I'm not sure how my example of 123456789.012345000 should look, but since you didn't ask, I'm not going to guess.

SQL | How to always round up regardless of the last integer value, even when that may be 0

I am currently outputting values out to 6 decimal places, and would like to round up the 6th place regardless of the integer value.
I have been using a CEILING() function so far which has worked great for values 1-9 on rounding up; however, in situations where I have the 7th decimal as 0 (ex: 2705.1520270), the function does not round up to 2705.152028.
select CEILING(price*1000000)/1000000 as PriceRound
from tc_alcf a (nolock)
Here is one approach:
SELECT ROUND(2705.1520270 + 0.0000005, 6);
2705.1520280
Demo
We can add 0.0000005 to the input and then just use SQL Server's ROUND function to 6 decimal places. This works because values with a sixth decimal place between 0 and 0.4999 (repeating) would become 5 to 0.9999 (repeating), meaning they would round up to the next digit. And values with already have 5 or greater in the sixth decimal place would not be bumped up to the next digit.
This problem should be familiar to many developers as the rounding half up problem.
Add 1 and use FLOOR():
select floor(price*1000000 + 1)/1000000 as PriceRound
from tc_alcf a
Or you can also shift the decimal by multiplying with the power function
CEILING(2705.1520275 * POWER(10,6)) / POWER(10,6)

FormatNumber replacing number with 0

Not understanding this:
Number returned from DataReader: 185549633.66000035
We have a requirement to maintain the number of decimal places per a User Choice.
For example: maintain 7 places.
We are using:
FormatNumber(dr.Item("Field"), 7, TriState.false, , TriState.True)
The result is: 185,549,633.6600000.
We would like to maintain the 3 (or 35) at the end.
When subtracting two numbers from the resulting query we are getting a delta but trying to show these two numbers out to 6,7,8 digits is not working thus indicating a false delta to the user.
Any advice would be appreciated.
Based on my testing, you must be working with Double values rather than Decimal. Not surprisingly, the solution to your problem can be found in the documentation.
For a start, you should not be using FormatNumber. We're not in VB6 anymore ToTo. To format a number in VB.NET, call ToString on that number. I tested this:
Dim dbl = 185549633.66000035R
Dim dec = 185549633.66000035D
Dim dblString = dbl.ToString("n7")
Dim decString = dec.ToString("n7")
Console.WriteLine(dblString)
Console.WriteLine(decString)
and I saw the behaviour you describe, i.e. the output was:
185,549,633.6600000
185,549,633.6600004
I read the documentation for the Double.ToString method (note that FormatNumber would be calling ToString internally) and this is what it says:
By default, the return value only contains 15 digits of precision although a maximum of 17 digits is maintained internally. If the value of this instance has greater than 15 digits, ToString returns PositiveInfinitySymbol or NegativeInfinitySymbol instead of the expected number. If you require more precision, specify format with the "G17" format specification, which always returns 17 digits of precision, or "R", which returns 15 digits if the number can be represented with that precision or 17 digits if the number can only be represented with maximum precision.
I then tested this:
Dim dbl = 185549633.66000035R
Dim dblString16 = dbl.ToString("G16")
Dim dblString17 = dbl.ToString("G17")
Console.WriteLine(dblString16)
Console.WriteLine(dblString17)
and the result was:
185549633.6600004
185549633.66000035

How to format integer as string with 2 digits?

I would like to format an integer 9 to "09" and 25 to "25".
How can this be done?
You can use either of these options:
The "0" Custom Specifier
value.ToString("00")
String.Format("{0:00}", value)
The Decimal ("D") Standard Format Specifier
value.ToString("D2")
String.Format("{0:D2}", value)
For more information:
Custom Numeric Format Strings
Standard Numeric Format Strings
If its just leading zero's that you want, you can use this:
value.tostring.padleft("0",2)
value.ToString().PadLeft(2, '0'); // C#
If you have 2 digits, say 25 for example, you will get "25" back....if you have just one digit, say 9 for example, you will get "09"....It is worth noting that this gives you a string back, and not an integer, so you may need to cast this later on in your code.
String formate is the best way to do that. It's will only add leading zero for a single length. 9 to "09" and 25 to "25".
String.format("%02d", value)
Bonus:
If you want to add multiple leading zero 9 to "0009" and 1000 to "1000". That's means you want a string for 4 indexes so the condition will be %04d.
String.format("%04d", value)
I don't know the exact syntax. But in any language, it would look like this.
a = 9
aString =""
if a < 10 then
aString="0" + a
else
aString = "" + a
end if

SQL - Create Unique AlphaNumeric based on a 10-digit integer stored as VARCHAR

I'm trying to emulate a function in SQL that a client has produced in Excel. In effect, they have a unique, 10-digit numeric value (VARCHAR) as the primary key in one of their enterprise database systems. Within another database, they require a unique, 5-digit alphanumeric identifier. They want that 5-digit alphanumeric value to be a representation of the 10-digit number. So what they did in excel was to split the 10-digit number into pairs, then convert each of those pairs into a hexadecimal value, then stitch them back together.
The EXCEL equation is:
=IF(VALUE(MID(A2,1,4))>0,DEC2HEX(VALUE(MID(A2,3,2)))&DEC2HEX(VALUE(MID(A2,5,2)))&DEC2HEX(VALUE(MID(A2,7,2)))&DEC2HEX(VALUE(MID(A2,9,2))),DEC2HEX(VALUE(MID(A2,5,2)))&DEC2HEX(VALUE(MID(A2,7,2)))&DEC2HEX((VALUE(MID(A2,9,2)))))
I need the SQL equivalent of this. Of course, should someone out there know a better way to accomplish their goal of "a 5-digit alphanumeric identifier" based off the 10-digit number, I'm all ears.
ADDED 8/2/2011
First of all, thank you to everyone for the replies. Nice to see folks willing to help and even enjoying it! Based on all the responses, I'm apt to tell my client they're intent is sound, only their method is off kilter. I'd also like to recommend a solution. So the challenge remains, just modified slightly:
CHALLENGE: Within SQL, take a 10 digit, unique NUMERIC string and represent it ALPHANUMERICALLY in as few characters as possible. The resulting string must also be unique.
Note that the first 3-4 characters in the 10-digit string are likely to be zeros, and that they could be stripped to shorten the resulting alphanumeric string. Not required, but perhaps helpful.
This problem is inherently impossible. You have a 10 digit numeric value that you want to convert to a 5 digit alphanumeric value. Since there are 10 numeric characters, this means that there are 10^10 = 10 000 000 000 unique values for your 10 digit number. Since there are 36 alphanumeric characters (26 letters + 10 numbers), there are 36^5 = 60 466 176 unique values for your 5 digit number. You cannot map a set of 10 billion elements into a set with around 60 million.
Now, lets take a closer look at what your client's code is doing:
So what they did in excel was to split the 10-digit number into pairs, then convert each of those pairs into a hexadecimal value, then stitch them back together.
This isn't 100% accurate. The excel code never uses the first 2 digits, but performs this operation on the remaining 8. There are two main problems with this algorithm which may not be intuitively obvious:
Two 10 digit numbers can map to the same 5 digit number. Consider the numbers 1000000117 and 1000001701. The last four digits of 1000000117 get mapped to 1 11, where the last four digits of 1000001701 get mapped to 11 1. This causes both to map to 00111.
The 5 digit number may not even end up being 5 digits! For example, 1000001616 gets mapped to 001010.
So, what is a possible solution? Well, if you don't care if that 5 digit number is unique or not, in MySQL you can use something like:
hex(<NUMERIC VALUE> % 0xFFFFF)
The log of 10^10 base 2 is 33.219280948874
> return math.log(10 ^ 10) / math.log(2)
33.219280948874
> = 2 ^ 33.21928
9999993422.9114
So, it takes 34 bits to represent this number. In hex this will take 34/4 = 8.5 characters, much more than 5.
> return math.log(10 ^ 10) / math.log(16)
8.3048202372184
The Excel macro is ignoring the first 4 (or 6) characters of the 10 character string.
You could try encoding in base 36 instead of 16. This will get you to 7 characters or less.
> return math.log(10 ^ 10) / math.log(36)
6.4254860446923
The popular base 64 encoding will get you to 6 characters
> return math.log(10 ^ 10) / math.log(64)
5.5365468248123
Even Ascii85 encoding won't get you down to 5.
> return math.log(10 ^ 10) / math.log(85)
5.1829075929158
You need base 100 to get to 5 characters
> return math.log(10 ^ 10) / math.log(100)
5
There aren't 100 printable ASCII characters, so this is not going to work, as zkhr explained as well, unless you're willing to go beyond ASCII.
I found your question interesting (although I don't claim to know the answer) - I googled a bit for you out of interest and found this which may help you http://dpatrickcaldwell.blogspot.com/2009/05/converting-decimal-to-hexadecimal-with.html