【发布时间】:2014-05-09 15:04:51
【问题描述】:
下面的宏
#define MS_TO_TICKS(ms) ( ( (float)(ms)/ MILLISECONDS_PER_SECOND) * clkRate() )
将以毫秒为单位的值转换为正确的时钟滴答数。出于某种原因,如果我将结果存储在有符号整数中,有时会得到与存储在无符号整数中不同的值。
下面的代码说明了问题,并输出如下:
Milliseconds: 7
Expected val: 14
Signed Int : 14 //OK
Unsigned Int: 14 //Still OK
Floating Pnt: 14.0000000000000
Double Precn: 14.0000004321337
Direct Macro: 14.0000004321337
Milliseconds: 10
Expected val: 20
Signed Int : 20 //Expected value, looks like it rounded up
Unsigned Int: 19 //Rounded Down? What?????
Floating Pnt: 20.0000000000000
Double Precn: 19.9999995529652
Direct Macro: 19.9999995529652
这是在 Core i7 处理器上运行,并使用 gcc 编译如下:
ccpentium -g -mtune=pentium4 -march=pentium4 -nostdlib -fno-builtin -fno-defer-pop \
-ansi -Wall -Werror -Wextra -Wno-unused-parameter -MD -MP
我没有看到使用 https://ideone.com/HaJVSJ 的相同行为
发生了什么事??
int clkRate()
{
return 2000;
}
const int MILLISECONDS_PER_SECOND = 1000;
#define MS_TO_TICKS(ms) ( ( (float)(ms)/ MILLISECONDS_PER_SECOND) * clkRate() )
void convertAndPrint(int ms)
{
int ticksInt;
unsigned ticksUint;
double ticksDbl;
float ticksFlt;
ticksInt = MS_TO_TICKS(ms);
ticksUint= MS_TO_TICKS(ms);
ticksFlt = MS_TO_TICKS(ms);
ticksDbl = MS_TO_TICKS(ms);
printf("Milliseconds: %i\n", ms);
printf("Expected val: %i\n",ms*2);
printf("Signed Int : %2i\n"
"Unsigned Int: %2u\n"
"Floating Pnt: %.13f\n"
"Double Precn: %.13f\n"
"Direct Macro: %.13f\n",
ticksInt,ticksUint,ticksFlt, ticksDbl, MS_TO_TICKS(ms));
}
void weirdConversionDemo(void)
{
convertAndPrint(7);
convertAndPrint(10);
}
==EDIT==
根据要求,汇编作为编译器的输出。我将代码稍微简化为:
int convertToSigned(int ms)
{
return MS_TO_TICKS(ms);
}
unsigned int convertToUnsigned(int ms)
{
return MS_TO_TICKS(ms);
}
convertToSigned 的汇编程序 (sn-p):
fildl 8(%ebp)
movl MS_PER_SECOND, %eax
pushl %eax
fildl (%esp)
leal 4(%esp), %esp
fdivrp %st, %st(1)
fstps -4(%ebp)
call clkRate
pushl %eax
fildl (%esp)
leal 4(%esp), %esp
fmuls -4(%ebp)
fstps -8(%ebp)
movss -8(%ebp), %xmm0
cvttss2si %xmm0, %eax
对于 convertToUnsigned
fildl 8(%ebp)
movl MS_PER_SECOND, %eax
pushl %eax
fildl (%esp)
leal 4(%esp), %esp
fdivrp %st, %st(1)
fstps -20(%ebp)
call clkRate
pushl %eax
fildl (%esp)
leal 4(%esp), %esp
fmuls -20(%ebp)
fnstcw -2(%ebp)
movzwl -2(%ebp), %eax
movb $12, %ah
movw %ax, -4(%ebp)
fldcw -4(%ebp)
fistpll -16(%ebp)
fldcw -2(%ebp)
movl -16(%ebp), %eax
movl -12(%ebp), %edx
【问题讨论】:
-
带符号的 int 是 20 比 unsigned int 是 19 更让我惊讶。
-
我同意....虽然我的评论说“预期价值”,但我真正的意思是“我想要的价值”。我期待 19
-
GCC 的选项
-S允许查看生成的程序集。您能否向我们展示为您的程序生成的程序集的相关部分?另外请在某处添加printf("FLT_EVAL_METHOD:%d\n", (int)FLT_EVAL_METHOD);。我相信FLT_EVAL_METHOD是在 math.h 中定义的。 -
是的,但可能要等到周末之后 :-)
-
在这种情况下,一种解决方法是移动除法,使宏现在为
((ms) * ((float)clkRate())/MILLISECONDS_PER_SECOND),但由于选择了 clkRate,这可能会奏效。此外,使用 round(MS_TO_TICKS(ms)) 似乎也做了正确的事情。
标签: c type-conversion