This is so many times repeated at SO, but I would want to state my question explicitly.
How is a decimal which would look like 2.0100 "rightly" presented to the user as
another "decimal" 2.01?
I see a lot of questions on SO where the input is a string "2.0100" and need a decimal 2.01 out of it and questions where they need decimal 2.0100 to be represented as string "2.01". All this can be achieved by basic string.Trim, decimal.Parse etc. And these are some of the approaches followed:
decimal.Parse(2.0100.ToString("G29"))
Using # literal
Many string.Format options.
Various Regex options
My own one I used till now:
if (2.0100 == 0) return 0; decimal p = decimal.Parse(2.0100.ToString().TrimEnd('0')); return p == 2.0100 ? p : 2.0100;
But I believe there has to be some correct way of doing it in .Net (at least 4) which deals with numeric operation and not string operation. I am asking for something that is not dealing with the decimal as string because I feel that ain't the right method to do this. I'm trying to learn something new. And would fancy my chances of seeing at least .1 seconds of performance gain since I'm pulling tens of thousands of decimal values from database :)
Question 2: If it aint present in .Net, which is the most efficient string method to get a presentable value for the decimal?
Edit: I do not just want a decimal to be presented it to users. In that case I can use it as a string. I do want it as decimal back. I will have to process on those decimal values later. So going by ToString approach, I first needs to convert it to string, and then again parse it to decimal. I am looking for something that doesn't deal with String
class. Some option to convert decimal .20100 to decimal .201?
The easiest way to format a decimal in a given format for the user is to use
decimal.ToString()
's formatting options.As for representing the value, 2.01 is equal to 2.0100. As long as you're within
decimal
's precision, it shouldn't matter how the value is stored in the system. You should only be worried with properly formatting the value for the user.Numbers are numbers and strings are strings. The concept of "two-ness" represented as a string in the English language is
2
. The concept of "two-ness" represented as a number is not really possibly to show because when you observe a number you see it as a string. But for the sake of argument it could be2
or2.0
or02
or02.0
or even10/5
. These are all representations of "two-ness".Your database isn't actually returning
2.0100
, something that you are inspecting that value with is converting it to a string and representing it that way for you. Whether a number has zeros at the end of it is merely a preference of string formatting, always.Also, never call
Decimal.parse()
on a decimal, it doesn't make sense. If you want to convert a decimal literal to a string just call(2.0100).ToString().TrimEnd('0')
The "extra zeroes" that occur in a
decimal
value are there because theSystem.Decimal
type stores those zeroes explicitly. For aSystem.Decimal
,1.23400
is a different value from1.234
, even though numerically they are equal:It's important to have the zeroes because many Decimal computations involve significant digits, which are a necessity of many scientific and high-precision calculations.
In your case, you don't care about them, but the appropriate answer is not "change Decimal for my particular application so that it doesn't store those zeroes". Instead, it's "present this value in a way that's meaningful to my users". And that's what
decimal.ToString()
is for.As noted, a decimal that internally stores
2.0100
could differ from one that stores2.01
, and the default behaviour ofToString()
can be affected.I recommend that you never make use of this.
Firstly,
decimal.Parse("2.0100") == decimal.Parse("2.01")
returnstrue
. While their internal representations are different this is IMO unfortunate. When I'm usingdecimal
with a value of 2.01 I want to be thinking:Not:
struct decimal { private int flags; private int hi; private int lo; private int mid; /methods that make this actually useful/ }
While different means of storing
2.01
in the above structure might exist, 2.01 remains 2.01.If you care about it being presented as
2.01
and not as2.0
or2.0100
then you care about a string representation. Your concern is about how a decimal is represented as a string, and that is how you should think about it at that stage. Consider the rule in question (minimum and maximum significant figures shown, and whether to include or exclude trailing zeros) and then code aToString
call appropriate.And do this close to where the string is used.
When you care about
2.01
, then deal with it as a decimal, and consider any code where the difference between2.01
and2.0100
matters to be a bug, and fix it.Have a clear split in your code between where you are using strings, and where you are using decimals.
Ok, so I'm answering for myself, I got a solution.
That just does it. I did some benchmarking as well (time presented as comments are mode, not mean):
Method:
Candidates:
Needless to cover regex options. I dont mean to say performance makes a lot of difference. I'm just pulling 5k to 20k rows at a time. But still it's nice to know a simpler and cleaner alternative to string approach exists.
If you liked the answer, pls redirect your votes to here or here or here.