我希望从长值中“截断”0。
例如,对于长值"1234560000",我想将最后的4个值降到123456,还需要知道掉了多少个0。
我可以通过% 10的操作来实现这一点:
void Main()
{
Console.WriteLine(Truncate(1234560000));
}
public static long Truncate(long mantissa)
{
int droppedZeros = 0;
while (mantissa % 10 == 0)
{
mantissa /= 10;
droppedZeros++;
}
return mantissa;
}这段代码被调用了数百万次,性能非常关键,我正在寻找提高性能的方法,以在没有模块的情况下实现相同的性能(这可以用位移位来完成吗?)
在每个请求中,我添加了一些基准值,包括一个基准测试,它使用已知的编译时间常量执行除法,以展示模块操作的相对开销:
Method | Mean | Error | StdDev | Median | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
---------------- |----------:|----------:|----------:|----------:|------------:|------------:|------------:|--------------------:|
DivideNoModulo | 1.863 ms | 0.0431 ms | 0.1272 ms | 1.855 ms | - | - | - | - |
ModuloBasic | 21.342 ms | 0.8776 ms | 2.5876 ms | 20.813 ms | - | - | - | - |
DivisionBasic | 18.159 ms | 1.7218 ms | 5.0768 ms | 15.937 ms | - | - | - | - |
DivisionSmarter | 7.510 ms | 0.5307 ms | 1.5649 ms | 7.201 ms | - | - | - | - |
ModuloSmarter | 8.517 ms | 0.1673 ms | 0.2886 ms | 8.531 ms | - | - | - | - |
StringTruncate | 42.370 ms | 1.7358 ms | 5.1181 ms | 40.566 ms | 1000.0000 | - | - | 8806456 B |基准代码:
[SimpleJob(RunStrategy.ColdStart, 1)]
[MemoryDiagnoser]
public class EncoderBenchmark
{
private long _mantissa;
[Benchmark]
public void DivideNoModulo()
{
for (var i = 0; i < 100000; i++)
{
_mantissa = 12345600000000;
_mantissa /= 100000000;
}
}
[Benchmark]
public void ModuloBasic()
{
for (var i = 0; i < 100000; i++)
{
_mantissa = 12345600000000;
while (_mantissa % 10 == 0)
{
_mantissa /= 10;
}
}
}
[Benchmark]
public void DivisionBasic()
{
for (var i = 0; i < 100000; i++)
{
_mantissa = 12345600000000;
for (;;)
{
long temp = _mantissa / 10;
if (temp * 10 != _mantissa)
break;
_mantissa = temp;
}
}
}
[Benchmark]
public void DivisionSmarter()
{
for (var i = 0; i < 100000; i++)
{
_mantissa = 12345600000000;
for (; ; )
{
long temp = _mantissa / 1000000;
if (temp * 1000000 != _mantissa)
break;
_mantissa = temp;
}
for (; ; )
{
long temp = _mantissa / 10;
if (temp * 10 != _mantissa)
break;
_mantissa = temp;
}
}
}
[Benchmark]
public void ModuloSmarter()
{
for (var i = 0; i < 100000; i++)
{
_mantissa = 12345600000000;
while (_mantissa % 1000000 == 0)
{
_mantissa /= 1000000;
}
while (_mantissa % 10 == 0)
{
_mantissa /= 10;
}
}
}
[Benchmark]
public void StringTruncate()
{
for (var i = 0; i < 100000; i++)
{
_mantissa = 12345600000000;
_mantissa = long.Parse(_mantissa.ToString().TrimEnd('0'));
}
}
}发布于 2019-02-06 06:29:23
用'%‘替换为'*’的速度要快一点
public static long T(long mantissa)
{
if (mantissa == 0)
return 0;
int droppedZeros = 0;
for (; ; )
{
long temp = mantissa / 1000000;
if (temp * 1000000 != mantissa)
break;
mantissa = temp;
droppedZeros += 6;
}
for (; ; )
{
long temp = mantissa / 1000;
if (temp * 1000 != mantissa)
break;
mantissa = temp;
droppedZeros += 3;
}
for (; ; )
{
long temp = mantissa / 10;
if (temp * 10 != mantissa)
break;
mantissa = temp;
droppedZeros++;
}
return mantissa;
}发布于 2019-02-06 03:54:42
您将很难使它有效地工作与位移位,因为这是理想的除以二,其中的10不是一个。
改进的一种可能性是使用多个循环来完成较大块的工作,例如:
if (mantissa != 0) {
while (mantissa % 1000000 == 0) {
mantissa /= 1000000;
droppedZeros += 6;
}
while (mantissa % 1000 == 0) {
mantissa /= 1000;
droppedZeros += 3;
}
while (mantissa % 10 == 0) {
mantissa /= 10;
droppedZeros++;
}
}这通常会导致执行的指令较少,但是,与所有优化、度量一样,不要猜测!可能不值得获得所获得的好处(如果有的话)。
注意,我也捕捉到了mantissa == 0的情况,因为这将导致原始代码中有一个无限循环。
您可能需要考虑的另一种可能性是,如果您多次对同一项执行此操作。例如,假设您有一个整数集合,每次您需要处理其中一个整数时,您必须去掉并计数尾随零。
在这种情况下,您实际上可以用另一种方式存储它们。例如,考虑(伪代码)结构:
struct item:
int originalItem
int itemWithoutZeroes
int zeroCount基本上,每当您第一次收到一个项(如1234560000),您就会立即将其转换为结构一次和一次。
{ 1234560000, 123456, 4 }这提供了零去除项的缓存版本,因此您不必再计算它。
因此,如果您想要去除尾数,只需使用item.itemWithoutZeros。如果要输出原始形式的数字,可以使用item.originalItem。如果要计数零,请使用item.zeroCount。
显然,这将占用更多的存储空间,但您通常会发现优化是一种时间/空间的权衡。
发布于 2019-02-06 05:28:17
更新您的Truncate逻辑如下。
public static long Truncate(long mantissa)
{
if (mantissa == 0)
return 0;
var mantissaStr = mantissa.ToString();
var mantissaTruncated = mantissaStr.TrimEnd('0');
int droppedZeros = mantissaStr.Length - mantissaTruncated.Length;
return Convert.ToInt64(mantissaTruncated);
}https://stackoverflow.com/questions/54546319
复制相似问题