Pelles C forum

C language => Expert questions => Topic started by: eheredia2511 on September 14, 2010, 11:38:23 PM

Title: Assignment and Ternary Operator
Post by: eheredia2511 on September 14, 2010, 11:38:23 PM
Hi for all!

I have a problem with the ternary operator and assignment, as shown below (see the coments):

Code: [Select]
#include <stdio.h>
#include <stdlib.h>

#define MIN(x,y) ( (x<y) ? (x) : (y) )
#define MAX(x,y) ( (x>y) ? (x) : (y) )

#define NELEMS 50

double vetor[NELEMS];

int main(void)
{
double min=0.0, max=0.0, minx=0.0, maxx=0.0;

for(int i=0;i<NELEMS;i++)
vetor[i]=(double) (rand())/RAND_MAX*100;

min=vetor[0];
max=vetor[0];

double x = 0.0;

for(int i=1;i<NELEMS;i++) {

x = vetor[i];

// CASE 1: this code doesn´t work *********************
// min=MIN(min, x);
// max=MAX(max, x);

// Case 2: neither this *******************************
            min = (min > x ? x : min);
            max = (max < x ? x : max);

// Case 3: but this works *****************************
// if( min > x ) min = x;
// if( max < x ) max = x;

}

printf("\n\n");
printf("MIN =%8.4f MAX =%8.4f\n",min,max);
             printf("\n\n");

return EXIT_SUCCESS;
}

Cases 1 and 2 don´t work. Case 3 always works!

Why?

Thanks in advance...






Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 15, 2010, 03:01:31 AM
It's in the construction of your  ? conditional:

Where the goal is to return the lesser of two numbers try it as:

min = (x < y) ?  x : y;

If the condition  (x < y) is true ... you get the first value after the ?  If it is false you get the second.

Title: Re: Assignment and Ternary Operator
Post by: eheredia2511 on September 15, 2010, 03:28:14 AM
Thanks,

but the problem persists. See my code (case 1).

[]s

Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 15, 2010, 04:28:46 AM
Ok, maybe I'm not getting what the problem is. 

I corrected the bracketing in your "case 2" example and it ran perfectly, giving a string of random numbers showing low and high values...  I uncommented each case in turn and ran the program again and they all work. Mind you they were not terribly random... but it did work.

What is the expected output?

Title: Re: Assignment and Ternary Operator
Post by: Robert on September 15, 2010, 04:44:00 AM
Ok, maybe I'm not getting what the problem is. 

I corrected the bracketing in your "case 2" example and it ran perfectly, giving a string of random numbers showing low and high values...  I uncommented each case in turn and ran the program again and they all work. Mind you they were not terribly random... but it did work.

What is the expected output?



For examples 1, 2 and 3 the Microsoft C/C++ compiled snippet prints

MIN =  0.1251 MAX = 98.8525

For examples 1 and 2 the Pelle's  C compiled snippet prints

MIN = 12.5836 MAX = 30.7502

For example 3 the Pelle's  C compiled snippet prints

MIN =  0.1805 MAX = 97.7357

None of the Pelle's C compiled values match the Microsoft compiled outputs.

Robert Wishlaw
 
Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 15, 2010, 04:48:32 AM
You are, afterall, working with random numbers.  If you preload a set sequence of numbers into your array and scan it, I'm pretty sure the outputs would be identical.
Title: Re: Assignment and Ternary Operator
Post by: Robert on September 15, 2010, 05:14:07 AM
You are, afterall, working with random numbers.  If you preload a set sequence of numbers into your array and scan it, I'm pretty sure the outputs would be identical.


For both, the Microsoft C/C++ and MinGW g++ compilers, examples 1, 2, and 3 print

MIN =  0.1251 MAX = 98.8525

Robert Wishlaw
Title: Re: Assignment and Ternary Operator
Post by: Robert on September 15, 2010, 05:25:30 AM
You are, afterall, working with random numbers.  If you preload a set sequence of numbers into your array and scan it, I'm pretty sure the outputs would be identical.


For both, the Microsoft C/C++ and MinGW g++ compilers, examples 1, 2, and 3 print

MIN =  0.1251 MAX = 98.8525

Robert Wishlaw

