Remove trailing zeros - c#

I have some fields returned by a collection as
2.4200
2.0044
2.0000
I want results like
2.42
2.0044
2
I tried with String.Format, but it returns 2.0000 and setting it to N0 rounds the other values as well.

I ran into the same problem but in a case where I do not have control of the output to string, which was taken care of by a library. After looking into details in the implementation of the Decimal type (see http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx),
I came up with a neat trick (here as an extension method):
public static decimal Normalize(this decimal value)
{
return value/1.000000000000000000000000000000000m;
}
The exponent part of the decimal is reduced to just what is needed. Calling ToString() on the output decimal will write the number without any trailing 0. E.g.
1.200m.Normalize().ToString();

Is it not as simple as this, if the input IS a string? You can use one of these:
string.Format("{0:G29}", decimal.Parse("2.0044"))
decimal.Parse("2.0044").ToString("G29")
2.0m.ToString("G29")
This should work for all input.
Update Check out the Standard Numeric Formats I've had to explicitly set the precision specifier to 29 as the docs clearly state:
However, if the number is a Decimal and the precision specifier is omitted, fixed-point notation is always used and trailing zeros are preserved
Update Konrad pointed out in the comments:
Watch out for values like 0.000001. G29 format will present them in the shortest possible way so it will switch to the exponential notation. string.Format("{0:G29}", decimal.Parse("0.00000001",System.Globalization.CultureInfo.GetCultureInfo("en-US"))) will give "1E-08" as the result.

In my opinion its safer to use Custom Numeric Format Strings.
decimal d = 0.00000000000010000000000m;
string custom = d.ToString("0.#########################");
// gives: 0,0000000000001
string general = d.ToString("G29");
// gives: 1E-13

I use this code to avoid "G29" scientific notation:
public static string DecimalToString(this decimal dec)
{
string strdec = dec.ToString(CultureInfo.InvariantCulture);
return strdec.Contains(".") ? strdec.TrimEnd('0').TrimEnd('.') : strdec;
}
EDIT: using system CultureInfo.NumberFormat.NumberDecimalSeparator :
public static string DecimalToString(this decimal dec)
{
string sep = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
string strdec = dec.ToString(CultureInfo.CurrentCulture);
return strdec.Contains(sep) ? strdec.TrimEnd('0').TrimEnd(sep.ToCharArray()) : strdec;
}

Use the hash (#) symbol to only display trailing 0's when necessary. See the tests below.
decimal num1 = 13.1534545765;
decimal num2 = 49.100145;
decimal num3 = 30.000235;
num1.ToString("0.##"); //13.15%
num2.ToString("0.##"); //49.1%
num3.ToString("0.##"); //30%

I found an elegant solution from http://dobrzanski.net/2009/05/14/c-decimaltostring-and-how-to-get-rid-of-trailing-zeros/
Basically
decimal v=2.4200M;
v.ToString("#.######"); // Will return 2.42. The number of # is how many decimal digits you support.

A very low level approach, but I belive this would be the most performant way by only using fast integer calculations (and no slow string parsing and culture sensitive methods):
public static decimal Normalize(this decimal d)
{
int[] bits = decimal.GetBits(d);
int sign = bits[3] & (1 << 31);
int exp = (bits[3] >> 16) & 0x1f;
uint a = (uint)bits[2]; // Top bits
uint b = (uint)bits[1]; // Middle bits
uint c = (uint)bits[0]; // Bottom bits
while (exp > 0 && ((a % 5) * 6 + (b % 5) * 6 + c) % 10 == 0)
{
uint r;
a = DivideBy10((uint)0, a, out r);
b = DivideBy10(r, b, out r);
c = DivideBy10(r, c, out r);
exp--;
}
bits[0] = (int)c;
bits[1] = (int)b;
bits[2] = (int)a;
bits[3] = (exp << 16) | sign;
return new decimal(bits);
}
private static uint DivideBy10(uint highBits, uint lowBits, out uint remainder)
{
ulong total = highBits;
total <<= 32;
total = total | (ulong)lowBits;
remainder = (uint)(total % 10L);
return (uint)(total / 10L);
}

This is simple.
decimal decNumber = Convert.ToDecimal(value);
return decNumber.ToString("0.####");
Tested.
Cheers :)

