ThinkC Dividing two unsigned long int to double?

Relating to ThinkC Development

eric

Administrator
Staff member
Sep 2, 2021
835
1,340
93
MN
scsi.blue
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?
 

Melkhior

Tinkerer
Jan 9, 2022
98
49
18
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...
 

Crutch

Tinkerer
Jul 10, 2022
292
226
43
Chicago
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

Melkhior

Tinkerer
Jan 9, 2022
98
49
18
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...
 

Crutch

Tinkerer
Jul 10, 2022
292
226
43
Chicago
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
 

BFEXTU

Tinkerer
Jul 15, 2022
169
143
43
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:

Crutch

Tinkerer
Jul 10, 2022
292
226
43
Chicago
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).
 

BFEXTU

Tinkerer
Jul 15, 2022
169
143
43
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:

Crutch

Tinkerer
Jul 10, 2022
292
226
43
Chicago
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