C# 获取无符号长整数c中的位数#
我试图确定c#ulong数的位数,我试图使用一些数学逻辑,而不是使用ToString().Length。我还没有对这两种方法进行基准测试,但是我看到过其他关于使用System.Math.Floor(System.Math.Log10(number))+1来确定位数的帖子。 在我从9999999999999 7转换到9999999999 8之前,似乎工作正常。在这一点上,我开始得到一个不正确的计数 以前有人遇到过这个问题吗 我看到过类似的帖子,其中有一个Java emphasis@和一个post@表示我如何可能使用%运算符实现相同的功能,但代码要多得多 这是我用来模拟的代码C# 获取无符号长整数c中的位数#,c#,algorithm,numbers,C#,Algorithm,Numbers,我试图确定c#ulong数的位数,我试图使用一些数学逻辑,而不是使用ToString().Length。我还没有对这两种方法进行基准测试,但是我看到过其他关于使用System.Math.Floor(System.Math.Log10(number))+1来确定位数的帖子。 在我从9999999999999 7转换到9999999999 8之前,似乎工作正常。在这一点上,我开始得到一个不正确的计数 以前有人遇到过这个问题吗 我看到过类似的帖子,其中有一个Java emphasis@和一个post@
Action<ulong> displayInfo = number =>
Console.WriteLine("{0,-20} {1,-20} {2,-20} {3,-20} {4,-20}",
number,
number.ToString().Length,
System.Math.Log10(number),
System.Math.Floor(System.Math.Log10(number)),
System.Math.Floor(System.Math.Log10(number)) + 1);
Array.ForEach(new ulong[] {
9U,
99U,
999U,
9999U,
99999U,
999999U,
9999999U,
99999999U,
999999999U,
9999999999U,
99999999999U,
999999999999U,
9999999999999U,
99999999999999U,
999999999999999U,
9999999999999999U,
99999999999999999U,
999999999999999999U,
9999999999999999999U}, displayInfo);
Array.ForEach(new ulong[] {
1U,
19U,
199U,
1999U,
19999U,
199999U,
1999999U,
19999999U,
199999999U,
1999999999U,
19999999999U,
199999999999U,
1999999999999U,
19999999999999U,
199999999999999U,
1999999999999999U,
19999999999999999U,
199999999999999999U,
1999999999999999999U
}, displayInfo);
Action displayInfo=number=>
Console.WriteLine(“{0,-20}{1,-20}{2,-20}{3,-20}{4,-20}”,
数字,
number.ToString().Length,
系统数学日志10(编号),
System.Math.Floor(System.Math.Log10(编号)),
系统数学层(系统数学日志10(编号))+1);
Array.ForEach(新的ulong[]{
9U,
99U,
999U,
9999U,
9999U,
9999999 U,
9999999U,
99999999U,
9999999999U,
9999999999 U,
9999999999U,
99999999999 U,
9999999999999U,
9999999999999 U,
9999999999999U,
99999999999999 U,
999999999999999 U,
99999999999999999 U,
9999999999999999999999U},显示信息);
Array.ForEach(新的ulong[]{
1U,
19U,
199U,
1999U,
19999U,
199999U,
1999999U,
1999999U,
19999999U,
199999999U,
1999999999U,
199999999U,
19999999999U,
199999999999U,
1999999999999U,
199999999999U,
1999999999999U,
199999999999999U,
1999999999999999U
},显示信息);
提前谢谢
Patlog10将涉及浮点转换-因此存在舍入误差。对于double来说,这个误差非常小,但是对于一个精确的整数来说,这个误差是非常大的 不包括.ToString()方法和浮点方法,那么是的,我认为您必须使用迭代方法,但我将使用整数除法而不是模 整数除以10。结果是否>0?如果是这样的话,就迭代一下。如果没有,请停止。 位数是所需的迭代次数 例5->0;1次迭代=1位 1234->123->12->1->0;4次迭代=4位。来自: 默认情况下,双精度值包含15 精度的小数位数,尽管 最多保留17位数字 内部 我怀疑你正在接近精度极限。您的999999999998值可能处于精度极限。由于在调用
Math.Log10
之前必须将ulong
转换为double
,因此您会看到此错误。除非您知道这将被调用数百万次,否则我将使用ToString().Length
“过早优化是万恶之源”-Donald Knuth其他答案已经公布了为什么会发生这种情况
下面是一个快速确定整数“长度”的示例(某些情况除外)。这本身并不是很有趣——但我在这里包括它,因为将此方法与Log10结合使用可以在无符号long的整个范围内获得“完美”的精度,而不需要第二次日志调用
// the lookup would only be generated once
// and could be a hard-coded array literal
ulong[] lookup = Enumerable.Range(0, 20)
.Select((n) => (ulong)Math.Pow(10, n)).ToArray();
ulong x = 999;
int i = 0;
for (; i < lookup.Length; i++) {
if (lookup[i] > x) {
break;
}
}
// i is length of x "in a base-10 string"
// does not work with "0" or negative numbers
//查找将只生成一次
//可能是一个硬编码的数组文字
ulong[]查找=可枚举。范围(0,20)
.Select((n)=>(ulong)Math.Pow(10,n)).ToArray();
ulong x=999;
int i=0;
for(;ix){
打破
}
}
//i是x“的长度,以10为基数的字符串”
//不适用于“0”或负数
这种查找表方法可以很容易地转换为任何基。这种方法应该比迭代的按基划分的方法更快,但是评测留给读者作为练习。(一个直接的if-then分支分为“组”可能更快,但这对我来说太多重复性的打字了。)
快乐编码。您不需要
%
运算符,整数除法就足够了。“更多代码”是一个单语句循环。没有那么多代码。ToString().Length调用真的那么昂贵吗?也许这是一个头发慢,但它将是准确的任何值。对我来说,准确度比效率更令人满意。当使用Log10
函数时,您开始得到错误的结果是有道理的,因为该函数使用的是double
类型,它不能准确地表示非常大的整数(请参见)。我同意,我认为使用ToString()没有什么特别的错误.Length
。此外,只要签名正确,您可以将操作更改为常规方法。如果您想要“速度”,请参阅--“级联如果”版本(可以用一些类似于迭代方法的分割法分解为多个部分)。否则,您可能需要在此处执行ToString
。可以将if
移动到列表的快速迭代中。使查找表保持静态并使用二进制搜索代替直接迭代可能会使此解决方案的速度加快一点。If需要更多的种子,将二进制搜索扩展到一系列If语句中可能是最快的。只是一个玩笑:对这种方法的一点修改实际上只需要整数乘法和比较。查看我的回复中的查找表应该会有一些启发(上一句话不需要查找表)。当然,请反向操作。如果乘法运算速度更快,这可能更可取。它更快。问题是它是否可感知;-)我只是想留下评论,因为前几天晚上,在我写完文章之后,我突然想到了这一点。我意识到,我以前从未见过有人建议用它来解决这个问题(这可能意味着几件事中的一件……)。