Depends on what your number represents and how you want to manage the values: is it a currency, do you need rounding or truncation, do you need this rounding only for display?
If for display consider formatting the numbers are x.ToString("")
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx and
http://msdn.microsoft.com/en-us/library/0c899ak8.aspx
If it is just rounding, use Math.Round overload that requires a MidPointRounding overload
http://msdn.microsoft.com/en-us/library/ms131274.aspx)
If you get your value from a database consider casting instead of conversion:
double value = (decimal)myRecord["columnName"];

This will work:
decimal source = 2.4200m;
string output = ((double)source).ToString();
Or if your initial value is string:
string source = "2.4200";
string output = double.Parse(source).ToString();
Pay attention to this comment.

Trying to do more friendly solution of DecimalToString (https://stackoverflow.com/a/34486763/3852139):
private static decimal Trim(this decimal value)
{
var s = value.ToString(CultureInfo.InvariantCulture);
return s.Contains(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator)
? Decimal.Parse(s.TrimEnd('0'), CultureInfo.InvariantCulture)
: value;
}
private static decimal? Trim(this decimal? value)
{
return value.HasValue ? (decimal?) value.Value.Trim() : null;
}
private static void Main(string[] args)
{
Console.WriteLine("=>{0}", 1.0000m.Trim());
Console.WriteLine("=>{0}", 1.000000023000m.Trim());
Console.WriteLine("=>{0}", ((decimal?) 1.000000023000m).Trim());
Console.WriteLine("=>{0}", ((decimal?) null).Trim());
}
Output:
=>1
=>1.000000023
=>1.000000023
=>

how about this:
public static string TrimEnd(this decimal d)
{
string str = d.ToString();
if (str.IndexOf(".") > 0)
{
str = System.Text.RegularExpressions.Regex.Replace(str.Trim(), "0+?$", " ");
str = System.Text.RegularExpressions.Regex.Replace(str.Trim(), "[.]$", " ");
}
return str;
}

You can just set as:
decimal decNumber = 23.45600000m;
Console.WriteLine(decNumber.ToString("0.##"));

The following code could be used to not use the string type:
int decimalResult = 789.500
while (decimalResult>0 && decimalResult % 10 == 0)
{
decimalResult = decimalResult / 10;
}
return decimalResult;
Returns 789.5

In case you want to keep decimal number, try following example:
number = Math.Floor(number * 100000000) / 100000000;

Here is an Extention method I wrote, it also removes dot or comma if it`s the last character (after the zeros were removed):
public static string RemoveZeroTail(this decimal num)
{
var result = num.ToString().TrimEnd(new char[] { '0' });
if (result[result.Length - 1].ToString() == "." || result[result.Length - 1].ToString() == ",")
{
return result.Substring(0, result.Length - 1);
}
else
{
return result;
}
}

To remove trailing zero's from a string variable dateTicks, Use
return new String(dateTicks.Take(dateTicks.LastIndexOf(dateTicks.Last(v => v != '0')) + 1).ToArray());

Additional Answer:
In a WPF Application using XAML you could use
{Binding yourDecimal, StringFormat='#,0.00#######################'}
The above answer will preserve the zero in some situations so you could still return 2.00 for example
{Binding yourDecimal, StringFormat='#,0.#########################'}
If you want to remove ALL trailing zeros, adjust accordingly.

The following code will be able to remove the trailing 0's. I know it's the hard way but it works.
private static string RemoveTrailingZeros(string input)
{
for (int i = input.Length - 1; i > 0; i-- )
{
if (!input.Contains(".")) break;
if (input[i].Equals('0'))
{
input= input.Remove(i);
}
else break;
}
return input;
}

string.Format("{0:G29}", decimal.Parse("2.00"))
string.Format("{0:G29}", decimal.Parse(Your_Variable))

try this code:
string value = "100";
value = value.Contains(".") ? value.TrimStart('0').TrimEnd('0').TrimEnd('.') : value.TrimStart('0');

Very simple answer is to use TrimEnd(). Here is the result,
double value = 1.00;
string output = value.ToString().TrimEnd('0');
Output is 1
If my value is 1.01 then my output will be 1.01

try like this
string s = "2.4200";
s = s.TrimStart("0").TrimEnd("0", ".");
and then convert that to float

Related

How do I convert a double to a string of 15 digits?

I have the number 123.1234567890129.
I want the result to be 123.123456789012 without the last digit being rounded.
I've tried:
("123.1234567890129").ToString("G15") //123.123456789013
One way that you could do this is to round to 16 like this
("123.1234567890129").ToString("G16").Substring(0, 16);
Since you said double.
Since doubles can have ANY number of digits you must round in some way. (you either round down, as inferred or you round up as in practice for this case)
Since you imply you only want to see the number of precise digits, you must find out how many digits are on each side of the decimal point (0 to 15 on either side)
An extenstion to round down
public static class DoubleExtensions
{
public static double RoundDown(this double value, int numDigits)
{
double factoral = Math.Pow(10, numDigits);
return Math.Truncate(value * factoral) / factoral;
}
}
test case
const int totalDigits = 15;
// why start with a string??
string somestring = "123.1234567890129";
const int totalDigits = 15;
// since the title says 'convert a double to a string' lets make it a double eh?
double d = double.Parse(somestring);
int value = (int)d;
double digitsRight = d - value;
int numLeft = (d - digitsRight).ToString().Count();
int numRight = totalDigits - numLeft;
double truncated = d.RoundDown(numRight);
string s = truncated.ToString("g15");
You can create custom FormatProvider and then create your implementation.
class Program
{
static void Main(string[] args)
{
double number = 123.1234567890129;
var result = string.Format(new CustomFormatProvider(15), "{0}", number);
}
}
public class CustomFormatProvider : IFormatProvider, ICustomFormatter
{
private readonly int _numberOfDigits;
public CustomFormatProvider(int numberOfDigits)
{
_numberOfDigits = numberOfDigits;
}
public object GetFormat(Type formatType) => formatType == typeof(ICustomFormatter) ? this : null;
public string Format(string format, object arg, IFormatProvider formatProvider)
{
if (!Equals(formatProvider))
return null;
if (!(arg is double))
{
return null;
}
var input = ((double)arg).ToString("R");
return input.Length > _numberOfDigits + 1 ? input.Substring(0, _numberOfDigits + 1) : input; // +1 because of dot
}
Unfortunately you cannot do in this way:
var result = number.ToString(new CustomFormatProvider(15));
because of value types limitation.. Double supports only CultureInfo and NumberFormatInfo formatters. If you pass different formatter it will return default instance: NumberFormatInfo.CurrentInfo'. You can make small workaround by usingstring.Format` method.
New to the community. First answer here. :)
I think you are looking for something like this. Works with or without decimal. This will cut the digits after the 15th digit only irrespective of length of the number. You can get the user to decide the accuracy by getting the precision value as a user input and performing that condition check accordingly. I used 15 because you mentioned it. Let me know if it works for you. Cheers!
string newstr;
int strlength,substrval;
double number;
string strnum = "123.1234567890129";
strlength = strnum.Length;
if(strlength>15)
{
strlength = 15;
}
substrval = strlength;
foreach(char x in strnum)
{
if(x=='.')
{
substrval++;
}
}
newstr = strnum.Substring(0, substrval);
number=Convert.ToDouble(newstr);
Alife Goodacre, code is printing "123.12345678901" insted "123.123456789012"
there should be Substring(0, 16) insted of Substring(0, 15)
Convert.ToDouble("123.1234567890129").ToString("G16").Substring(0, 16)
OutPut Screen with Code.