For the Pelle's C 5.01 compiled snippet the output for examples 1, 2, and 3 is

MIN =  0.1805 MAX = 97.7357

Robert Wishlaw

Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 15, 2010, 06:15:20 AM
Now ... instead of preloading the array with random numbers, put in a known sequence of pre-set numbers so that you are certain you have the same starting sequence on all compilers... with the same input you should get the same output.

What you are probably seeing is a difference between random number generators... and yes it does happen.  There is no standard method of creating random numbers.  Each compiler has it's own way of doing things.  In fact, if you add a call to srand(time); before your first call to rand() you'll get a different sequence every time, even from the same compiler.

Don't trip over that... it's normal and expected behavior. Random numbers are a deliberate unknown.


Title: Re: Assignment and Ternary Operator
Post by: Robert on September 15, 2010, 07:00:17 AM
Now ... instead of preloading the array with random numbers, put in a known sequence of pre-set numbers so that you are certain you have the same starting sequence on all compilers... with the same input you should get the same output.

What you are probably seeing is a difference between random number generators... and yes it does happen.  There is no standard method of creating random numbers.  Each compiler has it's own way of doing things.  In fact, if you add a call to srand(time); before your first call to rand() you'll get a different sequence every time, even from the same compiler.

Don't trip over that... it's normal and expected behavior. Random numbers are a deliberate unknown.

Yes, that is a good comment to make but the problem that eheredia2511 started this thread with regarding Pelle's 6.0 erratic output still remains. The Microsoft, MinGW and Pelle's C 5.0.1 compilers produce a consistent output, Pelle's C version 6.0 does not. The output from the three cases should be the same although, as you have commented, it may vary between compilers.

Robert Wishlaw
Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 15, 2010, 09:13:23 AM
Hi Robert... It still looks to me like the difference is bound to happen because he is testing with random numbers.  Again the same sequence of seed values applied every time in all three compilers should bring the same result and I don't see why it wouldn't.

If he were to replace:
Code: [Select]
for(int i=0;i<NELEMS;i++)
vetor[i]=(double) (rand())/RAND_MAX*100;
with something like...
Code: [Select]
for int (i = 0; i < NELEMS; i++)
vetor[i] = (double) i * 3.55;
He would now have a known initializer and the answers from all three compilers would (should) be exactly the same...

 What I'msaying is that the differences he's seeing are most likely due to the use of random number sequences and not due to different processing of his MIN and MAX macros (etc).


Title: Re: Assignment and Ternary Operator
Post by: JohnF on September 15, 2010, 10:06:40 AM
It seems to work ok in version 5 of PellesC but not in version 6.

This should be a bug report.

John
Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 15, 2010, 10:22:57 AM
Hi John...
I'm using 6.0 here and it worked for me...

the macros ran first try.
the second option worked once I fixed the brackets
the third option worked first try.


Title: Re: Assignment and Ternary Operator
Post by: JohnF on September 15, 2010, 10:49:44 AM
Using your alteration filling in the vector I get

min = 0.0000 max = 3.5500

John


Title: Re: Assignment and Ternary Operator
Post by: frankie on September 15, 2010, 03:33:30 PM
I modified the test program as below and made checks using as standard C runtime library the Pelles POCRT.lib and MSVCRT.lib from M$.
If you have coincident values using MingW maybe you are linking with M$ runtime library, so de facto you are using the same routine.
The compiler used is PellesC V6.00 RC#3.
Code: [Select]
#include <stdio.h>
#include <stdlib.h>

#define MIN(x,y) ( (x<y) ? (x) : (y) )
#define MAX(x,y) ( (x>y) ? (x) : (y) )

#define NELEMS 50

double vector[NELEMS];

