473,379 Members | 1,278 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,379 software developers and data experts.

sequence points and evaluation order

I've been playing with splint, which returns the following
warning for the code below:

statlib.c: (in function log_norm_pdf)
statlib.c(1054,31): Expression has undefined behavior (left
operand uses errno,
modified by right operand): (log(x) - mu) * (log(x) - mu)
Code has unspecified behavior. Order of evaluation of function
parameters or
subexpressions is not defined, so if a value is used and
modified in
different places not separated by a sequence point
constraining evaluation
order, then the result of the expression is unspecified.

How can the offending expression be written so that the order of
evaluation is properly specified? Can t2num be assigned the value
of any single expression equivalent to ((log(x)-mu) ^ 2) * -1.0?
/* Return log normal probability density at x.
mu=a_mean(ln(X)); sigma=s_stdev(ln(X)) (output OK) */
double log_norm_pdf(double x, double mu, double sigma)
{
double t1, t2num, t2den;

if(x <= 0.0) return 0.0;

t1 = 1.0 / (sqrt(2.0 * PI) * sigma * x);
t2num = -((log(x) - mu) * (log(x) - mu)); /* problem here */
t2den = (2.0 * (sigma * sigma));

return t1 * exp(t2num / t2den);
}

BTW: this function has been rigorously tested.
Sep 4 '06 #1
9 2481
John Smith wrote:
I've been playing with splint, which returns the following
warning for the code below:

statlib.c: (in function log_norm_pdf)
statlib.c(1054,31): Expression has undefined behavior (left
operand uses errno,
modified by right operand): (log(x) - mu) * (log(x) - mu)
Code has unspecified behavior. Order of evaluation of function
parameters or
subexpressions is not defined, so if a value is used and
modified in
different places not separated by a sequence point
constraining evaluation
order, then the result of the expression is unspecified.
I'm a bit puzzled by this.
Is it unspecified or undefined ? And why is it either ?
When it says "operand uses errno" does it mean reads
the value of errno or it means reads or writes the value
of errno ?
>
How can the offending expression be written so that the order of
evaluation is properly specified? Can t2num be assigned the value
of any single expression equivalent to ((log(x)-mu) ^ 2) * -1.0?
/* Return log normal probability density at x.
mu=a_mean(ln(X)); sigma=s_stdev(ln(X)) (output OK) */
double log_norm_pdf(double x, double mu, double sigma)
{
double t1, t2num, t2den;

if(x <= 0.0) return 0.0;

t1 = 1.0 / (sqrt(2.0 * PI) * sigma * x);
t2num = -((log(x) - mu) * (log(x) - mu)); /* problem here */
You can write this as
t2num = -( a = log(x) - mu , a * a) ;
Obviously a needs to be defined.
You can even write
{ double a ;
t2num = -( a = log(x) - mu , a * a) ;
}
to let the compiler know that the value of a
won't be needed anymore. Perhaps it will
affect optimization.
t2den = (2.0 * (sigma * sigma));

return t1 * exp(t2num / t2den);
}

BTW: this function has been rigorously tested.
Sep 4 '06 #2
John Smith wrote:
I've been playing with splint, which returns the following
warning for the code below:

statlib.c: (in function log_norm_pdf)
statlib.c(1054,31): Expression has undefined behavior (left
operand uses errno,
modified by right operand): (log(x) - mu) * (log(x) - mu)
Code has unspecified behavior. Order of evaluation of function
parameters or
subexpressions is not defined, so if a value is used and
modified in
different places not separated by a sequence point
constraining evaluation
order, then the result of the expression is unspecified.

