热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

计算整数小数长度的最快方法?(。净)-Fastestwaytocalculatethedecimallengthofaninteger?(.NET)

Ihavesomecodethatdoesalotofcomparisonsof64-bitintegers,howeveritmusttakeintoaccoun

I have some code that does a lot of comparisons of 64-bit integers, however it must take into account the length of the number, as if it was formatted as a string. I can't change the calling code, only the function.

我有一些代码可以对64位整数进行大量的比较,但是它必须考虑数字的长度,就像它被格式化为字符串一样。我无法更改调用代码,只能更改函数。

The easiest way (besides .ToString().Length) is:

最简单的方法(除了.ToString()。Length)是:

(int)Math.Truncate(Math.Log10(x)) + 1;

However that performs rather poorly. Since my application only sends positive values, and the lengths are rather evenly distributed between 2 and 9 (with some bias towards 9), I precomputed the values and have if statements:

然而,这表现得相当糟糕。由于我的应用程序只发送正值,并且长度相当均匀地分布在2到9之间(偏向9),我预先计算了值并使用if语句:

static int getLen(long x) {
    if (x <1000000) {
        if (x <100) return 2;
        if (x <1000) return 3;
        if (x <10000) return 4;
        if (x <100000) return 5;
        return 6;
    } else {
        if (x <10000000) return 7;
        if (x <100000000) return 8;
        if (x <1000000000) return 9; 
        return (int)Math.Truncate(Math.Log10(x)) + 1; // Very uncommon
    }
}

This lets the length be computed with an average of 4 compares.

这使得长度可以用平均4个比较来计算。

So, are there any other tricks I can use to make this function faster?

那么,我有什么其他技巧可以让这个功能更快吗?

Edit: This will be running as 32-bit code (Silverlight).

编辑:这将作为32位代码(Silverlight)运行。

Update:

I took Norman's suggestion and changed the ifs around a bit to result in an average of only 3 compares. As per Sean's comment, I removed the Math.Truncate. Together, this boosted things about 10%. Thanks!

我采用了Norman的建议并稍微改变了ifs,结果平均只有3个比较。根据肖恩的评论,我删除了Math.Truncate。总之,这促进了大约10%的事情。谢谢!

10 个解决方案

#1


6  

Two suggestions:

  1. Profile and put the common cases first.
  2. 简介并将常见案例放在第一位。

  3. Do a binary search to minimize the number of comparions in the worst case. You can decide among 8 alternatives using exactly three comparisons.
  4. 进行二分查找以最小化最坏情况下的比较次数。您可以使用恰好三个比较来决定8个替代方案。

This combination probably doesn't buy you much unless the distribution is very skew.

除非分布非常偏斜,否则这种组合可能不会给你带来太大的影响。

#2


5  

From Sean Anderson's Bit Twiddling Hacks:

来自Sean Anderson的Bit Twiddling Hacks:

Find integer log base 10 of an integer

查找整数的整数对数10

unsigned int v; // non-zero 32-bit integer value to compute the log base 10 of 
int r;          // result goes here
int t;          // temporary

static unsigned int const PowersOf10[] = 
    {1, 10, 100, 1000, 10000, 100000,
     1000000, 10000000, 100000000, 1000000000};

t = (IntegerLogBase2(v) + 1) * 1233 >> 12; // (use a lg2 method from above)
r = t - (v 

The integer log base 10 is computed by first using one of the techniques above for finding the log base 2. By the relationship log10(v) = log2(v) / log2(10), we need to multiply it by 1/log2(10), which is approximately 1233/4096, or 1233 followed by a right shift of 12. Adding one is needed because the IntegerLogBase2 rounds down. Finally, since the value t is only an approximation that may be off by one, the exact value is found by subtracting the result of v

通过首先使用上述技术之一来查找日志库2来计算整数对数库10.通过关系log10(v)= log2(v)/ log2(10),我们需要将其乘以1 / log2( 10),大约是1233/4096,或1233,然后右移12.需要添加一个,因为IntegerLogBase2向下舍入。最后,由于值t只是一个可能偏离1的近似值,因此通过减去v

This method takes 6 more operations than IntegerLogBase2. It may be sped up (on machines with fast memory access) by modifying the log base 2 table-lookup method above so that the entries hold what is computed for t (that is, pre-add, -mulitply, and -shift). Doing so would require a total of only 9 operations to find the log base 10, assuming 4 tables were used (one for each byte of v).

此方法比IntegerLogBase2多运行6次。通过修改上面的log base 2 table-lookup方法,可以加速(在具有快速内存访问的机器上),以便条目保存为t计算的内容(即pre-add,-mulitply和-shift)。这样做将需要总共仅9个操作来找到日志库10,假设使用了4个表(对于v的每个字节一个表)。

As far as computing IntegerLogBase2, there are several alternatives presented on that page. It's a great reference for all sorts of highly optimized integer operations.

就计算IntegerLogBase2而言,该页面上提供了几种替代方案。它是各种高度优化的整数运算的绝佳参考。

A variant of your version is also there, except it assumes the values (rather than the log base 10 of the values) are uniformly distributed, and therefore does an exponentially ordered search:

您的版本的变体也存在,除了它假设值(而不是值的日志基数10)是均匀分布的,因此执行指数排序的搜索:

Find integer log base 10 of an integer the obvious way

以明显的方式查找整数的整数对数10

unsigned int v; // non-zero 32-bit integer value to compute the log base 10 of 
int r;          // result goes here

r = (v >= 1000000000) ? 9 : (v >= 100000000) ? 8 : (v >= 10000000) ? 7 : 
    (v >= 1000000) ? 6 : (v >= 100000) ? 5 : (v >= 10000) ? 4 : 
    (v >= 1000) ? 3 : (v >= 100) ? 2 : (v >= 10) ? 1 : 0;

This method works well when the input is uniformly distributed over 32-bit values because 76% of the inputs are caught by the first compare, 21% are caught by the second compare, 2% are caught by the third, and so on (chopping the remaining down by 90% with each comparision). As a result, less than 2.6 operations are needed on average.

当输入均匀分布在32位值时,此方法很有效,因为76%的输入被第一次比较捕获,21%被第二次比较捕获,2%被第三次比较捕获,依此类推(斩波)每次比较后剩下的90%)。因此,平均需要不到2.6次操作。

