I have an input type integer that represents a number that needs to be converted to double between 1-100, and the rest is decimal precision.
Example: 1562 -> 15.62 ; 198912 -> 19.8912
Right now, I tried a conversion to string, count the number of characters, take 2 to check how many decimals I have and depending of the result "create" a composite string to get a valid double...
Any idea of there is a better way of resolving convert-precision on runtime.
What about this:
int value = 1562;
decimal d = value;
while (d > 100) {
d /= 10;
}
You can use LINQ Skip and Take like:
string str = "198912";
string newStr = string.Format("{0}.{1}", new string(str.Take(2).ToArray()), new string(str.Skip(2).ToArray()));
double d = double.Parse(newStr, CultureInfo.InvariantCulture);
You can add the checks for length on original string, and also use double.TryParse to see if you get valid values.
If you have an int to begin with then you can use decimal, which would provide you more accurate conversion. Like:
int number = 1562123123;
decimal decimalNumber = number;
while (decimalNumber > 100)
{
decimalNumber /= 10;
}
Here is a mathematical solution. The line lg = Math.Max(lg, 0); changes "2" to return "2.0" instead of "20.0" but I guess that depends on your needs for single digit numbers.
static double ToDoubleBetween1And100(int num)
{
var lg = Math.Floor(Math.Log10(num)) - 1;
lg = Math.Max(lg, 0);
return ((double)num) / Math.Pow(10, lg);
}
Related
Is it possible in C# to format a double value with double.ToString in a way that I have always a fixed number of digits, no matter on which side of the decimal point?
Say I wish 6 digits, I want to have these results:
0.00123456789 gives "0.00123"
1.23456789 gives "1.23457"
123.456789 gives "123.457"
0.0000000123456789 gives "0.00000"
12345678.9 gives "12345679" (on overflow I want to see all digits left of decimalpoint)
4.2 gives "4.20000"
I'm experimenting with double.ToString, but cannot find any suitable format string.
Already tried "G6" (gives sometimes exponential format), "F6" (comes close, but 0.123456789 gives "0.123457" which are 7 digits).
I think some of your examples are wrong.
But I still think that I understand what you want to achieve.
I made an extension method.
public static class StringExtensionMethods
{
public static string ToString(this double d, int numberOfDigits)
{
var result = "";
// Split the number.
// Delimiter can vary depending on locale, should consider this and not use "."
string[] split = d.ToString().Split(new string[] { "." }, StringSplitOptions.None);
if(split[0].Count() >= numberOfDigits)
{
result = split[0].Substring(0, numberOfDigits);
}
else
{
result = split[0];
result += ".";
result += split[1];
// Add padding.
while(result.Count() < numberOfDigits +1)
result += "0";
result = result.Substring(0, numberOfDigits + 1);
}
return result;
}
}
I ran it with your examples:
double d0 = 0.00123456789;
double d1 = 1.23456789;
double d2 = 123.456789;
double d3 = 0.0000000123456789;
double d4 = 12345678.9;
double d5 = 4.2;
Console.WriteLine(d0.ToString(6));
Console.WriteLine(d1.ToString(6));
Console.WriteLine(d2.ToString(6));
Console.WriteLine(d3.ToString(6));
Console.WriteLine(d4.ToString(6));
Console.WriteLine(d5.ToString(6));
This is the output:
0.00123
1.23456
123.456
1.23456
123456
4.20000
I don't think this is the best way to solve it, but I like extension methods.
DoubleConverter class: http://1drv.ms/1yEbvL4
If your goal is to avoid "jumping" of the decimal point:
Use g formating, this does the most sensible thing to do
See where the decimal point is in your resulting string
pad with spaces at the beginning to align the column at the decimal point
As I understand, there is no predefined format that does what I need. So for everyone who is interested, here is the function I ended up with:
public string FormatValue(double d, int noOfDigits)
{
double abs = Math.Abs(d);
int left = abs < 1 ? 1 : (int)(Math.Log10(abs) + 1);
int usedDigits = 0;
StringBuilder sb = new StringBuilder();
for(; usedDigits < left; usedDigits++)
{
sb.Append("0");
}
if(usedDigits < noOfDigits)
{
sb.Append(".");
for(; usedDigits < noOfDigits; usedDigits++)
{
sb.Append("0");
}
}
return d.ToString(sb.ToString());
}
I need to truncate a number to 2 decimal places, which basically means
chopping off the extra digits.
Eg:
2.919 -> 2.91
2.91111 -> 2.91
Why? This is what SQL server is doing when storing a number of a
particular precision. Eg, if a column is Decimal(8,2), and you try to
insert/update a number of 9.1234, the 3 and 4 will be chopped off.
I need to do exactly the same thing in c# code.
The only possible ways that I can think of doing it are either:
Using the stringformatter to "print" it out only
two decimal places, and then converting it to a decimal,
eg:
decimal tooManyDigits = 2.1345
decimal ShorterDigits = Convert.ToDecimal(tooManyDigits.ToString("0.##"));
// ShorterDigits is now 2.13
I'm not happy with this because it involves a to-string and then
another string to decimal conversion which seems a bit mad.
Using Math.Truncate (which only accepts an integer), so I
can multiply it by 100, truncate it, then divide by 100. eg:
decimal tooLongDecimal = 2.1235;
tooLongDecimal = Math.Truncate(tooLongDecimal * 100) / 100;
I'm also not happy with this because if tooLongDecimal is 0,
I'll get a divide by 0 error.
Surely there's a better + easier way! Any suggestions?
You've answered the question yourself; it seems you just misunderstood what division by zero means. The correct way to do this is to multiply, truncate, then devide, like this:
decimal TruncateTo100ths(decimal d)
{
return Math.Truncate(d* 100) / 100;
}
TruncateTo100ths(0m); // 0
TruncateTo100ths(2.919m); // 2.91
TruncateTo100ths(2.91111m); // 2.91
TruncateTo100ths(2.1345m); // 2.13
There is no division by zero here, there is only division by 100, which is perfectly safe.
The previously offered mathematical solutions are vulnerable to overflow with large numbers and/or a large number of decimal places. Consider instead the following extension method:
public static decimal TruncateDecimal(this decimal d, int decimals)
{
if (decimals < 0)
throw new ArgumentOutOfRangeException("decimals", "Value must be in range 0-28.");
else if (decimals > 28)
throw new ArgumentOutOfRangeException("decimals", "Value must be in range 0-28.");
else if (decimals == 0)
return Math.Truncate(d);
else
{
decimal integerPart = Math.Truncate(d);
decimal scalingFactor = d - integerPart;
decimal multiplier = (decimal) Math.Pow(10, decimals);
scalingFactor = Math.Truncate(scalingFactor * multiplier) / multiplier;
return integerPart + scalingFactor;
}
}
Usage:
decimal value = 18446744073709551615.262626263m;
value = value.TruncateDecimal(6); // Result: 18446744073709551615.262626
I agree with p.s.w.g. I had the similar requirement and here is my experience and a more generalized function for truncating.
http://snathani.blogspot.com/2014/05/truncating-number-to-specificnumber-of.html
public static decimal Truncate(decimal value, int decimals)
{
decimal factor = (decimal)Math.Pow(10, decimals);
decimal result = Math.Truncate(factor * value) / factor;
return result;
}
Using decimal.ToString('0.##') also imposes rounding:
1.119M.ToString("0.##") // -> 1.12
(Yeah, likely should be a comment, but it's hard to format well as such.)
public static decimal Rounding(decimal val, int precision)
{
decimal res = Trancating(val, precision + 1);
return Math.Round(res, precision, MidpointRounding.AwayFromZero);
}
public static decimal Trancating(decimal val,int precision)
{
if (val.ToString().Contains("."))
{
string valstr = val.ToString();
string[] valArr = valstr.Split('.');
if(valArr[1].Length < precision)
{
int NoOfZeroNeedToAdd = precision - valArr[1].Length;
for (int i = 1; i <= NoOfZeroNeedToAdd; i++)
{
valstr = string.Concat(valstr, "0");
}
}
if(valArr[1].Length > precision)
{
valstr = valArr[0] +"."+ valArr[1].Substring(0, precision);
}
return Convert.ToDecimal(valstr);
}
else
{
string valstr=val.ToString();
for(int i = 0; i <= precision; i++)
{
if (i == 1)
valstr = string.Concat(valstr, ".0");
if(i>1)
valstr = string.Concat(valstr, "0");
}
return Convert.ToDecimal(valstr);
}
}
How can i print the numbers of a float/double variable after the decimal point?
For example for 435.5644 it will output 5644.
try with
fraction = value - (long) value;
or :
fraction = value - Math.Floor(value);
You can try the following:
double d = 435.5644;
int n = (int)d;
var v = d - n;
string s = string.Format("{0:#.0000}", v);
var result = s.Substring(1);
result: 5644
EDIT: reference to another question (http://stackoverflow.com/questions/4512306/get-decimal-part-of-a-number-in-javascript)
You can do the following:
double d = 435.5644;
float f = 435.5644f;
Console.WriteLine(Math.Round(d % 1, 4) * 10000);
Console.WriteLine(Math.Round(f % 1, 4) * 10000);
That will give you the integer part you looking for.
Best is to do it as Aghilas Yakoub answered, however, here below another option using string handling. Assuming all amounts will have decimals and that decimal separator is a dot (.) you just need to get the index 1.
double d = 435.5644;
Console.WriteLine(d.ToString().Split('.')[1]);
float f = 435.5644f;
Console.WriteLine(f.ToString().Split('.')[1]);
Otherwise you may get a Unhandled Exception: System.IndexOutOfRangeException.
How can I display the number with just the 2 not=zero decimals?
Example:
For 0.00045578 I want 0.00045 and for 1.0000533535 I want 1.000053
There is no built in formatting for that.
You can get the fraction part of the number and count how many zeroes there are until you get two digits, and put together the format from that. Example:
double number = 1.0000533535;
double i = Math.Floor(number);
double f = number % 1.0;
int cnt = -2;
while (f < 10) {
f *= 10;
cnt++;
}
Console.WriteLine("{0}.{1}{2:00}", i, new String('0', cnt), f);
Output:
1.000053
Note: The given code only works if there actually is a fractional part of the number, and not for negative numbers. You need to add checks for that if you need to support those cases.
My solution would be to convert the number to a string. Search for the ".", then count zeroes till you find a non-zero digit, then take two digits.
It's not an elegant solution, but I think it will give you consistent results.
Try this function, using parsing to find the # of fractional digits rather than looking for zeros (it works for negative #s as well):
private static string GetTwoFractionalDigitString(double input)
{
// Parse exponential-notation string to find exponent (e.g. 1.2E-004)
double absValue = Math.Abs(input);
double fraction = (absValue - Math.Floor(absValue));
string s1 = fraction.ToString("E1");
// parse exponent peice (starting at 6th character)
int exponent = int.Parse(s1.Substring(5)) + 1;
string s = input.ToString("F" + exponent.ToString());
return s;
}
You can use this trick:
int d, whole;
double number = 0.00045578;
string format;
whole = (int)number;
d = 1;
format = "0.0";
while (Math.Floor(number * Math.Pow(10, d)) / Math.Pow(10, d) == whole)
{
d++;
format += "0";
}
format += "0";
Console.WriteLine(number.ToString(format));
How could i convert data from string to long in C#?
I have data
String strValue[i] ="1100.25";
now i want it in
long l1;
If you want to get the integer part of that number you must first convert it to a floating number then cast to long.
long l1 = (long)Convert.ToDouble("1100.25");
You can use Math class to round up the number as you like, or just truncate...
Math.Round
Math.Ceil
You can also use long.TryParse and long.Parse.
long l1;
l1 = long.Parse("1100.25");
//or
long.TryParse("1100.25", out l1);
http://msdn.microsoft.com/en-us/library/system.convert.aspx
l1 = Convert.ToInt64(strValue)
Though the example you gave isn't an integer, so I'm not sure why you want it as a long.
long l1 = Convert.ToInt64(strValue);
That should do it.
You won't be able to convert it directly to long because of the decimal point i think you should convert it into decimal and then convert it into long something like this:
String strValue[i] = "1100.25";
long l1 = Convert.ToInt64(Convert.ToDecimal(strValue));
hope this helps!
long is internally represented as System.Int64 which is a 64-bit signed integer.
The value you have taken "1100.25" is actually decimal and not integer hence it can not be converted to long.
You can use:
String strValue = "1100.25";
decimal lValue = Convert.ToDecimal(strValue);
to convert it to decimal value
You can also do using Int64.TryParse Method. It will return '0' if their is any string value but did not generate an error.
Int64 l1;
Int64.TryParse(strValue, out l1);
You can create your own conversion function:
static long ToLong(string lNumber)
{
if (string.IsNullOrEmpty(lNumber))
throw new Exception("Not a number!");
char[] chars = lNumber.ToCharArray();
long result = 0;
bool isNegative = lNumber[0] == '-';
if (isNegative && lNumber.Length == 1)
throw new Exception("- Is not a number!");
for (int i = (isNegative ? 1:0); i < lNumber.Length; i++)
{
if (!Char.IsDigit(chars[i]))
{
if (chars[i] == '.' && i < lNumber.Length - 1 && Char.IsDigit(chars[i+1]))
{
var firstDigit = chars[i + 1] - 48;
return (isNegative ? -1L:1L) * (result + ((firstDigit < 5) ? 0L : 1L));
}
throw new InvalidCastException($" {lNumber} is not a valid number!");
}
result = result * 10 + ((long)chars[i] - 48L);
}
return (isNegative ? -1L:1L) * result;
}
It can be improved further:
performance wise
make the validation stricter in the sense that it currently doesn't care if characters after first decimal aren't digits
specify rounding behavior as parameter for conversion function. it currently does rounding