7

I realize this question could be processor dependent, but hopefully someone can point me in the right direction. For the life of me, I cannot figure out how to convert an unsigned long long int representing nanoseconds to a double representing seconds in C (I'm using a 32-bit big-endian PowerPC 405 for this particular test, and a GNU C99 compiler).

I've tried:

unsigned long long int nanoseconds = 1234567890LLU;
double nanoseconds_d = nanoseconds*1e-9;

Also:

nanoseconds_d = ((double) nanoseconds)*1e-9;

For both cases, I just get 0. What am I doing wrong here?

EDITED TO ADD FULL EXAMPLE

#include <stdio.h>
#include <stdlib.h>

int
main( int argc, char *argv[] )
{
    unsigned long long int nanoseconds = 1234567890LLU;
    double nanoseconds_d = nanoseconds * 1e-9;
    printf("%g\n", nanoseconds_d);

    return 0;
}

MAKEFILE

SRCS    = simple.c    
INCLUDE := -I$(PWD)            
CFLAGS  := -O0 -g3 -Wall -fmessage-length=0 -mhard-float -fsigned-char -D_REENTRANT
LIBS    := -lc

OBJS = $(SRCS:.c=.o)
PROG = $(SRCS:.c=).out

all: $(PROG)

$(PROG): $(OBJS)
    @echo "Linking object files with output."
    $(CC) -o $(PROG) $(OBJS) $(LIBS)
    @echo "Linking complete."

$(OBJS): $(SRCS)
    @echo "Starting compilation."
    $(CC) $(CFLAGS) $(INCLUDE) -c $<
    @echo "Compilation complete."   

clean::
    @$(RM) *.o *.out
shansen
  • 317
  • 1
  • 2
  • 12
  • 2
    Works fine here. What is the nonsense value, and how are you printing it? – Fred Foo May 23 '13 at 14:45
  • 3
    You might have stumbled on a compiler bug. Converting a 64-bit unsigned value to `double` would be done with a sequence of several instructions (as opposed to just one) and this little-used sequence would be wrong in at least some cases for your compiler. As a test/workaround, try summing the results of two conversions 32-bit -> double. – Pascal Cuoq May 23 '13 at 14:54
  • Pascal, I think you're on to something. It works fine if I sum two long ints and then convert to double. – shansen May 23 '13 at 14:59
  • Please show us this "nonsense value". – Keith Thompson May 23 '13 at 15:13
  • I have been unable to duplicate the nonsense value, which is the reason I have not posted it. I am getting 0 for every conversion I try. The nonsense value must have been a typo or something, apologies. – shansen May 23 '13 at 15:14
  • I see no problem in the subset of the code that you've shown us. A short self-contained example could also be helpful. You haven't shown us a complete program; you might be omitting something that you don't know is relevant. – Keith Thompson May 23 '13 at 15:15
  • Full example works when compiled natively on the PowerPC target. It fails (nanoseconds_d == 0) when cross compiled with powerpc-405-linux-gnu-gcc on my 64-bit Windows machine. – shansen May 23 '13 at 15:23
  • The program, Makefile and all works fine on X86-linux (hardly a surprise). – Adrian Ratnapala May 23 '13 at 15:25
  • You should avoid that transformation as much as possible because it can changes your numbers value when you try to take back your values if they are too big and after 15 digits you lose your precision too. – oknsnl Sep 02 '14 at 06:40

2 Answers2

4

Works here when using %g to print

#include <stdlib.h>
#include <stdio.h>

int main(){
    unsigned long long int nanoseconds = 1234567890LLU;
    double nanoseconds_d = nanoseconds*1e-9;
    printf("%g\n", nanoseconds_d);

    nanoseconds_d = ((double) nanoseconds)*1e-9;
    printf("%g\n", nanoseconds_d);
}

outputs

1.23457
1.23457
FDinoff
  • 30,689
  • 5
  • 75
  • 96
0

It turns out that the version of cross gcc I was using had a bug that had to do with soft vs. hard floating point. Therefore, the cast from unsigned long long to double wasn't working properly, causing the issue.

shansen
  • 317
  • 1
  • 2
  • 12