C# String.format a number with dynamic number of significant digits [duplicate]

I have some fields returned by a collection as
2.4200
2.0044
2.0000
I want results like
2.42
2.0044
2
I tried with String.Format, but it returns 2.0000 and setting it to N0 rounds the other values as well.
I ran into the same problem but in a case where I do not have control of the output to string, which was taken care of by a library. After looking into details in the implementation of the Decimal type (see http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx),
I came up with a neat trick (here as an extension method):
public static decimal Normalize(this decimal value)
{
return value/1.000000000000000000000000000000000m;
}
The exponent part of the decimal is reduced to just what is needed. Calling ToString() on the output decimal will write the number without any trailing 0. E.g.
1.200m.Normalize().ToString();
Is it not as simple as this, if the input IS a string? You can use one of these:
string.Format("{0:G29}", decimal.Parse("2.0044"))
decimal.Parse("2.0044").ToString("G29")
2.0m.ToString("G29")
This should work for all input.
Update Check out the Standard Numeric Formats I've had to explicitly set the precision specifier to 29 as the docs clearly state:
However, if the number is a Decimal and the precision specifier is omitted, fixed-point notation is always used and trailing zeros are preserved
Update Konrad pointed out in the comments:
Watch out for values like 0.000001. G29 format will present them in the shortest possible way so it will switch to the exponential notation. string.Format("{0:G29}", decimal.Parse("0.00000001",System.Globalization.CultureInfo.GetCultureInfo("en-US"))) will give "1E-08" as the result.
In my opinion its safer to use Custom Numeric Format Strings.
decimal d = 0.00000000000010000000000m;
string custom = d.ToString("0.#########################");
// gives: 0,0000000000001
string general = d.ToString("G29");
// gives: 1E-13
I use this code to avoid "G29" scientific notation:
public static string DecimalToString(this decimal dec)
{
string strdec = dec.ToString(CultureInfo.InvariantCulture);
return strdec.Contains(".") ? strdec.TrimEnd('0').TrimEnd('.') : strdec;
}
EDIT: using system CultureInfo.NumberFormat.NumberDecimalSeparator :
public static string DecimalToString(this decimal dec)
{
string sep = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
string strdec = dec.ToString(CultureInfo.CurrentCulture);
return strdec.Contains(sep) ? strdec.TrimEnd('0').TrimEnd(sep.ToCharArray()) : strdec;
}
Use the hash (#) symbol to only display trailing 0's when necessary. See the tests below.
decimal num1 = 13.1534545765;
decimal num2 = 49.100145;
decimal num3 = 30.000235;
num1.ToString("0.##"); //13.15%
num2.ToString("0.##"); //49.1%
num3.ToString("0.##"); //30%
I found an elegant solution from http://dobrzanski.net/2009/05/14/c-decimaltostring-and-how-to-get-rid-of-trailing-zeros/
Basically
decimal v=2.4200M;
v.ToString("#.######"); // Will return 2.42. The number of # is how many decimal digits you support.
A very low level approach, but I belive this would be the most performant way by only using fast integer calculations (and no slow string parsing and culture sensitive methods):
public static decimal Normalize(this decimal d)
{
int[] bits = decimal.GetBits(d);
int sign = bits[3] & (1 << 31);
int exp = (bits[3] >> 16) & 0x1f;
uint a = (uint)bits[2]; // Top bits
uint b = (uint)bits[1]; // Middle bits
uint c = (uint)bits[0]; // Bottom bits
while (exp > 0 && ((a % 5) * 6 + (b % 5) * 6 + c) % 10 == 0)
{
uint r;
a = DivideBy10((uint)0, a, out r);
b = DivideBy10(r, b, out r);
c = DivideBy10(r, c, out r);
exp--;
}
bits[0] = (int)c;
bits[1] = (int)b;
bits[2] = (int)a;
bits[3] = (exp << 16) | sign;
return new decimal(bits);
}
private static uint DivideBy10(uint highBits, uint lowBits, out uint remainder)
{
ulong total = highBits;
total <<= 32;
total = total | (ulong)lowBits;
remainder = (uint)(total % 10L);
return (uint)(total / 10L);
}
This is simple.
decimal decNumber = Convert.ToDecimal(value);
return decNumber.ToString("0.####");
Tested.
Cheers :)
Depends on what your number represents and how you want to manage the values: is it a currency, do you need rounding or truncation, do you need this rounding only for display?
If for display consider formatting the numbers are x.ToString("")
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx and
http://msdn.microsoft.com/en-us/library/0c899ak8.aspx
If it is just rounding, use Math.Round overload that requires a MidPointRounding overload
http://msdn.microsoft.com/en-us/library/ms131274.aspx)
If you get your value from a database consider casting instead of conversion:
double value = (decimal)myRecord["columnName"];
This will work:
decimal source = 2.4200m;
string output = ((double)source).ToString();
Or if your initial value is string:
string source = "2.4200";
string output = double.Parse(source).ToString();
Pay attention to this comment.
Trying to do more friendly solution of DecimalToString (https://stackoverflow.com/a/34486763/3852139):
private static decimal Trim(this decimal value)
{
var s = value.ToString(CultureInfo.InvariantCulture);
return s.Contains(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator)
? Decimal.Parse(s.TrimEnd('0'), CultureInfo.InvariantCulture)
: value;
}
private static decimal? Trim(this decimal? value)
{
return value.HasValue ? (decimal?) value.Value.Trim() : null;
}
private static void Main(string[] args)
{
Console.WriteLine("=>{0}", 1.0000m.Trim());
Console.WriteLine("=>{0}", 1.000000023000m.Trim());
Console.WriteLine("=>{0}", ((decimal?) 1.000000023000m).Trim());
Console.WriteLine("=>{0}", ((decimal?) null).Trim());
}
Output:
=>1
=>1.000000023
=>1.000000023
=>
how about this:
public static string TrimEnd(this decimal d)
{
string str = d.ToString();
if (str.IndexOf(".") > 0)
{
str = System.Text.RegularExpressions.Regex.Replace(str.Trim(), "0+?$", " ");
str = System.Text.RegularExpressions.Regex.Replace(str.Trim(), "[.]$", " ");
}
return str;
}
You can just set as:
decimal decNumber = 23.45600000m;
Console.WriteLine(decNumber.ToString("0.##"));
The following code could be used to not use the string type:
int decimalResult = 789.500
while (decimalResult>0 && decimalResult % 10 == 0)
{
decimalResult = decimalResult / 10;
}
return decimalResult;
Returns 789.5
In case you want to keep decimal number, try following example:
number = Math.Floor(number * 100000000) / 100000000;
Here is an Extention method I wrote, it also removes dot or comma if it`s the last character (after the zeros were removed):
public static string RemoveZeroTail(this decimal num)
{
var result = num.ToString().TrimEnd(new char[] { '0' });
if (result[result.Length - 1].ToString() == "." || result[result.Length - 1].ToString() == ",")
{
return result.Substring(0, result.Length - 1);
}
else
{
return result;
}
}
To remove trailing zero's from a string variable dateTicks, Use
return new String(dateTicks.Take(dateTicks.LastIndexOf(dateTicks.Last(v => v != '0')) + 1).ToArray());
Additional Answer:
In a WPF Application using XAML you could use
{Binding yourDecimal, StringFormat='#,0.00#######################'}
The above answer will preserve the zero in some situations so you could still return 2.00 for example
{Binding yourDecimal, StringFormat='#,0.#########################'}
If you want to remove ALL trailing zeros, adjust accordingly.
The following code will be able to remove the trailing 0's. I know it's the hard way but it works.
private static string RemoveTrailingZeros(string input)
{
for (int i = input.Length - 1; i > 0; i-- )
{
if (!input.Contains(".")) break;
if (input[i].Equals('0'))
{
input= input.Remove(i);
}
else break;
}
return input;
}
string.Format("{0:G29}", decimal.Parse("2.00"))
string.Format("{0:G29}", decimal.Parse(Your_Variable))
try this code:
string value = "100";
value = value.Contains(".") ? value.TrimStart('0').TrimEnd('0').TrimEnd('.') : value.TrimStart('0');
Very simple answer is to use TrimEnd(). Here is the result,
double value = 1.00;
string output = value.ToString().TrimEnd('0');
Output is 1
If my value is 1.01 then my output will be 1.01
try like this
string s = "2.4200";
s = s.TrimStart("0").TrimEnd("0", ".");
and then convert that to float

Format a double value to fit into a maximum string size

I need to format a double value so that it fits within a field of 13 characters. Is there a way to do this with String.Format or am I stuck with character-by-character work?
Edits: (hopefully they will stay this time)
With cases greater than a trillion I am to report an error. It's basically a calculator interface.
My own answer:
private void DisplayValue(double a_value)
{
String displayText = String.Format("{0:0." + "".PadRight(_maxLength, '#') + "}", a_value);
if (displayText.Length > _maxLength)
{
var decimalIndex = displayText.IndexOf('.');
if (decimalIndex >= _maxLength || decimalIndex < 0)
{
Error();
return;
}
var match = Regex.Match(displayText, #"^-?(?<digits>\d*)\.\d*$");
if (!match.Success)
{
Error();
return;
}
var extra = 1;
if (a_value < 0)
extra = 2;
var digitsLength = match.Groups["digits"].Value.Length;
var places = (_maxLength - extra) - digitsLength;
a_value = Math.Round(a_value, places);
displayText = String.Format("{0:0." + "".PadRight(_maxLength, '#') + "}", a_value);
if (displayText.Length > _maxLength)
{
Error();
return;
}
}
DisplayText = displayText;
}
If this is calculator, then you can not use character-by-character method you mention in your question. You must round number to needed decimal places first and only then display it otherwise you could get wrong result. For example, number 1.99999 trimmed to length of 4 would be 1.99, but result 2 would be more correct.
Following code will do what you need:
int maxLength = 3;
double number = 1.96;
string output = null;
int decimalPlaces = maxLength - 2; //because every decimal contains at least "0."
bool isError = true;
while (isError && decimalPlaces >= 0)
{
output = Math.Round(number, decimalPlaces).ToString();
isError = output.Length > maxLength;
decimalPlaces--;
}
if (isError)
{
//handle error
}
else
{
//we got result
Debug.Write(output);
}
You have a lot formatting options using String.Format, just specify format after placeholder like this {0:format}.
Complete example looks like this:
Console.WriteLine("Your account balance is {0:N2}.", value);
Output would be:
Your account balance is 15.34.
All of the options for numeric types are listed here:
http://msdn.microsoft.com/en-us/library/dwhawy9k(v=vs.110).aspx
This seems to work for me (but is hand-rolled):
static string FormatDouble(double d)
{
int maxLen = 13;
double threshold = Math.Pow(10, maxLen);
if (d >= threshold || d <= 0 - (threshold/10))
return "OVERFLOW";
string strDisplay = "" + d;
if (strDisplay.Length > maxLen )
strDisplay = strDisplay.Substring(0, maxLen);
if (strDisplay.EndsWith("."))
strDisplay = strDisplay.Replace(".", "");
return strDisplay;
}
Let me know if it gives you trouble with scientific notation creeping in. I believe the format "{0:R}" should help you avoid that explicitly.
Also, I wasn't sure if you were including +/- sign in digit count or if that was in a separate UI slot.
The theory on rounding here is that, yes, "" + d might round some things, but in general it's going to be many more digits out than are ever displayed so it shouldn't matter. So this method should always truncate.
Here's a solution that does rounding. (I couldn't think of a non-mathematical way to do it):
static string FormatDouble(double d)
{
int maxLen = 13;
int places = (int)Math.Max(Math.Log10(Math.Abs(d)), 0);
places += (d == Math.Abs(d) ? 1 : 2);
if (places > maxLen || places < 1 - maxLen)
return "OVERFLOW";
if (Math.Floor(d) == d) ++places; // no decimal means one extra spot
d = Math.Round(d, Math.Max(maxLen - places - 1, 0));
return string.Format("{0:R}", d);
}
Note: I still think your users might appreciate seeing something closer to what is being stored in the underlying memory than what is often typical of calculators. (I especially hate the ones that can turn 0.99 into 1.01) Either way, you've got at least 3 solutions now so it's up to you.

C# equivalent of BigDecimal.stripTrailingZeros()

In Java you can use BigDecimal.stripTrailingZeros() to remove any extra zeros at the end.
I've read a few questions on here about how to strip trailing zeros from a decimal in C# but none of them seem to offer correct solutions.
This question for example the answer of doing ToString("G") doesn't always work.
Ideally I would like a function that does decimal -> decimal with the new decimal having the least scale possible without losing any info or removing any trailing zeros.
Is there any way to do this easily? Or would it involve fiddling around with decimal.GetBits()?
EDIT: Should also add I have i18n to worry about so doing string manipulation on the result isn't ideal because of differences in decimal separators.
How about Decimal.Parse(d.ToString("0.###########################"))?
Here is what i have come up with (Crazy code but works smoothly)
private decimal Normalize(decimal d)
{
string[] tmp = d.ToString().Split('.');
string val = tmp[0];
string fraction = null;
decimal result;
if(tmp.Length > 1) fraction = tmp[1];
if(fraction != null && Getleast(fraction) > 0)
{
decimal.TryParse(val.ToString() + "." + fraction.TrimEnd('0').ToString(),out result);
}
else
{
return decimal.Parse(val);
}
return result;
}
private decimal Getleast(string str)
{
decimal res;
decimal.TryParse(str.TrimEnd('0'),out res);// It returns 0 even if we pass null or empty string
return res;
}
Here are sample Input:
Console.WriteLine(Normalize(0.00M));
Console.WriteLine(Normalize(0.10M));
Console.WriteLine(Normalize(0001.00M));
Console.WriteLine(Normalize(1000.01M));
Console.WriteLine(Normalize(1.00001230M));
Console.WriteLine(Normalize(0031.200M));
Console.WriteLine(Normalize(0.0004000M));
Console.WriteLine(Normalize(123));
And respective output:
0
0.1
1
1000.01
1.0000123
31.2
0.0004
123
Not the most elegant of solutions but it should do everything you need.
private decimal RemoveTrailingZeros(decimal Dec)
{
string decString = Dec.ToString();
if (decString.Contains("."))
{
string[] decHalves = decString.Split('.');
int placeholder = 0, LoopIndex = 0;
foreach (char chr in decHalves[1])
{
LoopIndex++;
if (chr != '0')
placeholder = LoopIndex;
}
if (placeholder < decHalves[1].Length)
decHalves[1] = decHalves[1].Remove(placeholder);
Dec = decimal.Parse(decHalves[0] + "." + decHalves[1]);
}
return Dec;
}
Fixed version, Thanks Shekhar_Pro!

Convert string to double with 2 digit after decimal separator

All began with these simple lines of code:
string s = "16.9";
double d = Convert.ToDouble(s);
d*=100;
The result should be 1690.0, but it's not. d is equal to 1689.9999999999998.
All I want to do is to round a double to value with 2 digit after decimal separator.
Here is my function.
private double RoundFloat(double Value)
{
float sign = (Value < 0) ? -0.01f : 0.01f;
if (Math.Abs(Value) < 0.00001) Value = 0;
string SVal = Value.ToString();
string DecimalSeparator = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator;
int i = SVal.IndexOf(DecimalSeparator);
if (i > 0)
{
int SRnd;
try
{
// вземи втората цифра след десетичния разделител
SRnd = Convert.ToInt32(SVal.Substring(i + 3, 1));
}
catch
{
SRnd = 0;
}
if (SVal.Length > i + 3)
SVal = SVal.Substring(0, i + 3);
//SVal += "00001";
try
{
double result = (SRnd >= 5) ? Convert.ToDouble(SVal) + sign : Convert.ToDouble(SVal);
//result = Math.Round(result, 2);
return result;
}
catch
{
return 0;
}
}
else
{
return Value;
}
But again the same problem, converting from string to double is not working as I want.
A workaround to this problem is to concatenate "00001" to the string and then use the Math.Round function (commented in the example above).
This double value multiplied to 100 (as integer) is send to a device (cash register) and this values must be correct.
I am using VS2005 + .NET CF 2.0
Is there another more "elegant" solution, I am not happy with this one.
Doubles can't exactly represent 16.9. I suggest you convert it to decimal instead:
string s = "16.9";
decimal m = Decimal.Parse(s) * 100;
double d = (double)m;
You might just want to keep using the decimal instead of the double, since you say you'll be using it for monetary purposes. Remember that decimal is intended to exactly represent decimal numbers that fit in its precision, while double will only exactly represent binary numbers that do.
Math.Round(number, 1)
Edit I got the wrong question - the rounding problems are inherent to a floating point type (float, double). You should use decimal for this.
The best solution for not going be crazy is:
string s = "16.9";
For ,/.
double d = Convert.ToDouble(s.Replace(',','.'),System.Globalization.CultureInfo.InvariantCulture);
For rounding:
Convert.ToDouble((d).ToString("F2"));

Categories

Resources