int main(void)
{
double min1,min2,min3, max1,max2,max3, minx=0.0, maxx=0.0;

for(int i=0;i<NELEMS;i++)
vector[i]=(double) (rand())/RAND_MAX*100;
//vector[i] = (double) i * 3.55;


min1=min2=min3=vector[0];
max1=max2=max3=vector[0];

double x = 0.0;

for(int i=1;i<NELEMS;i++) {

x = vector[i];

// CASE 1: this code doesn´t work *********************
min1=MIN(min1, x);
max1=MAX(max1, x);

// Case 2: neither this *******************************
    min2 = (min2 > x ? x : min2);
    max2 = (max2 < x ? x : max2);

// Case 3: but this works *****************************
if( min3 > x ) min3 = x;
if( max3 < x ) max3 = x;

}

printf("\n\n");
printf("Case 1 -> MIN =%8.4f MAX =%8.4f\n",min1,max1);
printf("Case 2 -> MIN =%8.4f MAX =%8.4f\n",min2,max2);
printf("Case 3 -> MIN =%8.4f MAX =%8.4f\n",min3,max3);
             printf("\n\n");

return EXIT_SUCCESS;
}
But I haven't seen any bug.

The values changes depending on the pseudodistribution of the random function, which of course have not the same implementation for all libraries.
You can see it enlarging the array, i.e NELEMS=5000. The larger you make it, higher is the probability that you will cover the whole range of pseudorandom values.
If you use the linear filling proposed by CommonTater you will get the correct answer:
MIN=0.00 (i=0)*3.55
MAX=173.95 (i=49)*3.55
The bracketing have no influence because the expression is solved based on operators priorities.
John I don't understand why you get that strange result. Please try my code.
Eheredia2511 what you exactly mean for cases 1 & 2 not working? compilation error, zero values or simply not coincident with M$? In last case I already explained the reason.
Title: Re: Assignment and Ternary Operator
Post by: JohnF on September 15, 2010, 05:03:58 PM
Frankie, here's your code with just a few lines commented out. Run it and see the answer.

Code: [Select]
#include <stdio.h>
#include <stdlib.h>

#define MIN(x,y) ( (x<y) ? (x) : (y) )
#define MAX(x,y) ( (x>y) ? (x) : (y) )

#define NELEMS 50

double vector[NELEMS];

int main(void)
{
double min1,min2,min3, max1,max2,max3, minx=0.0, maxx=0.0;

for(int i=0;i<NELEMS;i++)
// vector[i]=(double) (rand())/RAND_MAX*100;
vector[i] = (double) i * 3.55;


min1=min2=min3=vector[0];
max1=max2=max3=vector[0];

double x = 0.0;

for(int i=1;i<NELEMS;i++) {

x = vector[i];

// CASE 1: this code doesn´t work *********************
// min1=MIN(min1, x);
// max1=MAX(max1, x);

// Case 2: neither this *******************************
    min2 = (min2 > x ? x : min2);
    max2 = (max2 < x ? x : max2);

// Case 3: but this works *****************************
// if( min3 > x ) min3 = x;
// if( max3 < x ) max3 = x;

}

printf("\n\n");
// printf("Case 1 -> MIN =%8.4f MAX =%8.4f\n",min1,max1);
printf("Case 2 -> MIN =%8.4f MAX =%8.4f\n",min2,max2);
// printf("Case 3 -> MIN =%8.4f MAX =%8.4f\n",min3,max3);
             printf("\n\n");

return EXIT_SUCCESS;
}

I get the same as I posted earlier.

John
Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 15, 2010, 05:22:48 PM
FWIW... my results coincide with Frankie's ...

Title: Re: Assignment and Ternary Operator
Post by: JohnF on September 15, 2010, 05:34:23 PM
Have you run it with maximum speed optimisation? With the code that I posted last.

EDIT: Also 'minimise size' has the problem.

John
Title: Re: Assignment and Ternary Operator
Post by: eheredia2511 on September 15, 2010, 06:09:55 PM
I get the following answers from the code modified to show the preloaded values:

Clip 1.png -> Case 1
Clip 2.png -> Case 2
Clip 3.png -> Case 3

The version of Pelles C is 6.00.4 and I use the default options to compile and execute.

I think this is a bug!

[]s.

Title: Re: Assignment and Ternary Operator
Post by: frankie on September 15, 2010, 06:18:14 PM
Yup John, you are right!
The compiler doesn't preserve the value of the loop variable 'i', and make a single looping.
Another bug of the new register allocator  :'(.
This revision of the compiler, while much more efficient of the previous release 5.00, is really buggy!!
Pelle have to rework completely the register allocator.
To make it work I had to declare the variable 'i' as volatile. You can check the code below (still another variation). If you remove the qualifier 'volatile' the problem reappears.
Code: [Select]
#include <stdio.h>
#include <stdlib.h>

