OSDK C compiler : are floats supported?

Questions, bug reports, features requests, ... about the Oric Software Development Kit. Please indicate clearly in the title the related element (OSDK for generic questions, PictConv, FilePack, XA, Euphoric, etc...) to make it easy to locate messages.

Post Reply
User avatar
NekoNoNiaow
Flight Lieutenant
Posts: 272
Joined: Sun Jan 15, 2006 10:08 pm
Location: Montreal, Canadia

OSDK C compiler : are floats supported?

Post by NekoNoNiaow » Wed Apr 10, 2019 3:46 am

Hello kitties,

While attempting to use float values in my program I encountered a few weird issues with numerical values which led me to wonder if float values were correctly supported by the C compiler of the OSDK.
In order to verify that floats were properly supported I wrote the following program:

Code: Select all

{
	long  testl = 224;
	float testlf = (float)testl;
	long  clockl = clock();
	float clockf = 123;
	float clocklf = clockl;
	float seconds = clockf / (float)CLOCKS_PER_SEC;
	float seconds2 = clockf / CLOCKS_PER_SEC;
	clock_t TIME0, TIME1;
	printf("testl:    %d\n", testl);
	printf("testlf:   %f\n", testlf);
	printf("clockl:   %d\n", clockl);
	printf("clockf:   %f\n", clockf);
	printf("clocklf:  %f\n", clocklf);
	printf("seconds:  %f\n", seconds);
	printf("seconds2: %f\n", seconds2);
	TIME0 = clock();
	{
		int a=0;
		int i;
		for (i = 0; i < 0x7FF; ++i)
		{
			printf("a:%d    \r", a);
			a++;
		}
		printf("\n");
	}
	TIME1 = clock();
	printf("duration : %fs\n", (double)( TIME1-TIME0 ) / CLOCKS_PER_SEC);
}
and... it turns out that well, floats are mostly non working. (Cf attached image below.) :shock:
OSDK1.13 float test.png

Especially, conversions between integer values and floats seem to produce complete gibberish.
Is this a known limitation of the compiler or is this a bug?

User avatar
Dbug
Site Admin
Posts: 2929
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: OSDK C compiler : are floats supported?

Post by Dbug » Wed Apr 10, 2019 5:08 pm

I believe Fabrice fixed some issues in the floats recently, maybe we can try that again when the integration of the new code is done.

User avatar
Dbug
Site Admin
Posts: 2929
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: OSDK C compiler : are floats supported?

Post by Dbug » Wed Apr 10, 2019 6:48 pm

Would be nice if you could provide the source code.
Like the complete project that I can just recompile, because else it's just guess work.

User avatar
NekoNoNiaow
Flight Lieutenant
Posts: 272
Joined: Sun Jan 15, 2006 10:08 pm
Location: Montreal, Canadia

Re: OSDK C compiler : are floats supported?

Post by NekoNoNiaow » Fri Apr 12, 2019 2:22 am

Yup!
Here it is:

The code:

Code: Select all


#include <time.h>

void main(void)
{
	long  testl = 224;
	float testlf = (float)testl;
	long  clockl = clock();
	float clockf = 123;
	float clocklf = clockl;
	float seconds = clockf / (float)CLOCKS_PER_SEC;
	float seconds2 = clockf / CLOCKS_PER_SEC;
	clock_t TIME0, TIME1;
	printf("testl:    %d\n", testl);
	printf("testlf:   %f\n", testlf);
	printf("clockl:   %d\n", clockl);
	printf("clockf:   %f\n", clockf);
	printf("clocklf:  %f\n", clocklf);
	printf("seconds:  %f\n", seconds);
	printf("seconds2: %f\n", seconds2);
	TIME0 = clock();
	{
		int a=0;
		int i;
		for (i = 0; i < 0x7FF; ++i)
		{
			printf("a:%d    \r", a);
			a++;
		}
		printf("\n");
	}
	TIME1 = clock();
	printf("duration : %fs\n", (double)( TIME1-TIME0 ) / CLOCKS_PER_SEC);
	get();
}
and the corresponding osdk_config.bat:

Code: Select all

