获取无符号长整数c#中的位数

时间:2011-02-09 19:15:43

标签: c# algorithm numbers

我正在尝试确定c#ulong数字中的位数,我试图使用一些数学逻辑而不是使用ToString()。长度。我没有对这两种方法进行基准测试,但已经看到有关使用System.Math.Floor(System.Math.Log10(number))+ 1来确定位数的其他帖子。 似乎工作正常,直到我从999999999999997过渡到999999999999998,此时,我开始得到一个不正确的计数。

之前有没有人遇到过这个问题?

我见过类似帖子的Java重点@ Why log(1000)/log(10) isn't the same as log10(1000)?以及帖子@ How to get the separate digits of an int number?,它表示我怎么可能使用%运算符实现相同但有更多代码

这是我用来模拟这个

的代码
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);

提前致谢

专利

4 个答案:

答案 0 :(得分:7)

log10将涉及浮点转换 - 因此舍入错误。对于double来说,误差非常小,但对于精确整数来说这是一个大问题!

排除.ToString()方法和浮点方法,然后是,我认为你将不得不使用迭代方法,但我会使用整数除法而不是模数。

整数除以10.结果是&gt; 0?如果是这样的话。如果没有,停止。 位数是所需的迭代次数。

EG。 5 - &gt; 0; 1次迭代= 1位数。

1234 - &gt; 123 - &gt; 12 - &gt; 1 - &gt; 0; 4次迭代= 4位数。

答案 1 :(得分:6)

我会使用ToString().Length,除非你知道这将被召唤数百万次。

“过早优化是所有邪恶的根源” - 唐纳德克努特

答案 2 :(得分:3)

来自documentation

  

默认情况下,Double值包含15   但精度的十进制数字   最多保留17位数字   内部。

我怀疑你正在达到精确限制。您的值999,999,999,999,998可能处于精度限制。由于在调用ulong之前必须将double转换为Math.Log10,因此您会看到此错误。

答案 3 :(得分:0)

其他答案已经发布为什么会发生这种情况。

这是一个确定整数“长度”的快速方法示例(某些情况除外)。这本身并不是很有趣 - 但是我把它包含在这里因为使用这个方法与Log10 结合使用可以获得无条件长整个范围的“完美”精度,而无需第二次日志调用

// 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

这种查找表方法可以很容易地转换为任何基础。 这种方法应该比迭代的逐个分区方法更快,但是分析是留给读者的练习。 (直接if-then分支分成“组”可能更快,但这对我的口味来说太多重复键入。)

快乐的编码。