我可以在 c 中编译时计算 pow(10,x) 吗?
是否可以在编译时计算 pow(10,x) ?
我有一个不支持浮点且整数除法缓慢的处理器。 我试图在编译时执行尽可能多的计算。 如果我将 x
和 C/pow(10,x)
作为参数传递(x 和 C 始终是常量整数,但它们是每次调用都有不同的常量)。 我想知道是否可以通过引入一个自动执行 1/pow(10,x)
的宏来减少这些函数调用的错误,而不是强迫程序员计算它?
有预处理器技巧吗? 我可以强制编译器优化库调用吗?
Is it possible to compute pow(10,x) at compile time?
I've got a processor without floating point support and slow integer division. I'm trying to perform as many calculations as possible at compile time. I can dramatically speed up one particular function if I pass both x
and C/pow(10,x)
as arguments (x and C are always constant integers, but they are different constants for each call). I'm wondering if I can make these function calls less error prone by introducing a macro which does the 1/pow(10,x)
automatically, instead of forcing the programmer to calculate it?
Is there a pre-processor trick? Can I force the compiler optimize out the library call?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
在溢出 int (甚至 long)之前,可能的值非常少。 为了清楚起见,把它做成一张桌子!
编辑:如果您使用浮点数(看起来像您),那么不,如果不实际编写在 make 进程中运行并将值输出到文件的代码,则不可能在编译时调用 pow() 函数(例如头文件),然后进行编译。
There are very few values possible before you overflow int (or even long). For clarities sake, make it a table!
edit: If you are using floats (looks like you are), then no it's not going to be possible to call the pow() function at compile time without actually writing code that runs in the make process and outputs the values to a file (such as a header file) which is then compiled.
GCC 将以足够高的优化级别执行此操作(-O1 为我执行此操作)。 例如:
在 -O1 -m32 处编译为:
这也无需强制转换即可工作 - 当然,您确实会在其中获得浮点加载指令,如 Linux ABI 在 FPU 寄存器中传递浮点返回值。
GCC will do this at a sufficiently high optimization level (-O1 does it for me). For example:
Compiles at -O1 -m32 to:
This works without the cast as well - of course, you do get a floating-point load instruction in there, as the Linux ABI passes floating point return values in FPU registers.
您可以使用 Boost.Preprocessor 来完成此操作:
http:// www.boost.org/doc/libs/1_39_0/libs/preprocessor/doc/index.html
代码:
You can do it with Boost.Preprocessor:
http://www.boost.org/doc/libs/1_39_0/libs/preprocessor/doc/index.html
Code:
实际上,通过利用 C 预处理器,您可以让它计算任何实
C
和积分x
的C pow(10, x)
。 请注意,正如@quinmars 所指出的,C 允许您使用科学语法来表达数值常量:用于常量。 考虑到这一点,再加上一点聪明,我们可以构造一个预处理器宏,它采用 C 和 x 并将它们组合成一个求幂标记:
现在可以将其用作常数数值:
Actually, by exploiting the C preprocessor, you can get it to compute
C pow(10, x)
for any realC
and integralx
. Observe that, as @quinmars noted, C allows you to use scientific syntax to express numerical constants:to be used for constants. With this in mind, and a bit of cleverness, we can construct a preprocessor macro that takes
C
andx
and combine them into an exponentiation token:This can now be used as a constant numerical value:
您可以使用科学计数法来表示浮点值,这是 C 语言的一部分。 它看起来像这样:
E
之前的数字(E
可能是大写或小写的1.602e-19
)是小数部分,其中E
之后的(带符号)数字序列是指数部分。 默认情况下,数字的类型为double
,但您可以附加浮点后缀(f
、F
、l 或
L
),如果您需要float
或long double
。我不建议将此语义打包到宏中:
You can use the scientific notation for floating point values which is part of the C language. It looks like that:
The number before the
E
( theE
maybe capital or small1.602e-19
) is the fraction part where as the (signed) digit sequence after theE
is the exponent part. By default the number is of the typedouble
, but you can attach a floating point suffix (f
,F
,l
orL
) if you need afloat
or along double
.I would not recommend to pack this semantic into a macro:
事实上,M4 是一个比 GCC 更强大的预处理器。 这两者之间的主要区别是 GCC 不是递归的,而 M4 是。 它使得诸如在编译时进行算术之类的事情成为可能(以及更多!)。 下面的代码示例就是您想要做的,不是吗? 我在一个文件源中将其变得庞大; 但我通常将 M4 的宏定义放在单独的文件中并调整我的 Makefile 规则。 这样,您的代码就可以避免丑陋的侵入性 M4 定义进入我在这里完成的 C 源代码中。
编译此代码示例的命令行使用 GCC 和 M4 从标准输入读取的功能。
希望这有帮助!
Actually, you have M4 which is a pre-processor way more powerful than the GCC’s. A main difference between those two is GCC’s is not recursive whereas M4 is. It makes possible things like doing arithmetic at compile-time (and much more!). The below code sample is what you would like to do, isn’t it? I made it bulky in a one-file source; but I usually put M4's macro definitions in separate files and tune my Makefile rules. This way, your code is kept from ugly intrusive M4 definitions into the C source code I've done here.
The command line to compile this code sample uses the ability of GCC and M4 to read from the standard input.
Hope this help!
如果您只需要在编译时使用该值,请使用科学记数法,如
pow(10, 2)
的 1e2如果您想在编译时填充值,然后在运行时使用它们,则只需使用查找表,因为有 只有 23 种不同的 10 次方可以在双精度下精确表示
您可以在运行时从上面的查找表中获取更大的 10 次方以快速得到结果不需要一次又一次地乘以 10,但结果只是一个接近 10 次方的值,就像您使用 10eX 且 X > 时一样。 22
如果不需要负指数,则可以删除最后一个分支。
如果内存有限,您还可以进一步减小查找表的大小。 例如,通过仅存储 10 的偶数次方并在指数为奇数时乘以 10,表大小现在只有一半。
If you just need to use the value at compile time, use the scientific notation like 1e2 for
pow(10, 2)
If you want to populate the values at compile time and then use them later at runtime then simply use a lookup table because there are only 23 different powers of 10 that are exactly representable in double precision
You can get larger powers of 10 at runtime from the above lookup table to quickly get the result without needing to multiply by 10 again and again, but the result is just a value close to a power of 10 like when you use 10eX with X > 22
If negative exponents is not needed then the final branch can be removed.
You can also reduce the lookup table size further if memory is a constraint. For example by storing only even powers of 10 and multiply by 10 when the exponent is odd, the table size is now only a half.
GCC 的最新版本(大约 4.3)添加了使用 GMP 和 MPFR 通过评估恒定的更复杂函数来进行一些编译时优化的功能。 这种方法使您的代码简单且可移植,并信任编译器来完成繁重的工作。
当然,它能做的事情是有限的。 这是更改日志中的说明的链接,其中包括一个列表受此支持的功能。 “pow”就是其中之一。
Recent versions of GCC ( around 4.3 ) added the ability to use GMP and MPFR to do some compile-time optimizations by evaluating more complex functions that are constant. That approach leaves your code simple and portable, and trust the compiler to do the heavy lifting.
Of course, there are limits to what it can do. Here's a link to the description in the changelog, which includes a list of functions that are supported by this. 'pow' is one them.
不幸的是,您无法使用预处理器来预先计算库调用。 如果 x 是整数,您可以编写自己的函数,但如果它是浮点类型,我看不到任何好的方法来做到这一点。
Unfortunately, you can't use the preprocessor to precalculate library calls. If x is integral you could write your own function, but if it's a floating-point type I don't see any good way to do this.
bdonlan 的重放非常准确,但请记住,只要您愿意在自己的自定义预处理器中解析和分析代码,您就可以执行在编译框中选择的几乎任何优化。 在大多数版本的 unix 中,覆盖调用编译器在调用编译器之前调用您自己的自定义步骤的隐式规则是一项微不足道的任务。
bdonlan's replay is spot on but keep in mind that you can perform nearly any optimization you chose on the compile box provided you are willing to parse and analyze the code in your own custom preprocessor. It is a trivial task in most version of unix to override the implicit rules that call the compiler to call a custom step of your own before it hits the compiler.