SET OSDKADDR=$600
SET OSDKNAME=FLOATS
SET OSDKFILE=main
SET OSDKCOMP=-O0

User avatar
NekoNoNiaow
Flight Lieutenant
Posts: 272
Joined: Sun Jan 15, 2006 10:08 pm
Location: Montreal, Canadia

Re: OSDK C compiler : are floats supported?

Post by NekoNoNiaow » Fri Apr 12, 2019 3:13 am

Ohhhh, I think I have found the actual issue and it might not be float related at all. :D

Gimme a few minutes and I will get back with more details. ;)

Edit: yup, not related to float, there is something fishy with integer computations as soon as a call to clock() is involved. :shock:

Here's a small test program:

Code: Select all

void main()
{
  typedef unsigned long time_t;
  clock_t clockValue;
  time_t	seconds, seconds_rounded, mod;
  int blob;

  blob = 100;
  printf("blob/100 : %d\n", blob/100);
  printf("blob/CLOCKS_PER_SEC : %d\n", blob/CLOCKS_PER_SEC);
  printf("\n");
  clockValue = 2;
  printf("clockValue : %d\n", clockValue);
  printf("clockValue*100 : %d\n", clockValue*100);
  printf("clockValue*100/100 : %d\n", clockValue*100/100);
  printf("\n");
  seconds = clockValue * 100;
  printf("seconds(=clockValue*100) : %d\n", seconds);
  printf("seconds/CLOCKS_PER_SEC : %d\n", seconds/CLOCKS_PER_SEC);
  printf("\n");
  clockValue = clock();
  printf("clockValue : %d\n", clockValue);
  printf("clockValue*100 : %d\n", clockValue*100);
  printf("clockValue*100/100 : %d\n", clockValue*100/100);
  printf("\n");
  blob = 300;
  printf("blob/100 : %d\n", blob/100);
  printf("blob/CLOCKS_PER_SEC : %d\n", blob/CLOCKS_PER_SEC);
  printf("\n");
  seconds = clockValue * 100;
  printf("seconds(=clockValue*100) : %d\n", seconds);
  printf("seconds/CLOCKS_PER_SEC : %d\n", seconds/CLOCKS_PER_SEC);
 }
And here its actual output:
OSDK1.13 int test.png
Notice that, once clock() has been called, the computations involving the variable "seconds" are nonsensical.
However, the same computations involving the variable "blop" stay undisturbed, maybe because it is an "int" rather than an "unsigned long"?

Edit2: The "unsigned long" hypothesis is wrong, cf below.

Here is a program which demonstrates more precisely that the problem comes from assigning the result of a call to clock() to a variable and that it propagates to other variables to which this value is assigned. :D

Here it is:

Code: Select all

void main()
{
  //clock_t clockValue;
  unsigned long clockValue;
  unsigned long blob_l;

  clockValue = 2;

  blob_l = clockValue * 100;
  printf("blob_l : %d\n", blob_l);
  printf("blob_l/100 : %d\n", blob_l/100);
  printf("\n");

  clockValue = clock();
  printf("clockValue : %d\n", clockValue);
  printf("clockValue*100 : %d\n", clockValue*100);
  printf("clockValue*100/100 : %d\n", clockValue*100/100);
  printf("\n");

  blob_l = 2 * 100;
  printf("blob_l : %d\n", blob_l);
  printf("blob_l/100 : %d\n", blob_l/100);
  printf("\n");

  blob_l = clockValue * 100;
  printf("blob_l : %d\n", blob_l);
  printf("blob_l/100 : %d\n", blob_l/100);
  printf("\n");
} 
And its nonsensical output:
OSDK1.13 int test final.png
As you can see, if blob_l is assigned the same value as clockValue * 100, it computes just fine.
But if it is assigned clockValue*100, when clockValue comes from clock(), then blob_l computations get messed up even though blob_l's value is actually still correct. :shock:

I initially suspected that clock() was corrupting memory or something but it modifies nothing but the A and X registers so I doubt that is the case.
My intuition is that the issue lies with how the compiler handles variable assignation. I have not (yet) looked at the generated assembly code though.