#3


2  

Here's a binary-search version, which I have tested, which works on 64-bit integers using exactly five comparisons each time.

这是我测试过的二进制搜索版本,它每次只使用五次比较就可以使用64位整数。

int base10len(uint64_t n) {
  int len = 0;
  /* n <10^32 */
  if (n >= 10000000000000000ULL) { n /= 10000000000000000ULL; len += 16; }
  /* n <10^16 */
  if (n >= 100000000) { n /= 100000000; len += 8; }
  /* n <100000000 = 10^8 */
  if (n >= 10000) { n /= 10000; len += 4; }
  /* n <10000 */
  if (n >= 100) { n /= 100; len += 2; }
  /* n <100 */
  if (n >= 10) { return len + 2; }
  else         { return len + 1; }
}

I doubt this is going to be any faster than what you're already doing. But it's predictable.

我怀疑这会比你已经做的更快。但这是可以预测的。

#4


2  

I did some testing, and this seems to be 2-4 times faster than the code that you have now:

我做了一些测试,这似乎比你现在的代码快2-4倍:

static int getLen(long x) {
    int len = 1;
    while (x > 9999) {
        x /= 10000;
        len += 4;
    }
    while (x > 99) {
        x /= 100;
        len += 2;
    }
    if (x > 9) len++;
    return len;
}

Edit:
Here is a version that uses more Int32 operations, that should work better if you don't have an x64 application:

编辑:这是一个使用更多Int32操作的版本,如果您没有x64应用程序,它应该可以更好地工作:

static int getLen(long x) {
    int len = 1;
    while (x > 99999999) {
        x /= 100000000;
        len += 8;
    }
    int y = (int)x;
    while (y > 999) {
        y /= 1000;
        len += 3;
    }
    while (y > 9) {
        y /= 10;
        len ++;
    }
    return len;
}

#5


0  

You commented in code that 10 digits or more is very uncommon, so your original solution is not bad

您在代码中注释了10位数或更多位数是非常罕见的,因此您的原始解决方案也不错

#6


0  

I haven't tested this, but the change of base law says:

我没有测试过这个,但基本法的变化说:

Log10(x) = Log2(x) / Log2(10)

Log10(x)= Log2(x)/ Log2(10)

Log2 should be a bit faster than Log10 if it's implemented right.

如果实现正确,Log2应该比Log10快一点。

#7


0  

static int getDigitCount( int x )
    {
    int digits = ( x <0 ) ? 2 : 1; // '0' has one digit,negative needs space for sign
    while( x > 9 ) // after '9' need more
        {
        x /= 10; // divide and conquer
        digits++;
        }
    return digits;
    }

#8


-1  

not sure if this is faster or not.. but you can always count...

不确定这是否更快..但你可以随时计算......

static int getLen(long x) {
    int len = 1;
    while (x > 0) {
        x = x/10;
        len++
    };
    return len
}

#9


-1  

What do you mean by length? Number of zeros or everything? This does significant figures, but you get the general idea

你的长度是什么意思?零或一切的数量?这确实有重要的数字,但你得到了一般的想法

public static string SpecialFormat(int v, int sf)  
{  
     int k = (int)Math.Pow(10, (int)(Math.Log10(v) + 1 - sf));  
     int v2 = ((v + k/2) / k) * k;  
     return v2.ToString("0,0");  
}

#10


-1  

It's a simple way.

这是一种简单的方法。

private static int GetDigitCount(int number)
{
    int digit = 0;

    number = Math.Abs(number);

    while ((int)Math.Pow(10, digit++) <= number);

    return digit - 1;
}

If number is unsigned int then "Math.Abs(number)" not necessary.

如果number是unsigned int,那么“Math.Abs​​(number)”不是必需的。

I made extension method with all numeric types.

我用所有数字类型制作了扩展方法。

    private static int GetDigitCount(dynamic number)
    {
        dynamic digit = 0;

        number = Math.Abs(number);

        while ((dynamic)Math.Pow(10, digit++) <= number)
            ;

        return digit - 1;
    }

    public static int GetDigit(this int number)
    {
        return GetDigitCount(number);
    }

    public static int GetDigit(this long number)
    {
        return GetDigitCount(number);
    }

then you use this.

然后你用这个。

int x = 100;
int digit = x.GetDigit();  // 3 expected.

推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文介绍了在wepy中运用小顺序页面受权的计划,包含了用户点击作废后的从新受权计划。 ... [详细]
author-avatar
OH-MQNZ_259
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有