The following macro
#define MS_TO_TICKS(ms) ( ( (float)(ms)/ MILLISECONDS_PER_SECOND) * clkRate() )
converts a value in milliseconds to the correct number of clock ticks. For some reason, if I store the result in a signed integer, i sometimes get a different value than if I store in an unsigned integer.
The code below illustrates the problem, and outputs the following:
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
This is running on a Core i7 processor, and compiled using gcc as follows:
ccpentium -g -mtune=pentium4 -march=pentium4 -nostdlib -fno-builtin -fno-defer-pop \
-ansi -Wall -Werror -Wextra -Wno-unused-parameter -MD -MP
I don't see the same behaviour using https://ideone.com/HaJVSJ
What is going on??
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==
As requested, assembly as output from compiler. I simplified the code slightly to:
int convertToSigned(int ms)
{
return MS_TO_TICKS(ms);
}
unsigned int convertToUnsigned(int ms)
{
return MS_TO_TICKS(ms);
}
Assembler (snippet) for convertToSigned:
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
and for 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