如何修复我的numberOfDigits函数

时间:2013-06-19 20:19:38

标签: performance algorithm vba math optimization

遇到一些代码,其中通过将数字转换为字符串然后使用len()来确定位数。

Function numOfDigits_len(n As Long) As Long
    numOfDigits_len = Len(Str(n)) - 1
End Function

现在虽然这有效,但我知道与任何不使用字符串的方法相比它会很慢,所以我写了一个使用log()的方法。

Function numOfDigits_log(n As Long) As Long
    numOfDigits_log = Int(Log(n) / Log(10)) + 1
End Function

将运行时间减少1/2,这很好,但在特定情况下发生了一些奇怪的事情。

  n     numOfDigits_log(n)
=====  ====================
 999            3
1000            3
1001            4

它无法正确处理1000。我认为这是因为浮点和舍入问题。

Function numOfDigits_loop(ByVal n As Long) As Long
    Do Until n = 0
        n = n \ 10
        numOfDigits_loop = numOfDigits_loop + 1
    Loop
End Function

写了这个,当数字大于10 ^ 6时,结果变慢了约10%,并且随着n变大,似乎变得越来越慢。如果我是务实的话,这很好,但我想找到更理想的东西。

现在我的问题是,有没有办法准确使用log()方法。我可以做类似

的事情
Function numOfDigits_log(n As Long) As Long
    numOfDigits_log = Int(Log(n) / Log(10) + 0.000000001) + 1
End Function

但它似乎非常“hacky”。有没有比log()方法更快或更快的更好的方法?  注意:我意识到在很多情况下这种优化是没有意义的,但现在我遇到过这种情况我想“修复”它

3 个答案:

答案 0 :(得分:1)

while循环保证正确性,即它不使用任何浮点计算

int numDigits = 0;
while(num != 0) {
    num /= 10;
    numDigits++;
}

您还可以使用更大的除数

加快速度
int numDigits = 0;
if(num >= 100000 || num <= -100000) {
    int prevNum;
    while(num != 0) {
        prevNum = num;
        num /= 100000;
        numDigits += 5;
    }
    num = prevNum;
    numDigits -= 5;
}
while(num != 0) {
    num /= 10;
    numDigits++;
}

答案 1 :(得分:1)

我之前已经回答了这个问题,但我找不到了,所以这里是基础知识:

int i = ... some number >= 0 ...
int n = 1;
if (i >= 100000000){i /= 100000000; n += 8;}
if (i >= 10000){i /= 10000; n += 4;}
if (i >= 100){i /= 100; n += 2;}
if (i >= 10){i /= 10; n += 1;}

那是在C中,但你明白了。

答案 2 :(得分:0)

你会喜欢这个。

我们住在一个基地10号码系统!这意味着您所要做的就是ROUND UP。

一些数字的长度ALWAYS = ceiling (log n)。例如:7456412(一个7位数字)。记录(7456412)= 6.8 ...向上舍入,你有7. log(9999)= 3.9999。向上,它是4。

特殊情况是你不必舍入,或者当你有10的幂时。例如:log(1000)= 3.如果你能检测到你有10的幂,添加一个日志结果,你赢了!

你可以做这种检测的方式就像

double log10;
int clog10;
int length;

log10 = (Log(n) / Log(10)); // can also use a private static final long hardcoded for Log(10)
clog10 = ceiling(log10);
if (Int(log10) == clog10)
  length = clog10 + 1;
else
  length = clog10;