Edit3: just looked at the generated assembly code and I cannot for the hell of me figure out what is wrong. The code seems to properly assign the variables and call the proper mul and div functions, yet the result is wrong when the computation depends in some way from the result of clock()...
It is late and I am tired so I will stop there for now. ;)

User avatar
iss
Squad Leader
Posts: 852
Joined: Sat Apr 03, 2010 5:43 pm
Location: Bulgaria
Contact:

Re: OSDK C compiler : are floats supported?

Post by iss » Fri Apr 12, 2019 8:02 am

The problem is 'overflow'. Try this function:

Code: Select all

void sizes(void)
{
  printf("char   : %d\n", sizeof(char  ));
  printf("short  : %d\n", sizeof(short ));
  printf("int    : %d\n", sizeof(int   ));
  printf("long   : %d\n", sizeof(long  ));
  printf("float  : %d\n", sizeof(float ));
  printf("double : %d\n", sizeof(double));
  printf("\n\npress a key...");
  getchar();
  printf("\n");
}
Screenshot_20190412_093810.png
So, long and int are the same size - 2 bytes!
And in your code when clockValue gets bigger than 655 things start to be strange in clockValue*100,
because the result is > 65535. Also the same limitation has obviously the 'printf' function itself.
Try this code:

Code: Select all

#define F(x)  ((x)/1000),((x)%1000)
void test_clock(void)
{
  //clock_t clockValue;
  unsigned long clockValue;
  unsigned long blob_l;

  clockValue = 2;

  blob_l = clockValue * 100;
  printf("blob_l : %d%d\n", F(blob_l));
  printf("blob_l/100 : %d%d\n", F(blob_l/100));
  printf("\n");

  clockValue = 655;//clock();
  printf("clockValue : %d%d\n", F(clockValue));
  printf("clockValue*100 : %d%d\n", F(clockValue*100));
  printf("clockValue*100/100 : %d%d\n", F(clockValue*100/100));
  printf("\n");

  blob_l = 2 * 100;
  printf("blob_l : %d%d\n", F(blob_l));
  printf("blob_l/100 : %d%d\n", F(blob_l/100));
  printf("\n");

  blob_l = clockValue * 100;
  printf("blob_l : %d%d\n", F(blob_l));
  printf("blob_l/100 : %d%d\n", F(blob_l/100));
  printf("\n");
} 
playing with 655 - you will see how the results will change... hope this helps.

User avatar
iss
Squad Leader
Posts: 852
Joined: Sat Apr 03, 2010 5:43 pm
Location: Bulgaria
Contact:

Re: OSDK C compiler : are floats supported?

Post by iss » Fri Apr 12, 2019 8:07 am

... and you can adjust the line:

Code: Select all

#define F(x)  ((x)/1000),((x)%1000)
with different coefficient (i.e. 1,10,100...) to 'fit' better the expected result :).

User avatar
NekoNoNiaow
Flight Lieutenant
Posts: 272
Joined: Sun Jan 15, 2006 10:08 pm
Location: Montreal, Canadia

Re: OSDK C compiler : are floats supported?

Post by NekoNoNiaow » Sat Apr 13, 2019 12:55 am

The problem cannot be overflow, I initially thought that was the case which is why I printed the intermediary values and they all fit snugly into a 16 bit integer.

All computations fit the same pattern:
  • set a variable to a value of 200 (in the latter case, that is obtained by "clock() * 100").
  • this value fits comfortably within a 16 bit integer (max positive value 32767, min negative -32768)
  • then the variable is divided by 100 or CLOCKS_PER_SEC (which is also 100).
  • some of these divisions obtain the proper value (2) and some go to kitten's heaven (200 / 100 => 646)
You say that clock() returns 655 but it does not, it called immediately after reset and reaches actually only 2.
Hence the multiplied value reaches 200 in all cases. Then we divide that by 100 we get 646, but only if that value was set via a variable which got its value from calling clock().

To illustrate what is going on, I will comment the program I posted below:

Code: Select all

