ThinkC Dividing two unsigned long int to double?

Relating to ThinkC Development

eric

Administrator
Staff member
Sep 2, 2021
1,328
2,307
113
MN
bluescsi.com
In ThinkC 6:
C:
main()
{
    unsigned long int data_size, remaning_size;
   
    data_size = 12345;
    remaning_size = 2345;
   
    printf("%f\n", (data_size - remaning_size) / data_size);
    // expected: 0.810044
    // actual:   0.000000
}

/*
    Tried:
    casting each element to double, eg ((double)data_size - remaning_size) / data_size) - no go
    adding 0.0 - (data_size + 0.0 - rem_size) / data_size // this oddly works in the debug window, but not via printf  
    pulling hair out
*/

I'm at a loss why this isn't working - @jcs tried this in ThinkC 5 and it works. What's going on here in ThinkC 6?
 
In 'normal' C, it is supposed to gives 0 - all the operations are done with integer operations, even if you display the resulting bit-pattern as a floating-point value (which may expect 8 or 10 bytes but an unsigned long int is likely to be only 4 bytes).
If you convert the values to some floating-point representation first, then it should work, provided the conversion specifier/length modifier in printf() is adequate. Whether the C promotion rules are respected when you do operations between values of different types is anyone's guess - they should be, but we're in the early days of C on non-UNIX system here.

Of course early C compilers may do weird things. What you could try is to explicitly convert everything to double (or even long double if you're compiling for a hardware FPU, and using a L length modifier in printf ... if that's supported!), do the computation, then do the printf(). If that works, you can start removing intermediate steps to figure out what's going on in that specific C compiler...
 
This is legit weird. I just tried it too. Cast to double first should work, but you tried that (and I tried it too).

Very oddly, if I change “unsigned long” to just “long”, it works.

Are you including #stdio.h and not just getting an automatically generated prototype for printf? I assume yes …. Hmmm.
 
  • Like
Reactions: eric
Can you provide the syntax you'd suggest to do such conversion? I feel like I've tried every combination I know.

Just initialize some variables explicitly:

main()
{
unsigned long int data_size, remaning_size;
double ds_d, rs_d, ds_minus_rs_d, result_d;

data_size = 12345;
remaning_size = 2345;

ds_d = data_size;
rs_d = remaning_size;
ds_minus_rs_d = ds_d - rs_d;
result_d = ds_minus_rs_d / ds_d;

printf("%f\n", result_d);
// expected: 0.810044
// actual: dunno :)
}

if _that_ doesn't work, try printing the intermediate values one by one to see where it fails (or use a step-by-step debugger if printf() is really unreliable).

edit: some of the intermediate values will only exist with old compilers that don't optimize well; most modern one will just remove everything but the last value. To avoid that, you can define argv/argv and initialize data_size/remaning_size with atoi(argv[k]) when argv is big enough, which prevent such optimizations and make it easier to test multiple values. Assuming your libc contains atoi(), that is...
 
I have no idea what’s up here but I think THINK C 6 is having trouble adding a double to an unsigned long. Look:

1664383686320.png
 
Just look at the 68K assembly - it will be immediately obvious what the problem is. If it's a compiler bug, then you will see it. Also, you may have better luck with the extended data type...or not. I forget...but will try it.

Also, Think C has compiler options for code optimization and also native floating point. It's entirely possible that the presence or absence of those features is affecting the outcome. Yoiu could try disabling code optimization and enabling native floating point support.

I just had a quick look and there are also settings for 8-byte doubles and 881/020 code, etc. You could be hitting a compiler issue.
 
Last edited:
Well I don’t really know how the _FP68K package works absent reading the Apple Numerics Guide or something, but the disassembly is pretty opaque. It’s pushing pointers to the params, then pushing an opcode and calling _FP68K (twice, in the first ‘d1’ example … presumably the first time to convert the unsigned long to a double).
 
My C is definitely rusty, but in the d1 line above, isn't the () going to resolve before the +? Shouldn't it be: (double)(a + b)?

I guess I have to go look at a freaking precedence table or something.

Oh, I see -- never mind - that's what you were trying to show. I will look at the 68K later - can't do it right now. Plus, Think C is crashing on SheepShaver.
 
Last edited:
My money is on compiler error. Trying it with 0 + 0 …..

1664401701507.png


And by the way, if I enable “generate 68881 code” in Compiler Options it works fine, so I think something is wrong with the way THINK 6 is calling SANE.
 
Last edited:
  • Like
Reactions: BFEXTU
Back