我知道你可以使用模数和除法得到数字的数字。以下是我过去的做法:( 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风格还是其他?
感谢。我问,因为我想要在我的个人项目中做这件事,我想尽可能高效地做到这一点。
非常感谢任何帮助和/或见解。
答案 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和计数)