ast*_*tef 82
没有转换的解决方案string(在外来文化的情况下可能很危险):
static int GetNumberOfDigits(decimal d)
{
decimal abs = Math.Abs(d);
return abs < 1 ? 0 : (int)(Math.Log10(decimal.ToDouble(abs)) + 1);
}
Run Code Online (Sandbox Code Playgroud)
请注意,此解决方案适用于所有十进制值
UPDATE
事实上,这个解决方案不与一些大的值正常工作,例如:999999999999998,999999999999999,9999999999999939...
显然,数学运算double对于这项任务来说不够准确.
在搜索错误的值时,我倾向于使用string本主题中提出的基于替代的替代方法.至于我,这证明它们更可靠和易于使用(但要注意文化).但是,基于循环的解决方案可以更快.
感谢评论员,羞辱我,给你上课.
Mar*_*kus 32
您也可以将数字除以10,直到它等于0.有趣的是,小数的数学运算比将小数转换为字符串并返回长度慢得多(参见下面的基准).
此解决方案不使用以double作为输入的Math方法; 所以所有操作都是在小数上完成的,不涉及任何转换.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
输出是29.要运行此示例,请访问此链接.
旁注:一些基准测试显示出令人惊讶的结果(10k运行):
while ((d = decimal.Floor(d / 10m)) != 0m):25mswhile ((d = d / 10m) > 1m):32毫秒同样使用随机数而不是总是相同的值(以避免可能的十进制缓存到字符串转换)表明基于字符串的方法要快得多.
Kev*_*ühl 26
我会试试这个:
Math.Truncate(467.45).ToString().Length
Run Code Online (Sandbox Code Playgroud)
如果你想确保不会有不同文化和负小数的一些奇怪的结果,你最好使用这个:
var myDecimal = 467.45m;
Math.Truncate(Math.Abs(myDecimal)).ToString(CultureInfo.InvariantCulture).Length
Run Code Online (Sandbox Code Playgroud)
Ste*_*uer 13
我更喜欢以下而不是强制转换,int以确保您也可以处理大数字(例如decimal.MaxValue):
Math.Truncate ( Math.Abs ( decValue ) ).ToString( "####" ).Length
Run Code Online (Sandbox Code Playgroud)
decimal d = 467.45M;
int i = (int)d;
Console.WriteLine(i.ToString(CultureInfo.InvariantCulture).Length); //3
Run Code Online (Sandbox Code Playgroud)
作为一种方法;
public static int GetDigitsLength(decimal d)
{
int i = int(d);
return i.ToString(CultureInfo.InvariantCulture).Length;
}
Run Code Online (Sandbox Code Playgroud)
注意:当然你应该首先检查你的小数位数是否大于Int32.MaxValue或小于.因为如果是,你会得到一个OverflowException.
是这样的情况,使用long而不是int可以更好的方法.然而,即使a long(System.Int64)也不足以容纳所有可能的decimal价值.
正如Rawling所提到的,你的完整部分可以容纳千位分隔符,在这种情况下我的代码将被破坏.因为这样,它完全忽略了我的号码是否包含NumberFormatInfo.NumberGroupSeparator.
这就是为什么只获取数字是一种更好的方法.喜欢;
i.ToString().Where(c => Char.IsDigit(c)).ToArray()
Run Code Online (Sandbox Code Playgroud)
这是一个递归的例子(主要是为了好玩).
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
}
Run Code Online (Sandbox Code Playgroud)
Math.Floor(Math.Log10((double)n) + 1); 是要走的路.
转换int为BAD因为decimal可能大于int:
Decimal.MaxValue = 79,228,162,514,264,337,593,543,950,335;
Int32.MaxValue = 2,147,483,647; //that is, hexadecimal 0x7FFFFFFF;
Run Code Online (Sandbox Code Playgroud)
Math.Floor(n).ToString().Count(); 很糟糕,因为它可能包括数千个分隔符.
如果你偏向于较小的数字,你可以使用更简单的东西.
它分为两种方法,因此第一种方法较小,可以内联.
性能与Log10的解决方案大致相同,但没有舍入错误.使用Log10的方法仍然是最快的(有点)特别适用于数量> 100万的数字.
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
}
Run Code Online (Sandbox Code Playgroud)
此代码使用以下T4模板生成:
<#
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
}
}
}
Run Code Online (Sandbox Code Playgroud)