I'm trying to come up with a global way of converting a string to X number of decimal places and I'm having no luck. I need this to return a decimal with X number of decimals.
Here is what I have so far but I cannot figure out how to get it to know what to divide by easily:
public static decimal ToXDecimalPlaces(this object value, int numberofdecimalplaces, decimal defaultValue = 0)
{
double retval;
if (double.TryParse(value.ToString(), out retval))
{
return (decimal)(retval / 10);
}
return defaultValue;
}
So if I send it:
value = "12345"
value.ToXDecimalPlaces(2)
I'd like to get back:
123.45
etc.
The division of the retval needs to be different pending on the numberofdecimalplaces.
Any suggestions? I would prefer not to have to create a handful of extension methods or is that what I should do?
Should I just create:
To1DecimalPlaces
To2DecimalPlaces
To3DecimalPlaces
etc
For each one I need and move on?
How about using Math.Pow?
Something like
return (decimal)(retval / Math.Pow(10, numberofdecimalplaces));
Related
I know that C# has some options to format decimal numbers with some extended logic in the ToString() method, as e.g.
double d1 = 1.3333;
double d2 = 1.6666;
string d1Str = d1.ToString("#0.00"); // 1.33
string d2Str = d2.ToString("#0.00"); // 1.67
That's great, my number is rounded to the second decimal. But what if I wanted to round to a step of 0.05 instead of 0.01? Is there a way to use the ToString() method in a similar way to round the value not to a given step-size (e.g. 0.05)?
Note: I know I could do something like this:
(Math.Round(1.33333*20)/20).ToString();
but the question is about getting this result using ToString() only.
Is it possible for you to create an extension overload for ToString() for these components?
If so you could write something like:
public static class DoubleStaticExtension
{
public static string ToString(this double value, string format, int decimalToRoundHalfwayAt)
{
int modifier = 2 * (int)Math.Pow(10, decimalToRoundHalfwayAt -1 );
return (Math.Round(value * modifier, MidpointRounding.AwayFromZero) / modifier).ToString(format);
}
}
Calling that with
double d = 9.333333;
string result = d.ToString("#0.00", 2);
Would give a result of 9.35
And
double d = 9.333333;
string result = d.ToString("#0.00", 1);
Would give a result of 9.50
I have read the second line in a text file which contains 2.75 and I am trying to get it to do something if it meets certain criteria. I'm sure I have done this before and has a simple answer but I can't seen to figure it out.
string SecondLine;
using (var reader = new StreamReader(SPFile2))
{
reader.ReadLine();
SecondLine = reader.ReadLine();
}
int NewValue;
NewValue = Convert.ToInt32(SecondLine);
if ((NewValue >= 2) && (NewValue <= 2.99))
{
// Do Something
}
if ((NewValue >= 3) && (NewValue <= 3.99))
{
// Do something else
}
What have I missed out?
You are converting a decimal number to an Int32 that does not hold decimals. This will turn the number in NewValue into 2 as it truncates towards zero. You need to store the variable in a double, float or decimal whichever is best for your requirements.
See the following example that uses a double and Parse:
double newValue = Double.Parse(secondLine);
Note that if you are unsure if the value will be a double you should use Double.TryParse
double newValue;
bool result = Double.TryParse(secondLine, out newValue);
if (!result) //Parse failed
Note that if the parsing fails it may be down to your culture settings i.e. a ',' for the decimal separator not a '.'. However there is an overload for Parse and TryParse that allows you to pass culture information in.
You are trying to parse a string that represents a double into a integer
that will cause a
System.IFormatException
{"Input string was not in a correct
format."}{"Input string was not in a correct format."}
if you know it is a number with decimal part then do:
var newValue = Convert.ToDouble(secondLine);
if you know it is an integer then try:
var newValue = Convert.ToInt32(secondLine);
My question might looks like silly, but i struck with it.
I have a string value "155.300" and i want to convert it to integer.
I tryed but throwing System.FormatException....pls someone help me out.
Since your source data is string you need to Convert it to Double first then just cast it to int or use Convert.ToInt32, but remember Convert.ToInt32 rounds it to nearest integer number, whereas casting takes the int part of the number (truncate)
double d = Convert.ToDouble("155.00");
int a = (int) d;
int b = Convert.ToInt32(d);
Or in a single Line
int b =(int) Convert.ToDouble("155.000");
EDIT
Since you want to use decimal point as thousand separator, I believe in German culture you can try the following.
int b = ((int)Convert.ToDouble("154.500", new CultureInfo("de-DE")));
That will give you 154500
EDIT 2
Or much better is to use int.Parse with NumberStyles.AllowThousands:
int b = int.Parse("154.500", NumberStyles.AllowThousands, new CultureInfo("de-DE"));
First parse it as a decimal or double (probably best to use decimal as you've got decimal data) then either cast or use something like Math.Round, depending on your requirements.
Basically, you need to always consider what data you've got: "155.300" isn't a string representation of an integer, so don't try to parse it as an integer. Parse it as what it is, then convert that to an integer.
Alternatively, you could hack at the string representation first, but personally I find that to be a more brittle approach in many cases.
EDIT: Note that if this is really already an integer, but with a thousands separator, you don't need to use double at all - you can use int.Parse, specifying an appropriate culture and number style:
int parsed = int.Parse(text, NumberStyles.Integer | NumberStyles.AllowThousands,
culture);
Here is a working conversion sample. Take a special look with the edge conditions, the output may be different if using several rounding/casting techniques
class Program
{
public static int MyToInt(string str)
{
double result;
bool success = Double.TryParse(str, out result);
if (!success)
{
throw new ArgumentException(
"Cannot parse a string into a double");
}
return Convert.ToInt32(result); // 156
//return (int)result; // 155 <<
//return (int)Math.Round(result); // 156
}
static void Main(string[] args)
{
string s = "155.500";
int value = MyToInt(s);
}
}
You can try this:
string str = "123.123";
str = str.Remove(str.IndexOf('.'), 1);
int result;
int.TryParse(str, out result);
Edit: Based on your comment, modified to multiply by thousand.
Or you can just try:
string str = "123.123";
double result;
double.TryParse(str, out result);
int final = (int)(result * 1000);
I'm having a problem getting TryParse to work correctly for me. I have a list of values that I am almost assured are valid (as they come from another component in our system) but I would like to make sure there is proper error handling in place.
Here is an example list of my values:
20.00
20.00
-150.00
And here is the method I originally wrote:
private decimal CalculateValue(IEnumerable<XElement> summaryValues)
{
decimal totalValue = 0;
foreach (XElement xElement in summaryValues)
{
decimal successful;
Decimal.TryParse(xElement.Value, out successful);
if (successful > 0)
totalValue += Decimal.Parse(xElement.Value);
}
return totalValue;
}
The variable 'successful' was returning false for -150.00, so I added NumberStyles:
private decimal CalculateValue(IEnumerable<XElement> summaryValues)
{
decimal totalValue = 0;
foreach (XElement xElement in summaryValues)
{
decimal successful;
Decimal.TryParse(xElement.Value, NumberStyles.AllowLeadingSign, null, out successful);
if (successful > 0)
totalValue += Decimal.Parse(xElement.Value, NumberStyles.AllowLeadingSign);
}
return totalValue;
}
However, now that I have the NumberStyles in there, none of the numbers will parse! I feel good about having IFormatProvider set to null as this is all within our system. Does anyone see what I may be doing wrong?
This is not how you are supposed to use TryParse.
TryParse returns a boolean (true/false), so your code above should be:
private decimal CalculateValue(IEnumerable<XElement> summaryValues)
{
decimal totalValue = 0;
foreach (XElement xElement in summaryValues)
{
decimal valueReturned;
bool successful = Decimal.TryParse(xElement.Value, out valueReturned);
if (successful)
totalValue += valueReturned;
}
return totalValue;
}
or more succinctly,
private decimal CalculateValue(IEnumerable<XElement> summaryValues)
{
decimal totalValue = 0;
foreach (XElement xElement in summaryValues)
{
decimal valueReturned;
if (Decimal.TryParse(xElement.Value, out valueReturned))
totalValue += valueReturned;
}
return totalValue;
}
Others are explaining how to do it right, but not really explaining what you're doing wrong.
Where you're using "successful" above isn't the success value, it's the actual number that is being parsed. So if you're parsing "-150.00" of course successful will be negative. The out value of TryParse is the actual parsed value and the boolean indicating whether the process was successful or not is the returned value. Using what you have to help understand would be something like:
string inputValue = "-150.00";
decimal numericValue;
bool isSucessful = Decimal.TryParse(inputValue , out numericValue);
In this case, isSuccessful will be TRUE, numericValue will be -150. When you're using user-provided values instead of the hardcoded one I used above you'll want to check:
if(isSuccessful)
{
// Do something with numericValue since we know it to be a valid decimal
}
else
{
// Inform User, throw exception, etc... as appropriate, Don't use numericValue because we know it's wrong.
}
The other answers have got the right idea with regard to the proper way to use Decimal.TryParse. However, if I were writing the method in question, I'd use LINQ to work with LINQ-to-XML objects:
private decimal CalculateValue(IEnumerable<XElement> summaryValues)
{
return summaryValues
.Sum(el =>
{
decimal value;
if (Decimal.TryParse(el.Value, out value))
return value;
return 0M;
});
}
This version works the exact same way, but it uses the Enumerable.Sum method to calculate the total. All I have to supply is an inline function that extracts decimal values from an XElement.
Came in from Google. Answer for me was the incoming culture was wrong - specifically in an incoming JSON file.
Use
totalValue += decimal.Parse(xElement.Value, NumberStyles.Any, CultureInfo.InvariantCulture);
or
bool successful = decimal.TryParse(xElement.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out value);
your successful is going to be negative for a negative value being parsed. your if (successful > 0) is what's tripping you up.
If they are almost positively going to be valid values, try using Convert.ToDecimal:
decimal val = Convert.ToDecimal(xElement.Value);
Otherwise, change your logic a bit to be more like:
decimal val;
if (Decimal.TryParse(xElement.Value, out val)){
// valid number
}
I would suggest you to tell XElement which node value it should look for as in:
XElement.Element("nodename").Value
Instead of XElement.Value. at least that is what I would do :)
What is the best way to take a string which can be empty or contain "1.2" for example, and convert it to an integer? int.TryParse fails, of course, and I don't want to use float.TryParse and then convert to int.
Solution 1: Convert.ToDouble (culture-dependent)
You may using Convert.ToDouble. But, beware! The below solution will work only when the number separator in the current culture's setting is a period character.
var a = (int)Convert.ToDouble("1.2");
Solution 2: Convert.ToDouble (culture-independent)
It's preferable to use IFormatProvider and convert the number in an independent way from the current culture settings:
var a = (int)Convert.ToDouble("1.2", CultureInfo.InvariantCulture.NumberFormat);
Solution 3: Parse & Split
Another way to accomplish this task is to use Split on parsed string:
var a = int.Parse("1.2".Split('.')[0]);
Or:
var a = int.Parse("1.2".Split('.').First());
Notes
If you want to handle empty and null strings, write a method and add string.IsNullOrEmpty condition.
To get decimal separator for the current culture setting, you can use NumberFormatInfo.NumberDecimalSeparator property.
You should also keep eye on rounding to avoid traps.
Select casting, Parse, TryParse or Convert class wisely. Read more at:
How to: Convert a string to an int (C# Programming Guide)
How to: Determine Whether a String Represents a Numeric Value (C# Programming Guide)
I don't know what's wrong with parsing to a float and converting to an int. I doubt that any other way would be more efficient but here's an attempt:
//allows empty strings and floating point values
int ParseInt(string s, bool alwaysRoundDown = false)
{
//converts null/empty strings to zero
if (string.IsNullOrEmpty(s)) return 0;
if (!s.Contains(".")) return int.Parse(s);
string parts = s.Split(".");
int i = int.Parse(parts[0]);
if (alwaysRoundDown || parts.Length==1) return i;
int digitAfterPoint = int.Parse(parts[1][0]);
return (digitAfterPoint < 5) ? i : i+1;
}
In order to globalize the code you would need to replace "." with System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator.
int a = (int)Math.Round(float.Parse("0.9"));
You need to round it first unless you want 0.9f being converted to 0 instead of 1.
Maybe you can try to delete everything after floating point using string functions and then convert to int. But seriously I don't think it's better than converting to float and then to int.
I think another way of doing it would be splitting the string into pieces taking the decimal (.) as the delimiter and then parsing for the integer. Of course, I am yet to ask you if the string might contain values like "37.56 miles in 32.65 seconds" type values.
Considering there will be only one value (string or number) in the string, I can think of something in the following line:
public int64 GetInt64(string input)
{
if (string.IsNullOrEmpty(input)) return 0;
// Split string on decimal (.)
// ... This will separate all the digits.
//
string[] words = input.Split('.');
return int.Parse(words[0]);
}
You can use the Visual Basic runtime Library to accomplish this from c#.
You need to add a reference to the assembly Microsoft.VisualBasic.dll to your solution.
Then the following code will do your conversion:
using VB = Microsoft.VisualBasic.CompilerServices;
class Program
{
static void Main(string[] args)
{
int i = VB.Conversions.ToInteger("1.2");
}
}
I had this same problem and ended up using a hybrid of Mark's and Dariusz':
if (num == "")
{
num = "0.00";
}
var num1 = (float)Convert.ToDouble(num);