void main()
{
  unsigned long clockValue;
  unsigned long blob_l;

  clockValue = 2;                                     // ok, clear enough

  blob_l = clockValue * 100;                          // blob_l is now 200
  printf("blob_l : %d\n", blob_l);                    // printf confirms it
  printf("blob_l/100 : %d\n", blob_l/100);            // prints correct result : 200/100 = 2
  printf("\n");

  clockValue = clock();                               // let's read the clock
  printf("clockValue : %d\n", clockValue);            // printf tells us "clockValue : 2"
  printf("clockValue*100 : %d\n", clockValue*100);    // printf tells us the obvious 2 * 100 = 200
  printf("clockValue*100/100 : %d\n", clockValue*100/100);  // printf output : "clockValue*100/100 : 653" -> what is going on?
  printf("\n");

  blob_l = 2 * 100;                           // let's try again, blob_l is 200
  printf("blob_l : %d\n", blob_l);            // printf confirms
  printf("blob_l/100 : %d\n", blob_l/100);    // printf confirms 200/100=2
  printf("\n");

  blob_l = clockValue * 100;                  // set blob_l to same value but from another source
  printf("blob_l : %d\n", blob_l);            // printf output confirms -> "blob_l : 200"
  printf("blob_l/100 : %d\n", blob_l/100);    // printf output : "blob_l/100 : 653"
  printf("\n");                               // --> huh oh, back to nonsense
}
There is no overflow involved there. Just that when the value is assigned directly, the computation is correct.
And when the value is assigned from the result of clock(), the computation ends up being wrong.

Pretty strange and quirky. ;)

User avatar
NekoNoNiaow
Flight Lieutenant
Posts: 272
Joined: Sun Jan 15, 2006 10:08 pm
Location: Montreal, Canadia

Re: OSDK C compiler : are floats supported?

Post by NekoNoNiaow » Sat Apr 13, 2019 1:38 am

Here is a much simpler program which exhibits the issue:

Code: Select all

#include <time.h>
void main()
{
  unsigned long clockValue;
  clockValue = clock();
  //clockValue = 1;
  printf("clockValue         : %d\n", clockValue);
  printf("clockValue*100     : %d\n", clockValue*100);
  printf("clockValue*100/100 : %d\n", clockValue*100/100);
  printf("\n");
}
As is, this gives the following output:

Code: Select all

clockValue         : 1
clockValue*100     : 100
clockValue*100/100 : 654  <- woozah ! what is going on?   \(oO)/
As you see, there is a commented line, if you uncomment it, instead we get the correct result:

Code: Select all

clockValue         : 1
clockValue*100     : 100
clockValue*100/100 : 1      <- correct value this time, even though clockValue is the same value as for the first run!
So, even though, the only thing we do is overwrite the value of clockValue with the same exact content, that is enough to fix the result.
Aliens! I tell you! There are aliens in our compiler! :)

Edit: I compared the buggy/not-buggy generated assembly language of the two above runs.

The two linked.s files produces with the commented line and uncommented are *very* close to one another except for a few very short sections which do not even seem directly related with the error on the last line...

Here are the differing parts, commented as best as I could given my limited knowledge of the compiler's internals:

Code: Select all

buggy                  not buggy

