首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用更快的方式从长截0代替% 10

用更快的方式从长截0代替% 10
EN

Stack Overflow用户
提问于 2019-02-06 03:44:27
回答 3查看 111关注 0票数 1

我希望从长值中“截断”0。

例如,对于长值"1234560000",我想将最后的4个值降到123456,还需要知道掉了多少个0。

我可以通过% 10的操作来实现这一点:

代码语言:javascript
复制
void Main()
{
    Console.WriteLine(Truncate(1234560000));
}

public static long Truncate(long mantissa)
{
    int droppedZeros = 0;

    while (mantissa % 10 == 0)
    {
        mantissa /= 10;
        droppedZeros++;
    }

    return mantissa;
}

这段代码被调用了数百万次,性能非常关键,我正在寻找提高性能的方法,以在没有模块的情况下实现相同的性能(这可以用位移位来完成吗?)

在每个请求中,我添加了一些基准值,包括一个基准测试,它使用已知的编译时间常量执行除法,以展示模块操作的相对开销:

代码语言:javascript
复制
          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 |

基准代码:

代码语言:javascript
复制
 [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'));
            }
        }
    }
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-02-06 06:29:23

用'%‘替换为'*’的速度要快一点

代码语言:javascript
复制
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;
}
票数 1
EN

Stack Overflow用户

发布于 2019-02-06 03:54:42

您将很难使它有效地工作与位移位,因为这是理想的除以二,其中的10不是一个。

改进的一种可能性是使用多个循环来完成较大块的工作,例如:

代码语言:javascript
复制
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的情况,因为这将导致原始代码中有一个无限循环。

您可能需要考虑的另一种可能性是,如果您多次对同一项执行此操作。例如,假设您有一个整数集合,每次您需要处理其中一个整数时,您必须去掉并计数尾随零。

在这种情况下,您实际上可以用另一种方式存储它们。例如,考虑(伪代码)结构:

代码语言:javascript
复制
struct item:
    int originalItem
    int itemWithoutZeroes
    int zeroCount

基本上,每当您第一次收到一个项(如1234560000),您就会立即将其转换为结构一次和一次。

代码语言:javascript
复制
{ 1234560000, 123456, 4 }

这提供了零去除项的缓存版本,因此您不必再计算它。

因此,如果您想要去除尾数,只需使用item.itemWithoutZeros。如果要输出原始形式的数字,可以使用item.originalItem。如果要计数零,请使用item.zeroCount

显然,这将占用更多的存储空间,但您通常会发现优化是一种时间/空间的权衡。

票数 3
EN

Stack Overflow用户

发布于 2019-02-06 05:28:17

更新您的Truncate逻辑如下。

代码语言:javascript
复制
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);
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54546319

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档