有趣的问题。为了清晰起见,测试时可能会出现很多错误,因为Java处理字符串的方式可能会影响结果。因此,让我们从构建适当的测试开始。
构建您的测试:
具体来说:适当的测试不依赖于loadstring,因为它会影响内存分配。您需要使用动态构造的字符串来进行测试。
您的整数的10-log(例如字符串的长度)将影响测试结果。字符串越长,Integer.tryParse所需的时间就越长。如果字符串更长,则需要计算更多的div/mul并花费更长的时间。影响性能的另一个因素是“-”符号。如果您有无符号整数,则应考虑这一点。
基本上,测量意味着:
- 创建具有适当长度的字符串(取决于您的数据!!!)。更多字符串=更好
- 创建与字符串数组匹配(或不匹配)的失败/通过整数数组。
- 垃圾回收。
- 使用这两个数组进行测试。
请确保在测试期间为此创建一个巨大的数组,以便您的测试不会受到影响。同时,请确保您使用的整数/随机数具有与您的数据相同的特征...因此,我无法为您执行测试,所以我只能坚持理论。
字符串转整数相等
了解字符串转整数转换的工作原理很有帮助,因此让我们从一个直截了当的解决方案开始,逐步提高。我目前的笔记本电脑上没有Java,所以对于C#语法我感到抱歉 :-) 不过你应该很容易修复它...
public int ConvertStringToInt(string s)
{
int val = 0;
if (s[0] == '-')
{
for (int i = 1; i < s.Length; ++i )
{
if (s[i] >= '0' && s[i] <= '9')
{
throw new Exception();
}
val = val * 10 + s[i] - '0';
}
return -val;
}
else
{
for (int i = 0; i < s.Length; ++i)
{
if (s[i] >= '0' && s[i] <= '9')
{
throw new Exception();
}
val = val * 10 + s[i] - '0';
}
return val;
}
}
如果您确定字符串中的数字永远不会为负数,当然可以省略条件
1。此外,如果您确定该字符串始终是一个数字(这在我看来是暗示),则可以优化
2。我通常使用算术溢出来生成大的无符号数字,这将从
2中删除一个附加条件。最终代码如下:
public int ConvertStringToInt(string s)
{
int val = 0;
if (s[0] == '-')
{
for (int i = 1; i < s.Length; ++i )
{
val = val * 10 + s[i] - '0';
}
return -val;
}
else
{
for (int i = 0; i < s.Length; ++i)
{
val = val * 10 + s[i] - '0';
}
return val;
}
}
下一步,您希望实现相等而不是转换。那么,我们能够评估多懒惰呢?嗯,我们需要解析几乎整个字符串才能进行检查。唯一确定的是,如果我们遇到一个“-”字符,我们也需要一个负整数。我最终得到了这个:
public bool EqualsStringInt(string s, int value)
{
int val = 0;
if (s[0] == '-')
{
if (value >= 0) { return false; }
for (int i = 1; i < s.Length; ++i )
{
val = val * 10 + s[i] - '0';
}
return (-val) == value;
}
else
{
if (value < 0) { return false; }
for (int i = 0; i < s.Length; ++i)
{
val = val * 10 + s[i] - '0';
}
return val == value;
}
}
整数和字符串的比较
我曾经在 C++ 中编写了一些将整数转换为字符串的代码,链接在这里:C++ performance challenge: integer to std::string conversion。如果你真正在寻找性能方面的好解决方案,这里也有一些值得考虑。
然而,仅仅检查相等比那个更容易。如果你仔细看算法,你会注意到:
- 缓冲区过量分配。你不需要这样做。如果你不等待 GC 和/或使用静态字符串来启动进程,你的测试结果会出错!
- 缓冲区重新分配。如果你按顺序填充了缓冲区,还需要翻转它。如果你不想等待 GC,这将影响测试结果!
这两个问题在长期运行中都应该耗费时间,并且都会影响你的测试结果。
此时,有趣的是你实际上并不需要完整的字符串 - 你只需要一个单独的字符。因此,我们就从这个角度来思考:
- 如果符号不匹配,则相等性失败
- 如果第一个字符不匹配,则相等性失败
- 如果生成的所有字符都相同,则相等性成功。
或者,在代码中:
public bool EqualsIntString(int value, string s)
{
if (s.Length == 0) { return false; }
if ((s[0] == '-' && value >= 0) || (s[0] != '-' && value < 0)) { return false; }
int limit = 0;
if (value < 0)
{
limit = 1;
value = -value;
}
for (int i=s.Length-1; i>=limit; --i)
{
char expected = (char)('0' + (value % 10));
value /= 10;
if (s[i] != expected) { return false; }
}
return true;
}
如果你没有负数,那么可以通过删除1来进行明显的优化。
你能做得更快吗?当然可以...这就是我首先发布C++链接的原因。大多数这些算法可以很容易地调整到这个“相等”的情况。
最后一个解决方案的可选优化
您可以使用10log来确定字符串的长度。这意味着有一个整数的下限和上限值。一个简单的查找表可以为您完成此操作。但是,如果未正确实现,10log会非常慢,因此请务必测试它!
哪一个更快
构建适当的测试并进行测试。我尝试在这里测试它,但没有您数据的特征,这可能会产生差异。
当然,如果您不需要如此直接的性能,请使用标准实现和equals,并进行测试。
str.equals(String.valueOf(integer));
。 - EpicPandaForce