How can the offending expression be written so that the order of
evaluation is properly specified? Can t2num be assigned the value
of any single expression equivalent to ((log(x)-mu) ^ 2) * -1.0?
/* Return log normal probability density at x.
mu=a_mean(ln(X)); sigma=s_stdev(ln(X)) (output OK) */
double log_norm_pdf(double x, double mu, double sigma)
{
double t1, t2num, t2den;

if(x <= 0.0) return 0.0;

t1 = 1.0 / (sqrt(2.0 * PI) * sigma * x);
t2num = -((log(x) - mu) * (log(x) - mu)); /* problem here */
What splint is trying to tell you is that the value of errno is
dependent on the order of evaluation of the 2 function calls. There is
no undefined behavior here (there is a sequence point between any
possible modifications to errno) and since you are not using errno
there isn't anything to worry about. You could use the value of errno,
it's value is not indeterminate, but you just can't be sure which call
to log() is the one that set the current value of errno. If you want
to get rid of the splint message you could store the value of "log(x) -
mu" in a temporary variable and do the multiplication seperately
although you might incur a precision hit. Your best bet is probably to
disable the warning inline for this particular case:

/* @-evalorder@ */
t2num = -((log(x) - mu) * (log(x) - mu)); /* problem here */
/* @+evalorder@ */

Robert Gamble

Sep 4 '06 #3
Spiros Bousbouras wrote:
John Smith wrote:
>I've been playing with splint, which returns the following
warning for the code below:

statlib.c: (in function log_norm_pdf)
statlib.c(1054,31): Expression has undefined behavior (left
operand uses errno,
modified by right operand): (log(x) - mu) * (log(x) - mu)
Code has unspecified behavior. Order of evaluation of function
parameters or
subexpressions is not defined, so if a value is used and
modified in
different places not separated by a sequence point
constraining evaluation
order, then the result of the expression is unspecified.

I'm a bit puzzled by this.
Is it unspecified or undefined ? And why is it either ?
When it says "operand uses errno" does it mean reads
the value of errno or it means reads or writes the value
of errno ?
The order of the two function calls is unspecified, but IIRC there is a
sequence point on calling a function, and the two calls are not
permitted to be run in parallel, so I can't see any undefined behaviour.
If either call sets errno it is guaranteed that errno will be set to a
non-0 value (standard functions do not set it to 0) so the code can
still test errno to see if an error has occurred and what at least one
error was. So I really don't see a problem.
>How can the offending expression be written so that the order of
evaluation is properly specified? Can t2num be assigned the value
of any single expression equivalent to ((log(x)-mu) ^ 2) * -1.0?
/* Return log normal probability density at x.
mu=a_mean(ln(X)); sigma=s_stdev(ln(X)) (output OK) */
double log_norm_pdf(double x, double mu, double sigma)
{
double t1, t2num, t2den;

if(x <= 0.0) return 0.0;

t1 = 1.0 / (sqrt(2.0 * PI) * sigma * x);
t2num = -((log(x) - mu) * (log(x) - mu)); /* problem here */

You can write this as
t2num = -( a = log(x) - mu , a * a) ;
Obviously a needs to be defined.
You can even write
{ double a ;
t2num = -( a = log(x) - mu , a * a) ;
}
to let the compiler know that the value of a
won't be needed anymore. Perhaps it will
affect optimization.
Personally I would do something more like
{
double a = log(x) - mu;
t2num -= a * a;
}

In my opinion this is easier to read. I don't see any benefit in using
the comma operator for this. Alternatively, of course, have it defined
earlier. I would consider calling log with the same value twice to be a
needless introduction of inefficiency and one that is less likely to be
fixed by the compiler than many.

For similar reasons I would probably #define ROOT_2PI
> t2den = (2.0 * (sigma * sigma));
Needless bracketing which, in my opinion, does not make it easier to read.
> return t1 * exp(t2num / t2den);
When assigning t1 I would not have used 1.0/whatever, instead I would
divide by t1 here.
>}

BTW: this function has been rigorously tested.
It may test OK but it would not have got through a code review with me
without changes or *very* good technical explanations of why they should
not be made.
--
Flash Gordon
Sep 4 '06 #4
Flash Gordon <sp**@flash-gordon.me.ukwrites:
Spiros Bousbouras wrote:
>John Smith wrote:
>>I've been playing with splint, which returns the following
warning for the code below:

statlib.c: (in function log_norm_pdf)
statlib.c(1054,31): Expression has undefined behavior (left
operand uses errno,
modified by right operand): (log(x) - mu) * (log(x) - mu)
Code has unspecified behavior. Order of evaluation of function
parameters or
subexpressions is not defined, so if a value is used and
modified in
different places not separated by a sequence point
constraining evaluation
order, then the result of the expression is unspecified.
I'm a bit puzzled by this.
Is it unspecified or undefined ? And why is it either ?
When it says "operand uses errno" does it mean reads
the value of errno or it means reads or writes the value
of errno ?

The order of the two function calls is unspecified, but IIRC there is
a sequence point on calling a function, and the two calls are not
permitted to be run in parallel, so I can't see any undefined
behaviour. If either call sets errno it is guaranteed that errno will
be set to a non-0 value (standard functions do not set it to 0) so the
code can still test errno to see if an error has occurred and what at
least one error was. So I really don't see a problem.
[...]

If log() is implemented as a macro, there may not be a sequence point.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Sep 4 '06 #5
Keith Thompson wrote:
Flash Gordon <sp**@flash-gordon.me.ukwrites:
Spiros Bousbouras wrote:
John Smith wrote:

I've been playing with splint, which returns the following
warning for the code below:

statlib.c: (in function log_norm_pdf)
statlib.c(1054,31): Expression has undefined behavior (left
operand uses errno,
modified by right operand): (log(x) - mu) * (log(x) - mu)
Code has unspecified behavior. Order of evaluation of function
parameters or
subexpressions is not defined, so if a value is used and
modified in
different places not separated by a sequence point
constraining evaluation
order, then the result of the expression is unspecified.
I'm a bit puzzled by this.
Is it unspecified or undefined ? And why is it either ?
When it says "operand uses errno" does it mean reads
the value of errno or it means reads or writes the value
of errno ?
The order of the two function calls is unspecified, but IIRC there is
a sequence point on calling a function, and the two calls are not
permitted to be run in parallel, so I can't see any undefined
behaviour. If either call sets errno it is guaranteed that errno will
be set to a non-0 value (standard functions do not set it to 0) so the
code can still test errno to see if an error has occurred and what at
least one error was. So I really don't see a problem.
[...]

If log() is implemented as a macro, there may not be a sequence point.
This is true, although it would be quite difficult to imagine a macro
version that calculates the log and sets errno all without introducing
a sequence point. In any case, it is definitely a QOI issue although I
find it somewhat disturbing that the Standard allows this. I wonder
why the Standard committee didn't stick in something that prohibits the
modification of an object with static duration from a macro version of
a library function without appropriate sequence points.

Robert Gamble

Sep 5 '06 #6

Robert Gamble wrote:
Keith Thompson wrote:
Flash Gordon <sp**@flash-gordon.me.ukwrites:
Spiros Bousbouras wrote:
>John Smith wrote:
>>
>>I've been playing with splint, which returns the following
>>warning for the code below:
>>>
>>statlib.c: (in function log_norm_pdf)
>>statlib.c(1054,31): Expression has undefined behavior (left
>>operand uses errno,
>> modified by right operand): (log(x) - mu) * (log(x) - mu)
>> Code has unspecified behavior. Order of evaluation of function
>>parameters or
>> subexpressions is not defined, so if a value is used and
>>modified in
>> different places not separated by a sequence point
>>constraining evaluation
>> order, then the result of the expression is unspecified.
>I'm a bit puzzled by this.
>Is it unspecified or undefined ? And why is it either ?
>When it says "operand uses errno" does it mean reads
>the value of errno or it means reads or writes the value
>of errno ?
>
The order of the two function calls is unspecified, but IIRC there is
a sequence point on calling a function, and the two calls are not
permitted to be run in parallel, so I can't see any undefined
behaviour. If either call sets errno it is guaranteed that errno will
be set to a non-0 value (standard functions do not set it to 0) so the
code can still test errno to see if an error has occurred and what at
least one error was. So I really don't see a problem.
[...]

If log() is implemented as a macro, there may not be a sequence point.

This is true, although it would be quite difficult to imagine a macro
version that calculates the log and sets errno all without introducing
a sequence point.
Despite the evidence of the error message above? That
makes it pretty easy to imagine I would say.
In any case, it is definitely a QOI issue although I
find it somewhat disturbing that the Standard allows this. I wonder
why the Standard committee didn't stick in something that prohibits the
modification of an object with static duration from a macro version of
a library function without appropriate sequence points.
Better still, a requirement that a macro version behave
as if the actual function would.

Sep 6 '06 #7
Flash Gordon wrote:
Personally I would do something more like
{
double a = log(x) - mu;
t2num -= a * a;
}
Is -= a typo?

The original code was:

t2num = -((log(x) - mu) * (log(x) - mu));

(with t2num uninitialized.)

Isn't
t2num -= a * a;
equivalent to
t2num = t2num - (a * a);
?
Sep 6 '06 #8
Spoon wrote:
Flash Gordon wrote:
>Personally I would do something more like
{
double a = log(x) - mu;
t2num -= a * a;
}

Is -= a typo?
<snip>

No, it was a reado. I wasn't reading carefully enough.However, the
general point still stands.
--
Flash Gordon
Sep 6 '06 #9
en******@yahoo.com wrote:
Robert Gamble wrote:
Keith Thompson wrote:
Flash Gordon <sp**@flash-gordon.me.ukwrites:
Spiros Bousbouras wrote:
John Smith wrote:
>
>I've been playing with splint, which returns the following
>warning for the code below:
>>
>statlib.c: (in function log_norm_pdf)
>statlib.c(1054,31): Expression has undefined behavior (left
>operand uses errno,
> modified by right operand): (log(x) - mu) * (log(x) - mu)
> Code has unspecified behavior. Order of evaluation of function
>parameters or
> subexpressions is not defined, so if a value is used and
>modified in
> different places not separated by a sequence point
>constraining evaluation
> order, then the result of the expression is unspecified.
I'm a bit puzzled by this.
Is it unspecified or undefined ? And why is it either ?
When it says "operand uses errno" does it mean reads
the value of errno or it means reads or writes the value
of errno ?

The order of the two function calls is unspecified, but IIRC there is
a sequence point on calling a function, and the two calls are not
permitted to be run in parallel, so I can't see any undefined
behaviour. If either call sets errno it is guaranteed that errno will
be set to a non-0 value (standard functions do not set it to 0) so the
code can still test errno to see if an error has occurred and what at
least one error was. So I really don't see a problem.
[...]
>
If log() is implemented as a macro, there may not be a sequence point.
This is true, although it would be quite difficult to imagine a macro
version that calculates the log and sets errno all without introducing
a sequence point.

Despite the evidence of the error message above? That
makes it pretty easy to imagine I would say.
It's not too difficult to imagine *a* function that would do this as
virtually any library function may set errno, but it would be difficult
to imagine a conforming implementation of the log function that does as
its implementation is non-trivial and it returns a non-int value.
In any case, it is definitely a QOI issue although I
find it somewhat disturbing that the Standard allows this. I wonder
why the Standard committee didn't stick in something that prohibits the
modification of an object with static duration from a macro version of
a library function without appropriate sequence points.

Better still, a requirement that a macro version behave
as if the actual function would.
There is a sequence point before any function in C returns. Requiring
that all macro versions of library functions have this sequence point
would unnecessarily complicate and invalidate many existing macros
such as those covering functions in ctype.h. As long as the macro does
not modify objects with static duration I don't see a need for forcing
the macro version to implement the sequence point.

Robert Gamble

Sep 6 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Sensorflo | last post by:
After browsing though many newsgroups articels I'm still not shure how operator precedence, operator associativity, sequence points, side effects go together. Currently I have the following view: ...
4
by: j | last post by:
In a footnote in the c99 standard the following is labeled as undefined: a = i; And in the second clause of section 6.5 the following is stated: "Between the previous and next sequence...
3
by: sugaray | last post by:
Can somebody explain to me what is sequence point ? With few examples would be even better. Thanx for your help.
53
by: Deniz Bahar | last post by:
I know the basic definition of a sequence point (point where all side effects guaranteed to be finished), but I am confused about this statement: "Between the previous and next sequence point an...
4
by: manuscheung | last post by:
Hi all, This is not a question. Here I found a good article that discusses sequence point in details: http://www.embedded.com/shared/printableArticle.jhtml?articleID=9900661
7
by: akarl | last post by:
Hi all, Why do I get a warning from gcc with the following program? $ cat test.c #include <stdio.h> int f(int n) { return n;
4
by: Daniel Kraft | last post by:
Hi all! I do not have a standard-document right next to me to cite from, but as far as I know, doing something like: a()=b()=c()=d(); or foo(d()+c()+b()+a()); has a fixed evaluation order...
2
by: Kai-Uwe Bux | last post by:
Please consider #include <iostream> int main ( void ) { int a = 0; a = ( (a = 5), 4 ); // (*) std::cout << a << '\n'; }
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.