#define MIN(x,y) ( (x<y) ? (x) : (y) )
#define MAX(x,y) ( (x>y) ? (x) : (y) )

#define NELEMS 50

double vector[NELEMS];

int main(void)
{
double min1,min2,min3, max1,max2,max3, minx=0.0, maxx=0.0;
volatile int i;

// for(int i=0;i<NELEMS;i++)
for(i=0;i<NELEMS;i++)
// vector[i]=(double) (rand())/RAND_MAX*100;
vector[i] = (double) i * 3.55;


min1=min2=min3=vector[0];
max1=max2=max3=vector[0];

double x = 0.0;

//for(int i=1;i<NELEMS;i++) {
for(i=1;i<NELEMS;i++) {

x = vector[i];

// CASE 1: this code doesn´t work *********************
//min1=MIN(min1, x);
//max1=MAX(max1, x);

// Case 2: neither this *******************************
    min2 = (min2 > x ? x : min2);
    max2 = (max2 < x ? x : max2);

// Case 3: but this works *****************************
//if( min3 > x ) min3 = x;
//if( max3 < x ) max3 = x;

}

printf("\n\n");
// printf("Case 1 -> MIN =%8.4f MAX =%8.4f\n",min1,max1);
printf("Case 2 -> MIN =%8.4f MAX =%8.4f\n",min2,max2);
// printf("Case 3 -> MIN =%8.4f MAX =%8.4f\n",min3,max3);
             printf("\n\n");

return EXIT_SUCCESS;
}
Title: Re: Assignment and Ternary Operator
Post by: eheredia2511 on September 15, 2010, 06:32:47 PM
Removing the sentence
Code: [Select]
x = vetor[i] and refactoring the code to use the expression
Code: [Select]
vetor[i] with the ternary operator, as in
Code: [Select]
min1=MIN(min1, vetor[i]), the execution raises an exception.

[]s
Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 15, 2010, 10:26:33 PM
So it looks like there's rather nasty bug in 6.0.. is it only in the .4 version? I have .3 and haven't had the problem, that I know of...

Thing is, I'm mid stream in developing some very complex code and if there is a problem, I need to know now, while it's still confined to my machine.



Title: Re: Assignment and Ternary Operator
Post by: JohnF on September 16, 2010, 07:10:51 AM
The problem is present for all incarnations of version 6.

Use version 5.

John
Title: Re: Assignment and Ternary Operator
Post by: frankie on September 16, 2010, 11:04:22 AM
Sad to say, but V 6.00 could really make a big mess....  :'(
My personal suggestion is to use V5.00 Stable for development, and only when everything is fully tested and debugged give a try with V6.00 to eventually take advantage of the much more code generation efficiency of the latter.
I suspect that most of the problems come from the newly introduced register allocator, which mainly developed to take advantage from the large register set of the 64bit CPU, fails to consider the interactions between composite registers, like ax:de and other, that happens in the more limited 32bits mode.

P.S. the last problem reported by eheredia2511 is the same that John outlined. The 'i' variable, held in ax register, is not preserved so when program try to access to value vector(i) the calculated displacement points out of memory allocated to the process, and this raises the exception for invalid memory access.

***Anyway*** it is very important to continue to check and report the problems from V6.00 to help Pelle to fix the compiler for the more or less announced version 6.50, that now becomes really a must!
Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 16, 2010, 03:01:33 PM
Oh crap... Thanks guys, I'm very happy this was discovered although it's about the last thing I wanted to hear.

Now comes the big upheaval as I revert to 5.00.

Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 16, 2010, 08:16:44 PM
A question... Is is possible to use the 5.0 ide and compiler with the version 6 headers and libraries?

If not, I'm in for a pretty big re-write...


Title: Re: Assignment and Ternary Operator
Post by: JohnF on September 16, 2010, 08:20:18 PM
Try it, and let us know. :)

John
Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 17, 2010, 12:51:13 AM
Oh gosh... somehow that wasn't quite the answer I was looking for John...

But... will do and will do....
Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 17, 2010, 02:07:00 AM
Ok, the best I can figure is that without some serious header editing, you're best to stay with the header and library set installed with the IDE. 

