I have no problem converting a double to such a string: 7.8746137240E-008
I don't know how to force the first digit to always be zero: 0.7874613724E-007
How to achieve that using a custom string format in C#?
Maybe do it yourself ;)
double foo = 7.8746137240E-008;
var numOfDigits = foo == 0 ? 0 : (int)Math.Ceiling(Math.Log10(Math.Abs(foo)));
string formatString = string.Format("{0:0.000000}E{1:+000;-000;+000}", foo / Math.Pow(10, numOfDigits), numOfDigits);
I found a simple solution:
value.ToString("\\0.0000000000E+000;-\\0.0000000000E+000")
You can do this by formatting with standard exponential notation followed by some post-processing:
public static string FormatNumberExpZero(double value, IFormatProvider format = null) {
if (!double.IsFinite(value)) // Infinity and NaN
return value.ToString(format);
// Format the number to a temporary buffer.
// "E10" means exponential notation with 10 decimal places.
Span<char> buffer = stackalloc char[24];
value.TryFormat(buffer, out int charCount, "E10", format);
// Don't touch any negative sign.
Span<char> bufferNoSign = (buffer[0] == '-') ? buffer.Slice(1) : buffer;
// Move everything after '.' one character forward to make space for the additional zero.
bufferNoSign.Slice(2, charCount - 2).CopyTo(bufferNoSign.Slice(3));
charCount++;
// Change 'X.' to '0.X'
bufferNoSign[2] = bufferNoSign[0];
bufferNoSign[1] = '.';
bufferNoSign[0] = '0';
// Read the exponent from the buffer.
Span<char> expChars = buffer.Slice(charCount - 4, 4);
int exponent = (expChars[1] - '0') * 100 + (expChars[2] - '0') * 10 + expChars[3] - '0';
if (expChars[0] == '-')
exponent = -exponent;
// Add 1 to the exponent to compensate.
exponent++;
// Write the new exponent back.
expChars[0] = (exponent < 0) ? '-' : '+';
int expAbs = (exponent < 0) ? -exponent : exponent;
int expDigit1 = expAbs / 100;
int expDigit2 = (expAbs - expDigit1 * 100) / 10;
int expDigit3 = expAbs - expDigit1 * 100 - expDigit2 * 10;
Console.WriteLine((expDigit1, expDigit2, expDigit3));
expChars[1] = (char)(expDigit1 + '0');
expChars[2] = (char)(expDigit2 + '0');
expChars[3] = (char)(expDigit3 + '0');
// Create the string.
return new string(buffer.Slice(0, charCount));
}
This solution is better than the one by #MarkSouls because it does not suffer from floating-point inaccuracy and/or overflow to infinity of doing value * 10. This requires .NET Standard 2.1 and so doesn't work with .NET Framework, though it can be modified to work with it (at the cost of allocating an additional string and char array).
I know no fancy way of achieving what you want but you can do it by writing your own function.
public static class Extender
{
public static string MyToString(this double value)
{
string s = (value * 10).ToString("E");
s = s.Replace(".", "");
return "0." + s;
}
}
It's just modifying exponential count and moving . front then adding 0.
public static void Main(string[] args)
{
Console.WriteLine(1d.MyToString());
Console.WriteLine(3.14159.MyToString());
Console.WriteLine(0.0033.MyToString());
Console.WriteLine(999414128.0.MyToString());
}
/* Output
0.1000000E+001
0.3141590E+001
0.3300000E-002
0.9994141E+009
*/
Not super cool code but it works, though I didn't check edge cases.
I wonder if there's more formal way to do it.
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);
}
I have a variable of decimal type and I want to check the number of digits before decimal point in it.
What should I do? For example, 467.45 should return 3.
Solution without converting to string (which can be dangerous in case of exotic cultures):
static int GetNumberOfDigits(decimal d)
{
decimal abs = Math.Abs(d);
return abs < 1 ? 0 : (int)(Math.Log10(decimal.ToDouble(abs)) + 1);
}
Note, that this solution is valid for all decimal values
UPDATE
In fact this solution does not work with some big values, for example: 999999999999998, 999999999999999, 9999999999999939...
Obviously, the mathematical operations with double are not accurate enough for this task.
While searching wrong values I tend to use string-based alternatives proposed in this topic. As for me, that is the evidence that they are more reliable and easy-to-use (but be aware of cultures). Loop-based solutions can be faster though.
Thanks to commentators, shame on me, lesson to you.
Instead of converting to string, you can also divide the number by 10 until it equals 0. Interesting is, that the mathematical operations on decimals are much slower than converting the decimal to a string and returning the length (see benchmarks below).
This solution does not use the Math-methods that take a double as input; so all operations are done on decimals and no casting is involved.
using System;
public class Test
{
public static void Main()
{
decimal dec = -12345678912345678912345678912.456m;
int digits = GetDigits(dec);
Console.WriteLine(digits.ToString());
}
static int GetDigits(decimal dec)
{
decimal d = decimal.Floor(dec < 0 ? decimal.Negate(dec) : dec);
// As stated in the comments of the question,
// 0.xyz should return 0, therefore a special case
if (d == 0m)
return 0;
int cnt = 1;
while ((d = decimal.Floor(d / 10m)) != 0m)
cnt++;
return cnt;
}
}
Output is 29. To run this sample, visit this link.
Side note: some benchmarks show surprising results (10k runs):
while ((d = decimal.Floor(d / 10m)) != 0m): 25ms
while ((d = d / 10m) > 1m): 32ms
ToString with Math-double-operations: 3ms
ToString with decimal-operations: 3ms
BigInt (see answer of #Heinzi): 2ms
Also using random numbers instead of always the same value (to avoid possible caching of the decimal to string conversion) showed that the string-based methods are much faster.
I would try this:
Math.Truncate(467.45).ToString().Length
If you want to be sure not having some weird results for different cultures and with negative decimals, you better use this:
var myDecimal = 467.45m;
Math.Truncate(Math.Abs(myDecimal)).ToString(CultureInfo.InvariantCulture).Length
I would prefer the following instead of casting to int to ensure that you can also handle big numbers (e.g. decimal.MaxValue):
Math.Truncate ( Math.Abs ( decValue ) ).ToString( "####" ).Length
decimal d = 467.45M;
int i = (int)d;
Console.WriteLine(i.ToString(CultureInfo.InvariantCulture).Length); //3
As a method;
public static int GetDigitsLength(decimal d)
{
int i = int(d);
return i.ToString(CultureInfo.InvariantCulture).Length;
}
Note: Of course you should check first your decimals full part is bigger than Int32.MaxValue or not. Because if it is, you get an OverflowException.
Is such a case, using long instead of int can a better approach. However even a long (System.Int64) is not big enough to hold every possible decimal value.
As Rawling mentioned, your full part can hold the thousands separator and my code will be broken in such a case. Because in this way, it totally ignores my number contains NumberFormatInfo.NumberGroupSeparator or not.
That's why getting numbers only is a better approach. Like;
i.ToString().Where(c => Char.IsDigit(c)).ToArray()
Here's a recursive example (mostly for fun).
void Main()
{
digitCount(0.123M); //0
digitCount(493854289.543354345M); //10
digitCount(4937854345454545435549.543354345M); //22
digitCount(-4937854345454545435549.543354345M); //22
digitCount(1.0M); //1
//approximately the biggest number you can pass to the function that works.
digitCount(Decimal.MaxValue + 0.4999999M); //29
}
int digitCount(decimal num, int count = 0)
{
//divided down to last digit, return how many times that happened
if(Math.Abs(num) < 1)
return count;
return digitCount(num/10, ++count); //increment the count and divide by 10 to 'remove' a digit
}
Math.Floor(Math.Log10((double)n) + 1); is the way to go.
Converting to int is BAD because decimal may be bigger than int:
Decimal.MaxValue = 79,228,162,514,264,337,593,543,950,335;
Int32.MaxValue = 2,147,483,647; //that is, hexadecimal 0x7FFFFFFF;
Math.Floor(n).ToString().Count(); is bad because it may include thousands seperators.
If you have a bias towards smaller numbers, you can use something more simple like this.
It is split up into two methods, so the first method is smaller and can be inlined.
Performance is about the same as the solution with the Log10, but without the rounding errors. The Method using Log10, is still the fastest (a bit) specially for numbers > 1 million.
public static int CountNrOfDigitsIfs(decimal d) {
var absD = Math.Abs(d);
// 1
if (absD < 10M) return 1;
// 2
if (absD < 100M) return 2;
// 3
if (absD < 1000M) return 3;
// 4
if (absD < 10000M) return 4;
return CountNrOfDigitsIfsLarge(d);
}
private static int CountNrOfDigitsIfsLarge(decimal d) {
// 5
if (d < 100000M) return 5;
// 6
if (d < 1000000M) return 6;
// 7
if (d < 10000000M) return 7;
// 8
if (d < 100000000M) return 8;
// 9
if (d < 1000000000M) return 9;
// 10
if (d < 10000000000M) return 10;
// 11
if (d < 100000000000M) return 11;
// 12
if (d < 1000000000000M) return 12;
// 13
if (d < 10000000000000M) return 13;
// 14
if (d < 100000000000000M) return 14;
// 15
if (d < 1000000000000000M) return 15;
// 16
if (d < 10000000000000000M) return 16;
// 17
if (d < 100000000000000000M) return 17;
// 18
if (d < 1000000000000000000M) return 18;
// 19
if (d < 10000000000000000000M) return 19;
// 20
if (d < 100000000000000000000M) return 20;
// 21
if (d < 1000000000000000000000M) return 21;
// 22
if (d < 10000000000000000000000M) return 22;
// 23
if (d < 100000000000000000000000M) return 23;
// 24
if (d < 1000000000000000000000000M) return 24;
// 25
if (d < 10000000000000000000000000M) return 25;
// 26
if (d < 100000000000000000000000000M) return 26;
// 27
if (d < 1000000000000000000000000000M) return 27;
// 28
if (d < 10000000000000000000000000000M) return 28;
return 29; // Max nr of digits in decimal
}
This code is generated using the following T4 template:
<#
const int SIGNIFICANT_DECIMALS = 29;
const int SPLIT = 5;
#>
namespace Study.NrOfDigits {
static partial class DigitCounter {
public static int CountNrOfDigitsIfs(decimal d) {
var absD = Math.Abs(d);
<#
for (int i = 1; i < SPLIT; i++) { // Only 29 significant digits
var zeroes = new String('0', i);
#>
// <#= i #>
if (absD < 1<#= zeroes #>M) return <#= i #>;
<#
}
#>
return CountNrOfDigitsIfsLarge(d);
}
private static int CountNrOfDigitsIfsLarge(decimal d) {
<#
for (int i = SPLIT; i < SIGNIFICANT_DECIMALS; i++) { // Only 29 significant digits
var zeroes = new String('0', i);
#>
// <#= i #>
if (d < 1<#= zeroes #>M) return <#= i #>;
<#
}
#>
return <#= SIGNIFICANT_DECIMALS #>; // Max nr of digits in decimal
}
}
}
So, I've run into this before, and solved it with this code:
SqlDecimal d = new SqlDecimal(467.45M);
int digits = d.Precision - d.Scale;
SqlDecimal is part of the System.Data.SqlTypes namespace. "Precision" is the total number of significant digits, while "Scale" is the number of digits after the decimal point.
Now, I know one objection to going this route is that SqlDecimal is part of the SQL Server-specific code. It's a valid point, but I would also point out that it's a part of the .NET framework itself, and has been since at least version 1.1, so it seems like it would be still be applicable no matter what the code around it is doing.
I looked under the hood with a decompiler (JetBrains' dotPeek in this instance), to see if maybe the code for calculating precision and scale could be easily extracted and just used, without pulling in SqlDecimal. The code to calculate scale is very simple, but the method to calculate precision is non-trivial, so if it were me, I'd just go through SqlDecimal.
This will do if you really don't want to use the Log method (which IMO is the best way). It's about the clearest way I can think of of doing this using ToString():
Math.Abs(val).ToString("f0", CultureInfo.InvariantCulture).Length
Or alternatively, if you don't want to count 0.123M as having one digit:
Math.Abs(val).ToString("#", CultureInfo.InvariantCulture).Length
You could use ToString function with a custom format.
Decimal value = 467.45m;
int count = Math.Abs(value).ToString("#", System.Globalization.CultureInfo.InvariantCulture).Length;
The # specify you only want the characters before the .
The System.Globalization.CultureInfo.InvariantCulture ensure you won't get any formating from the Region Option.
This answer is pretty much lifted from Calculate System.Decimal Precision and Scale but with a minor change to fit the question asked.
class Program
{
static void Main()
{
decimal dec = 467.45m;
Console.WriteLine(dec.GetNumberOfDigitsBeforeDecimalPlace());
}
}
public static class DecimalEx
{
public static int GetNumberOfDigitsBeforeDecimalPlace(this decimal dec)
{
var x = new System.Data.SqlTypes.SqlDecimal(dec);
return x.Precision - x.Scale;
}
}
Also if you want to do it without using the SqlDecimal class check out Jon Skeet's answer for the same question.
var sep = Convert.ToChar(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
var count = d.ToString().TakeWhile(c => c != sep).Count();
The mathematical way of doing this (and probably the fastest) is to get a logarytm of base 10 of a absolute value of this number and round it
up.
Math.Floor(Math.Log10(Math.Abs(val)) + 1);
TLDR all the other answers. I wrote this in PHP, and the math would be the same. (If I knew C# I'd have written in that language.)
$input=21689584.999;
$input=abs($input);
$exp=0;
do{
$test=pow(10,$exp);
if($test > $input){
$digits=$exp;
}
if($test == $input){
$digits=$exp+1;
}
$exp++;
}while(!$digits);
if($input < 1){$digits=0;}
echo $digits;
I don't doubt there's a better way, but I wanted to throw in my $.02
EDIT:
I php-ized the code I mentioned in my comments, but did away with the int conversion.
function digitCount($input){
$digits=0;
$input=abs($input);
while ($input >= 1) {
$digits++;
$input=$input/10;
//echo $input."<br>";
}
return $digits;
}
$big=(float)(PHP_INT_MAX * 1.1);
echo digitCount($big);
Use modulo, i'm not a C# programmer, but I'm pretty sure this solution work:
double i = 1;
int numberOfDecimals = 0;
while (varDouble % i != varDouble)
{
numberOfDecimals++;
i*=10;
}
return numberOfDecimals;
This would be the Java solution
public class test {
public static void main(String args[]) {
float f = 1.123f;
int a = (int) f;
int digits = 0;
while (a > 0) {
digits++;
a=a/10;
}
System.out.println("No Of digits before decimal="+digits);
}
}
If you treat zeros or lack of zeroes as 1 number, this is OK. If you want zero to return zero or lack of zero to return zero, then there are a few edge cases to work out which shouldn't be too hard to add. Also, should Absolute value to handle negative numbers. Added that test case as well.
const decimal d = 123.45m;
const decimal d1 = 0.123m;
const decimal d2 = .567m;
const decimal d3 = .333m;
const decimal d4 = -123.45m;
NumberFormatInfo currentProvider = NumberFormatInfo.InvariantInfo;
var newProvider = (NumberFormatInfo) currentProvider.Clone();
newProvider.NumberDecimalDigits = 0;
string number = d.ToString("N", newProvider); //returns 123 = .Length = 3
string number1 = d1.ToString("N", newProvider); //returns 0 = .Length = 1
string number2 = d2.ToString("N", newProvider); //returns 1 = .Length = 1
string number3 = d3.ToString("N", newProvider); //returns 0 = .Length = 1
string number4 = Math.Abs(d4).ToString("N", newProvider); //returns 123 = .Length = 3
Here's a somewhat final solution, if you find a test case that doesn't work, let me know. It should return 3,0,0,0,3 for the test cases provided.
public static int NumbersInFrontOfDecimal(decimal input)
{
NumberFormatInfo currentProvider = NumberFormatInfo.InvariantInfo;
var newProvider = (NumberFormatInfo)currentProvider.Clone();
newProvider.NumberDecimalDigits = 0;
var absInput = Math.Abs(input);
var numbers = absInput.ToString("N", newProvider);
//Handle Zero and < 1
if (numbers.Length == 1 && input < 1.0m)
{
return 0;
}
return numbers.Length;
}
Here is my optimized version of the code inspired by Gray's answer:
static int GetNumOfDigits(decimal dTest)
{
int nAnswer = 0;
dTest = Math.Abs(dTest);
//For loop version
for (nAnswer = 0; nAnswer < 29 && dTest > 1; ++nAnswer)
{
dTest *= 0.1M;
}
//While loop version
//while (dTest > 1)
//{
// nAnswer++;
// dTest *= 0.1M;
//}
return (nAnswer);
}
If you don't want the Math.Abs to be called inside this function then be sure to use it
outside the function on the parameter before calling GetNumOfDigits.
I decided to remove the other codes to reduce clutter in my answer, even though they helped me get to this point...
If there is any improvements needed, then let me know and I will update it :).
In order to get an accurate and culturally agnostic answer I do the following:
Use System.Numerics.BigInteger, whose constructor accepts a decimal and doesn't seem to produce any rounding errors.
Use BigInteger.Abs() to remove any sign.
Use BigInteger.ToString() with the "#" format to suppress any separators that might occur.
Code
decimal num = 123213123.123123M;
int length = BigInteger.Abs((BigInteger)num).ToString("#").Length;
You could do this by rounding the number, then getting the length of the new number. You could do it like this:
var number = 476.43;
var newNumber = Math.round(number);
//get the length of the rounded number, and subtract 1 if the
//number is negative (remove the negative sign from the count)
int digits = newNumber.ToString().Length - (number < 0 ? 1 : 0);
The other solutions will lose digits if the number is too large.
public int Digits(Decimal i)
{
NumberFormatInfo format = CultureInfo.CurrentCulture.NumberFormat;
var str = Math.Abs(i).ToString().Replace(format.NumberGroupSeparator, "");
var index = str.IndexOf(format.NumberDecimalSeparator);
var digits = index == -1 ? str.Length : index;
}
Algorithm:
Convert |decimal| to String.
If "." exist in the decimal, cut before it, otherwise consider the whole number.
Return string length.
Example:
3.14 --> 3.14 --> "3.14" --> "3.14".Substring(0,1) --> "3".Length --> 1
-1024 --> 1024 --> "1024" --> IndexOf(".") = -1 --> "1024" --> 4
Code:
static int getNumOfDigits (decimal num)
{
string d = Math.Abs(num).ToString();
if (d.IndexOf(".") > -1)
{
d = d.Substring(0, d.IndexOf("."));
}
return d.Length;
}
I haven't tested this but I would keep it straightforward and do:
decimal value = 467.45;
string str = Convert.toString(value); // convert your decimal type to a string
string[] splitStr = str.split('.'); // split it into an array (use comma separator assuming you know your cultural context)
Console.WriteLine(splitStr[0].Count); // get the first element. You can also get the number of figures after the point by indexing the next value in the array.
This does not handle negative numbers. If you care about those then considering taking the absolute value. Furthermore, if you want 0 before the decimal place to not be counted then you can use a simple if statement to check it.
simple :
string value = "467.45";
int count = value.split('.')[0] == "0" ? 0 : value.split('.')[0].ToString().Replace("-","").Count();
I'm trying to create a decimal representation of a big integer when it's divided by something. The follwoing is the code which does it, basically I want the precision to be of 2 places.
public string GetDecimal(BigInteger bigInteger,int divisor)
{
var remainder = BigInteger.Remainder(bigInteger, divisor);
var dividend = BigInteger.Divide(bigInteger, divisor);
var d = ((double)remainder / divisor);
var decimalPart = Math.Round(d, 2);
var retValue = dividend + decimalPart.ToString(".00");
return retValue;
}
}
Is there a better way of doing this please?
Thanks,
-Mike
You should probably not convert the types and do the long division on your own. This should work with any BigInteger value.
I'm sure there's room for improvement here...
public string GetDecimal(BigInteger bigInteger, int divisor)
{
BigInteger remainder;
var quotient = BigInteger.DivRem(bigInteger, divisor, out remainder);
const int decimalPlaces = 2;
var decimalPart = BigInteger.Zero;
for(int i = 0; i < decimalPlaces; i++)
{
var div = (remainder*10)/divisor;
decimalPart *= 10;
decimalPart += div;
remainder = remainder*10 - div*divisor;
}
var retValue = quotient.ToString() + "." + decimalPart.ToString(new string('0', decimalPlaces));
return retValue;
}
The built in .net decimal type is 128bit, and works with similar rounding constructs of other types. Is this number not large enough?
Instead of doing maths on it especially using less accurate types like double.
simply build a string with all but the last two digits, append a decimal point and then put the last one in.
e.g. Something like
int precision = 2;
negative = 0;
if (bigInteger < 0)
{
negative = 1;
}
String strValue = bigInteger.ToString().PadRight(precision + negative + 1,'0');
return strValue.Insert(strValue.Length - precision, ".");
var s=((bigInteger*200+divisor)/(2*(BigInteger)divisor)).ToString();
return s.Insert(".",s.Length-2);
This code only works for positive values, and uses AwayFromZero midpoint rounding. I also didn't care about localization issues.
How do I tell if a decimal or double value is an integer?
For example:
decimal d = 5.0; // Would be true
decimal f = 5.5; // Would be false
or
double d = 5.0; // Would be true
double f = 5.5; // Would be false
The reason I would like to know this is so that I can determine programmatically if I want to output the value using .ToString("N0") or .ToString("N2"). If there is no decimal point value, then I don't want to show that.
For floating point numbers, n % 1 == 0 is typically the way to check if there is anything past the decimal point.
public static void Main (string[] args)
{
decimal d = 3.1M;
Console.WriteLine((d % 1) == 0);
d = 3.0M;
Console.WriteLine((d % 1) == 0);
}
Output:
False
True
Update: As #Adrian Lopez mentioned below, comparison with a small value epsilon will discard floating-point computation mis-calculations. Since the question is about double values, below will be a more floating-point calculation proof answer:
Math.Abs(d % 1) <= (Double.Epsilon * 100)
There are any number of ways to do this. For example:
double d = 5.0;
bool isInt = d == (int)d;
You can also use modulo.
double d = 5.0;
bool isInt = d % 1 == 0;
How about this?
public static bool IsInteger(double number) {
return number == Math.Truncate(number);
}
Same code for decimal.
Mark Byers made a good point, actually: this may not be what you really want. If what you really care about is whether a number rounded to the nearest two decimal places is an integer, you could do this instead:
public static bool IsNearlyInteger(double number) {
return Math.Round(number, 2) == Math.Round(number);
}
Whilst the solutions proposed appear to work for simple examples, doing this in general is a bad idea. A number might not be exactly an integer but when you try to format it, it's close enough to an integer that you get 1.000000. This can happen if you do a calculation that in theory should give exactly 1, but in practice gives a number very close to but not exactly equal to one due to rounding errors.
Instead, format it first and if your string ends in a period followed by zeros then strip them. There are also some formats that you can use that strip trailing zeros automatically. This might be good enough for your purpose.
double d = 1.0002;
Console.WriteLine(d.ToString("0.##"));
d = 1.02;
Console.WriteLine(d.ToString("0.##"));
Output:
1
1.02
bool IsInteger(double num) {
if (ceil(num) == num && floor(num) == num)
return true;
else
return false;
}
Problemo solvo.
Edit: Pwned by Mark Rushakoff.
static bool IsWholeNumber(double x)
{
return Math.Abs(x % 1) < double.Epsilon;
}
Mark Rushakoff's answer may be simpler, but the following also work and may be more efficient since there is no implicit division operation:
bool isInteger = (double)((int)f) == f ;
and
bool isInteger = (decimal)((int)d) == d ;
If you want a single expression for both types, perhaps
bool isInteger = (double)((int)val) == (double)val ;
.NET 7 now has built-in methods for this:
decimal.IsInteger: https://learn.microsoft.com/en-us/dotnet/api/system.decimal.isinteger?view=net-7.0
double.IsInteger: https://learn.microsoft.com/en-us/dotnet/api/system.double.isinteger?view=net-7.0
You can check out the source code at:
https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Decimal.cs
https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Double.cs
If upper and lower bound of Int32 matters:
public bool IsInt32(double value)
{
return value >= int.MinValue && value <= int.MaxValue && value == (int)value;
}
You can use String formatting for the double type. Here is an example:
double val = 58.6547;
String.Format("{0:0.##}", val);
//Output: "58.65"
double val = 58.6;
String.Format("{0:0.##}", val);
//Output: "58.6"
double val = 58.0;
String.Format("{0:0.##}", val);
//Output: "58"
Let me know if this doesn't help.
public static bool isInteger(decimal n)
{
return n - (Int64)n == 0;
}
I faced a similar situation, but where the value is a string. The user types in a value that's supposed to be a dollar amount, so I want to validate that it's numeric and has at most two decimal places.
Here's my code to return true if the string "s" represents a numeric with at most two decimal places, and false otherwise. It avoids any problems that would result from the imprecision of floating-point values.
try
{
// must be numeric value
double d = double.Parse(s);
// max of two decimal places
if (s.IndexOf(".") >= 0)
{
if (s.Length > s.IndexOf(".") + 3)
return false;
}
return true;
catch
{
return false;
}
I discuss this in more detail at http://progblog10.blogspot.com/2011/04/determining-whether-numeric-value-has.html.
Using int.TryParse will yield these results:
var shouldBeInt = 3;
var shouldntBeInt = 3.1415;
var iDontWantThisToBeInt = 3.000f;
Console.WriteLine(int.TryParse(shouldBeInt.ToString(), out int parser)); // true
Console.WriteLine(int.TryParse(shouldntBeInt.ToString(), out parser)); // false
Console.WriteLine(int.TryParse(iDontWantThisToBeInt.ToString(), out parser)); // true, even if I don't want this to be int
Console.WriteLine(int.TryParse("3.1415", out parser)); // false
Console.WriteLine(int.TryParse("3.0000", out parser)); // false
Console.WriteLine(int.TryParse("3", out parser)); // true
Console.ReadKey();
You can simply compare the double against the int cast of the same value.
double d = 5.0m;
if (d == (int)d)
{
....
}
This is my solution to this problem. Maybe someone will useful.
public static bool IsInt(object number, int? decimalPlaces = null)
{
bool isInt;
var splinted = number.ToString().Split(',');
if (splinted.Length == 1)
isInt = true;
else
{
var charsAfterComma = decimalPlaces != null ? splinted[1].Substring(0, (int) decimalPlaces) : splinted[1];
isInt = charsAfterComma.First().ToString() == "0" && charsAfterComma.Replace("0", "") == "";
}
return isInt;
}
Try this:
number == Convert.ToInt16(number);
Perhaps not the most elegant solution but it works if you are not too picky!
bool IsInteger(double num) {
return !num.ToString("0.################").Contains(".");
}