_main                  _main               ;
  ldx #8                 ldx #8            ;
  lda #0                 lda #0            ;
  jsr enter              jsr enter         ;

  ldx #<(_clock)         ldx #<(_clock)    ; <- *tmp0 = clock  (16 bit)
  stx tmp0               stx tmp0          ;
  lda #>(_clock)         lda #>(_clock)    ;
  sta tmp0+1             sta tmp0+1        ;

  .(                     .(                ;
  lda tmp0               lda tmp0          ; <- self modifying code!
  sta call+1             sta call+1        ;
  lda tmp0+1             lda tmp0+1        ;
  sta call+2             sta call+2        ;
  ldy #0                 ldy #0            ;
call                   call                ;
  jsr 0000               jsr 0000          ; <- call clock()
 .)                     .)                 ;
 stx tmp0               stx tmp0           ; <- store the result in *tmp0
  sta tmp0+1             sta tmp0+1        ;    which is the "clockValue" variable

  clc                    clc               ;
  lda 0+(fp)             lda 0+(fp)        ; <- *tmp1 = *fp + 6  (16 bit)
  adc #6                 adc #6            ;
  sta tmp1               sta tmp1          ;
  lda 1+(fp)             lda 1+(fp)        ;
  adc #0                 adc #0            ;
  sta tmp1+1             sta tmp1+1        ;

  ldy #0                 ldy #0            ; <- *tmp1 = *tmp0  (16 bit)
  lda tmp0               lda tmp0          ;
  sta (tmp1),y           sta (tmp1),y      ;    this makes a copy
  iny                    iny               ;    of clockValue to *tmp1
  lda tmp0+1             lda tmp0+1        ;
  sta (tmp1),y           sta (tmp1),y      ;    clockValue is now in *tmp1 AND *tmp0

                         clc               ; <- *tmp0 = *fp + 6 (16 bit)
                         lda 0+(fp)        ;
                         adc #6            ;
                         sta tmp0          ;
                         lda 1+(fp)        ;
                         adc #0            ;
                         sta tmp0+1        ;

                         ldx #<(1)         ; <- *tmp1 = 1  (16 bit)
                         stx tmp1          ;
                         lda #>(1)         ;    this is our "clockValue = 1" assignment
                         sta tmp1+1        ;

                         ldy #0            ; <- *tmp0 = *tmp1  (16 bit)
                         lda tmp1          ;
                         sta (tmp0),y      ;    copy clockValue (*tmp1) to tmp0
                         iny               ;
                         lda tmp1+1        ;    clockValue is (again) in *tmp1 AND *tmp0
                         sta (tmp0),y      ;

  ldx #<(Lmain66)        ldx #<(Lmain66)   ; <- LMain66 = "clockValue : %d\n"
  stx tmp0               stx tmp1          ;    *tmp0/1 = "clockValue : %d\n"
  lda #>(Lmain66)        lda #>(Lmain66)   ;    IMPORTANT: clockValue is now only in
  sta tmp0+1             sta tmp1+1        ;    left: *tmp1    right: *tmp0

  lda tmp0               lda tmp1          ; <- this stores the above string on a pseudo stack
  ldy #0                 ldy #0            ;
  sta (sp),y             sta (sp),y        ;
  iny                    iny               ;
  lda tmp0+1             lda tmp1+1        ;
  sta (sp),y             sta (sp),y        ;    *sp = *tmp0/1 = "clockValue : %d\n"

  clc                                      ; <- *tmp0 = *fp + 6  (16 bit)
  lda 0+(fp)                               ;
  adc #6                                   ;
  sta tmp0                                 ;
  lda 1+(fp)                               ;
  adc #0                                   ;
  sta tmp0+1                               ;

  ldy #0                 ldy #0            ; <- *tmp0 = *tmp0  (16 bit)
  lda (tmp0),y           lda (tmp0),y      ;
  tax                    tax               ;
  iny                    iny               ;
  lda (tmp0),y           lda (tmp0),y      ;
  stx tmp0               stx tmp0          ;
  sta tmp0+1             sta tmp0+1        ;

  lda tmp0               lda tmp0          ; <- *(sp+2) = *tmp0  (16 bit)
  ldy #2                 ldy #2            ;    this stores the second parameter for printf
  sta (sp),y             sta (sp),y        ;
  iny                    iny               ;   uses tmp0 for both but clockValue is in tmp1
  lda tmp0+1             lda tmp0+1        ;   for left side, and tmp0 for right
  sta (sp),y             sta (sp),y        ;   ?? is that ok ??

  ldx #<(_printf)        ldx #<(_printf)   ; <- *tmp0 = printf
  stx tmp0               stx tmp0          ;
  lda #>(_printf)        lda #>(_printf)   ;
  sta tmp0+1             sta tmp0+1        ;

  .(                       .(              ; <- self modifying code
  lda tmp0                 lda tmp0        ;
  sta call+1               sta call+1      ;    calls printf
  lda tmp0+1               lda tmp0+1      ;
  sta call+2               sta call+2      ;
  ldy #4                   ldy #4          ;
call                     call              ;
  jsr 0000                 jsr 0000        ;
 .)                       .)               ;
I have also attached the two resulting linked.s files in case someone is willing to give them a look. ;)
Attachments
bug div.zip
(4.86 KiB) Downloaded 15 times

Post Reply