What I did was to snag a copy of the 6.00.03 headers and libraries and headers, copied them to a different drive (My projects drive) and then uninstalled the 6.00 setup.  Next I installed the 5.00.8 setup I have here and redirected the tools/folders to the version 6 headers... No dice, compile errors all over the place.

I don't know if this is easily fixable or not... but I really don't have the time to mess with it.  I'm going to have my hands full getting my project working on the 5.00 setup...











Title: Re: Assignment and Ternary Operator
Post by: frankie on September 17, 2010, 10:58:03 AM
CommonTater which errors you have?
The compiler shouldn't be sensitive to header or libraries versions.
Can you supply us more detail on the errors and so?
Anyway I suggest to act the reverse, I mean copy only the 5.00 compiler to the 6.00.
Try this make a full 6.00 installation, then make the same for version 5.00 on another drive or location, then copy pocc.exe in the 6.00 directory and remove the 5.00 installation.
This way only some pragmas shouldn't be recognized, but the rest should work.
I personally want to give a try as soon as I have time this weekend. If you test it let us know.
Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 17, 2010, 12:55:14 PM
CommonTater which errors you have?
The compiler shouldn't be sensitive to header or libraries versions.
Can you supply us more detail on the errors and so?
Anyway I suggest to act the reverse, I mean copy only the 5.00 compiler to the 6.00.
Try this make a full 6.00 installation, then make the same for version 5.00 on another drive or location, then copy pocc.exe in the 6.00 directory and remove the 5.00 installation.
This way only some pragmas shouldn't be recognized, but the rest should work.
I personally want to give a try as soon as I have time this weekend. If you test it let us know.

More detail...  Tough one, by redirecting the include and lib folders I immediately ran into problems with pragmas, as you mention  #prama once, which I've used extensively, in particular.  But there were difference in header structure as well... For example memset() somehow vanished... and there were problem with compiler flags such as -Ob1 which stopped working.  Basically I did a quick "Rebuild Workspace" looked at all the errors (dozens of them) and decided to stay with an intact distribution.
Title: Re: Assignment and Ternary Operator
Post by: frankie on September 20, 2010, 05:49:13 PM
I made a check and it seems to work apart for the switch -Ob1 as you said. For this you have to manually remove it modifying the macro CCFLAGS in Project->options on the "macros" tab.
The #pragma should not be a problem because by default the compiler should just ignores unknown pragmas.
I don't see any problem with memset.

My actual configuration is this (from help->about menu):
RSRC0009.DLL: Version 6.00.0
SUPPORT.DLL: Version 6.00.0
CFORMAT.DLL: Version 6.00.1
PORC.DLL: Version 6.00.0
POBR.DLL: Version 6.00.1
SQLITE3.DLL: Version 3.6.12
POCC.EXE: Version 5.00.13
POASM.EXE: Version 6.00.2
POLINK.EXE: Version 6.00.1
IDESPAWN.EXE: Version 6.00.0
Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 20, 2010, 07:07:51 PM
Thank you frankie... Right now, I'm trying to get caught up using the 5.0 distribution.  I will try your setup in a couple of days when I have a chance to hammer out some test code.

I take it you just dropped POCC from 5 into the setup for 6?
Title: Re: Assignment and Ternary Operator
Post by: frankie on September 21, 2010, 11:53:11 AM
just the compiler pocc.exe
Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 21, 2010, 04:52:16 PM
Annnnnnd.... does the problem go away?

I'm still a bit reluctant to commit to this mid-project...
Title: Re: Assignment and Ternary Operator
Post by: CommonTater on September 21, 2010, 05:49:42 PM
Ok... a ton of experimenting with this problem and the OP's code...
I can replicate the error in 6.0 if I select Minimize Size or Minimize Size More in the project options dialog (I normally Maximize Speed)... it appears that it is connected to the -OS flag... When that flag is not present I don't get the problem... when it is, I do.  I tried different calling conventions, fast and precise floating point modes, all inlining options and it appears to happen only when the -Os flag is present.  


Can anyone else repilcate this to be sure?

It's clearly a bug... I hope this is enough to help Pelle fix it.


See the attached screenshot... I've highlighted the "bad actors"....