【问题标题】:Finding the string length of a integer in .NET在.NET中查找整数的字符串长度
【发布时间】:2011-01-31 04:17:15
【问题描述】:

在 .NET 中,如果将整数表示为字符串,那么以字符为单位的整数长度的最佳方法是什么?

例如

1 = 1 个字符
10 = 2 个字符
99 = 2 个字符
100 = 3 个字符
1000 = 4 个字符

显而易见的答案是将 int 转换为字符串并获取其长度,但我希望尽可能获得最佳性能,而无需创建新字符串的开销。

【问题讨论】:

  • 始终平衡您试图获得的免费微秒与可怜的傻瓜(我猜是您自己)的昂贵阅读时间,后者必须稍后阅读和调试该代码。
  • 如果转换为以 10 为底的性能是一个问题,那么您应该为整数考虑直接十进制表示,例如 BCD。这种转换损失是计算器和早期 CPU 具有 BCD 算法的原因之一。
  • @GregS - 我怀疑不是转换本身就是问题,而是用大量无用的字符串填充字符串堆。然而,基于 GC 的工作方式,我认为这在实践中也不是问题。

标签: .net performance string math


【解决方案1】:

您可以使用对数来计算 int 的长度:

public static int IntLength(int i) {
  if (i <= 0) throw new ArgumentOutOfRangeException();

  return (int)Math.Floor(Math.Log10(i)) + 1;
}

测试通过:

[Test]
public void TestIntLength() {
  Assert.AreEqual(1, IntLength(1));
  Assert.AreEqual(1, IntLength(9));
  Assert.AreEqual(2, IntLength(10));
  Assert.AreEqual(2, IntLength(99));
  Assert.AreEqual(3, IntLength(100));
  Assert.AreEqual(3, IntLength(999));
  Assert.AreEqual(4, IntLength(1000));
  Assert.AreEqual(10, IntLength(int.MaxValue));
}

快速测试表明 log-method 比 int.ToString().Length 方法快 4 倍..

下面 GvS 显示的方法(使用 if 语句)比 log 方法快 6 倍(!):

public static int IntLengthIf(int i) {
  if (i < 10) return 1;
  if (i < 100) return 2;
  if (i < 1000) return 3;
  if (i < 10000) return 4;
  if (i < 100000) return 5;
  if (i < 1000000) return 6;
  if (i < 10000000) return 7;
  if (i < 100000000) return 8;
  if (i < 1000000000) return 9;
  throw new ArgumentOutOfRangeException();
}

这里是数字 1 到 10000000 的确切时间:

IntLengthToString: 4205ms
IntLengthLog10: 1122ms
IntLengthIf: 201ms

【讨论】:

  • 为了应对负数,你可以得到i的绝对值,然后在函数的结果上加1。
  • 如果您已经对此进行了快速测试,您应该将其与 GvS 的解决方案进行比较。那应该很有趣。
  • 您可以添加对负数的支持: public static int IntLengthIf(int i, bool WithMinus) { int iCount = 0;如果 (i_iValue
  • 顺便说一句,IntLengthIf 中有一个错误:如果你有像 MAXINT 这样的 > 1e9 的值,那么你有 10 位数字,但这种情况不处理。所以你应该添加if (i_iValue &lt;= int.MaxValue) return 10;
【解决方案2】:

如果输入在 0-10000 范围内

if (i < 10) return 1;
if (i < 100) return 2;
if (i < 1000) return 3;
if (i < 10000) return 4;
// etc

【讨论】:

  • 这是最简单的解决方案,而且读起来很好。它可能无法与优化的浮点对数竞争。
  • 我不会费心去做测试,但我敢打赌这个解决方案比对数解决方案更快。日志需要相当多的时钟周期来计算。
【解决方案3】:

你可以这样使用:

        int integer = 100;

        int charachtersCount = 0;
        while (integer > 0)
        {
            integer = integer/10;
            charachtersCount++;
        }

但是你真的需要优化它吗?我实际上更喜欢使用字符串(看起来好多了):

integer.ToString().Length

【讨论】:

  • 不错的解决方案,但正如您所说,我怀疑性能是否良好。我想字符串转换是最好的。
【解决方案4】:

如果您还需要处理负数,您可以使用 stmax solution 旋转:

public static int IntLength(int i) { 
  if (i == 0) return 1; // no log10(0)
  int n = (i < 0) ? 2 : 1;
  i = (i < 0) ? -i : i;

  return (int)Math.Floor(Math.Log10(i)) + n; 
} 

【讨论】:

    【解决方案5】:

    你可以这样做:

    int ndig = 1;
    if (n < 0){n = -n; ndig++;}
    if (n >= 100000000){n /= 100000000; ndig += 8;}
    if (n >=     10000){n /=     10000; ndig += 4;}
    if (n >=       100){n /=       100; ndig += 2;}
    if (n >=        10){n /=        10; ndig += 1;}
    

    或类似的东西。需要 4 次比较和 0-4 次除法。

    (在 64 位上,您必须添加第五级。)

    【讨论】:

    • 这一点很聪明。如果我喜欢它,它比直道稍慢。
    【解决方案6】:

    如果你想通过数学来做,你可以试试这个:

    int integer = 100
    int charCount = (int) Math.Ceiling(Math.Log10(integer+1));
    

    我怀疑这是否比转换为字符串快得多

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-05
      • 1970-01-01
      • 1970-01-01
      • 2017-06-13
      • 2013-05-03
      • 1970-01-01
      • 2018-01-20
      相关资源
      最近更新 更多