获取数字的数字有什么更好的选择吗? (C ++)

时间:2010-11-10 03:50:18

标签: c++

我知道你可以使用模数和除法得到数字的数字。以下是我过去的做法:( Psuedocode,以便让学生阅读这些一些为他们的家庭作业工作):

int pointer getDigits(int number) 
    initialize int pointer to array of some size
    initialize int i to zero
    while number is greater than zero
       store result of number mod 10 in array at index i
       divide number by 10 and store result in number
       increment i
    return int pointer

无论如何,我想知道是否有更好,更有效的方法来完成这项任务?如果没有,是否有任何替代方法来完成此任务,避免使用字符串? C风格还是其他?

感谢。我问,因为我想要在我的个人项目中做这件事,我想尽可能高效地做到这一点。

非常感谢任何帮助和/或见解。

7 个答案:

答案 0 :(得分:3)

除非你想要在2的幂的基数中表示数字,否则这是唯一的方法。

答案 1 :(得分:3)

提取数字所需的时间将与动态分配数组所需的时间相比相形见绌。考虑在结构中返回结果:

struct extracted_digits
{
    int number_of_digits;
    char digits[12];
};

您需要为此处的最大位数(12选择合适的值,这对于32位整数就足够了)。或者,您可以返回std::array<char, 12>并使用无效值对终端进行编码(因此,在最后一个值之后,存储10或其他不是数字的内容。

根据您是否要处理负值,您还必须决定如何报告一元减号(-)。

答案 2 :(得分:1)

通过“避免使用字符串”,我将假设你这样做是因为如果你想要一个整数值,只有字符串表示是非常低效的。

为此,我将建议一种可能适合的略微非正统的方法。不要将它们存储在一个表单中,将它们存储在两个中。下面的代码在C中 - 它将在C ++中工作,但你可能想要考虑使用c ++等价物 - 但它背后的想法并没有改变。

通过“存储两种形式”,我的意思是你可以有一个像:

这样的结构
typedef struct {
    int ival;
    char sval[sizeof("-2147483648")]; // enough for 32-bits
    int dirtyS;
} tIntStr;

并传递此结构(或其地址)而不是整数本身。

通过使用宏或内联函数,如:

inline void intstrSetI (tIntStr *is, int ival) {
    is->ival = i;
    is->dirtyS = 1;
}
inline char *intstrGetS (tIntStr *is) {
    if (is->dirtyS) {
        sprintf (is->sval, "%d", is->ival);
        is->dirtyS = 0;
    }
    return is->sval;
}

然后,要设置该值,您将使用:

tIntStr is;
intstrSetI (&is, 42);

每当你想要字符串表示时:

printf ("%s\n" intstrGetS(&is));
fprintf (logFile, "%s\n" intstrGetS(&is));

这样做的好处是只在需要时才计算字符串表示(上面的fprintf不必重新计算字符串表示,只有printf才会重新计算。)

  

这是我在SQL中使用预先计算的列和触发器的类似技巧。这个想法是你只在需要时进行计算。因此,用于保存索引的小写姓氏的额外列以及用于计算它的插入/更新触发器通常比select lower(non_lowercased_last_name)更有效。这是因为它会在所有读数中分摊计算成本(在写入时完成)。

从这个意义上讲,如果您的代码配置文件是set-int/use-string/set-int/use-string...,则没有什么优势。但是,如果它是set-int/use-string/use-string/use-string/use-string...,你将获得性能提升。

当然,这需要一个成本,只需要额外的额外存储空间,但大多数性能问题归结为空间/时间权衡。

并且,如果确实想要避免使用字符串,您仍然可以使用相同的方法(仅在需要时计算),只是计算(和结构)会有所不同。


顺便说一句:您可能希望使用库函数来执行此操作,而不是手工编写自己的代码。库函数通常会进行大量优化,可能比编译器可以从代码中生成的更多(尽管当然不能保证)。

考虑到用例有限,itoa(如果有的话)也可能会优于sprintf("%d")。但是,您应该测量,而不是猜测!不仅仅是库函数,还有整个解决方案(以及其他解决方案)。

答案 3 :(得分:1)

过早优化的蠢事。如果分析证明它很重要,那么一定要将你的算法与itoa进行比较 - 在​​内部它可能会使用一些你无法从C ++明确访问的CPU指令,而你的编译器的优化器可能不够聪明(例如AAM) ,在保存mod结果时div。)。实验(和基准测试)自己编写汇编程序。您可能需要深入研究ITOA的汇编实现(这与您要求的不同,但可能会建议最佳的CPU指令)。

答案 4 :(得分:1)

是的,有一种更有效的方法,但不是便携式的。英特尔的FPU具有特殊的BCD格式编号。因此,您所要做的就是调用相应的汇编程序指令,将ST(0)转换为BCD格式并将结果存储在内存中。指令名称为FBSTP

答案 5 :(得分:1)

使用“数字”00 - 99,看到基础100解决方案也可以正常工作,这是相当微不足道的。在每次迭代中,您都需要%100来生成这样的数字对,从而将步数减半。权衡是您的数字表现在是200个字节而不是10个。但是,它很容易适合L1缓存(显然,这仅适用于您转换大量数字,但无论如何效率都没有问题)。此外,您可能最终得到一个前导零,如“0128”。

答案 6 :(得分:0)

从数学上讲,整数的小数位数是1+int(log10(abs(a)+1))+(a<0);

您不会使用字符串,而是通过浮点和日志函数。如果您的平台具有任何类型的FP加速器(每台PC或类似设备)都不会有什么大不了的,并且会击败任何“基于sting”的算法(这远远超过迭代除以10和计数)