long double versions of functions in gcc under Cygwin

E

ena8t8si

Keith said:
Sure. (The last label should be BAIL1, not BAIL3).

Yes, thank you for the correction.
Just off the top of my head ...

With exception handlers, that would probably be written as three
nested blocks rather than straight-line code with gotos. As long as
you're creating nested blocks, I suppose you might as well just use
if-then-elses.

The code could be a bit simpler if you could assume that
release_resource() does nothing with a null pointer, as free() does.

Something that just occurred to me is that exceptions (in Ada or C++)
propagate across function calls. If we're (hypothetically) doing this
just to handle control flow within functions, that's not necessary.
Perhaps one answer is, rather than exception handling, to allow a
named break to exit from any scope, not just a loop or switch
statement.

So maybe something like this:

int typfun() /* This is not C. */
{
int rc;
...
USE_RESOURCE_ONE:
{
x = get_resource_one();
if(x==NULL){ rc = -1; break USE_RESOURCE_ONE };

USE_RESOURCE_TWO:
{
y = get_resource_two();
if(y==NULL){ rc = -2; break USE_RESOURCE_TWO; }

USE_RESOURCE_THREE:
{
z = get_resource_three();
if(z=NULL){ rc = -3; break USE_RESOURCE_THREE; }

rc = 0;
release_resource(z);
}

release_resource(y);
}

release_resource(x);
}

return rc;
}

The goto version is shorter, has the same number of labels,
and doesn't exhibit the crawling indentation property.
This version doesn't seem like an improvement to me.
Or, if release_resource() works correctly with a null pointer argument:

int typfun() /* This is not C. */
{
int rc;
...
USE_RESOURCES:
{
x = get_resource_one();
if(x==NULL){ rc = -1; break USE_RESOURCES; }

y = get_resource_two();
if(y==NULL){ rc = -2; break USE_RESOURCES; }

z = get_resource_three();
if(z=NULL){ rc = -3; break USE_RESOURCES; }

rc = 0;
} /* end of USE_RESOURCES block */

release_resource(z);
release_resource(y);
release_resource(x);

return rc;
}

Since there is only one level of nesting, this
structure can be achieved using a do/while(0)
block:

int typfun() /* C, not counting some missing declarations. */
{
int rc;
...
x = y = z = NULL;
do {
x = get_resource_one();
if(x==NULL){ rc = -1; break; }

y = get_resource_two();
if(y==NULL){ rc = -2; break; }

z = get_resource_three();
if(z==NULL){ rc = -3; break; }

rc = 0;
} while(0);

release_resource(z);
release_resource(y);
release_resource(x);

return rc;
}

So under the assumption that release(NULL) works,
the gotos in the original I would put under the
"bad coding" category more than needing a new
language control structure.

Maybe there are better motivating examples;
I just don't know what they are.
 
E

ena8t8si

Richard said:
It works better if you manage to write release_resource() to do nothing
on a null pointer (like malloc(), and unfortunately unlike fclose()).
You can then write this, which IMO looks cleaner:

int typfun()
{
int rc;
... x = y = z = NULL;
x = get_resource_one();
if(x==NULL){ rc = -1; goto BAIL; }

y = get_resource_two();
if(y==NULL){ rc = -2; goto BAIL; }

z = get_resource_three();
if(z==NULL){ rc = -3; goto BAIL; }

rc = 0;

BAIL:
release_resource(z);
release_resource(y);
release_resource(x);
return rc;
}

Yes, I prefer this approach myself, when workable.
Sometimes it isn't, which is why I wrote it the
other way in the first place. (Sadly, performance
concerns are sometimes of paramount interest,
and measurements showed they couldn't be
neglected in some of these situations.)
 
L

lcw1964

pete said:
http://groups.google.com/group/comp.lang.c/msg/e7cff29955d4971b

"We used to do successive multiplication, until we discovered
that accuracy degrades quickly with that approach.
The only really safe way to evaluate pow(x, y) accurately
is to compute exp(y * ln(x)) to extra internal precision.
(Took us a lot of rewrites, and a lot of careful testing,
to find that out.)" -- P.J. Plauger, Dinkumware, Ltd.

Thanks Pete. That makes sense.

On my machine, ln(LDBL_MAX) is a little over 11653. fs_expl(11653)
returns a result that matches the Maple output to 16 digits within 1
ulp, and with rounding matches perfectly to 15 digits. Considering the
vicissitudes of computing exp() as the argument gets large, I don't
think this is anything to sneeze at, since my experience has been on my
machine that a really good long double result usually means 18 digits
tops, occasionally 19 if the rounding error works in my favour.

Thanks for sharing your work.

Les
 
F

Flash Gordon

jaysome said:
This pattern maps very well onto try/catch blocks. First consider a
re-write of your example code (z=NULL corrected).

Yes thank you for the correction.
int typfun(void)
{
int rc;
...
x=y=z=NULL;
x = get_resource_one();
if(x==NULL){ rc = -1; goto CLEANUP; }
y = get_resource_two();
if(y==NULL){ rc = -2; goto CLEANUP; }
z = get_resource_three();
if(z==NULL){ rc = -3; goto CLEANUP; }

rc = 0;

CLEANUP:
release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

Now consider how it might be written in a language that provides
try/catch, and assumes release_resource() handles NULL, like it
should, like free() and delete and delete [] do:

int typfun()
{
int rc = 0;
...
x=y=z=NULL;
try
{
x = get_resource_one();
if(x==NULL){ rc = -1; throw rc; }
y = get_resource_two();
if(y==NULL){ rc = -2; throw rc; }
z = get_resource_three();
if(z==NULL){ rc = -3; throw rc; }
}
catch(int i)
{
rc = i;
}

release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

There's not much difference.

Two comments. First, not all resource allocation/release can be
rewritten in the style you suggest using release(NULL). [*]
Second, why would someone use throw when what's it's doing
basically just a goto in disguise?

Why use a for loop when it is just a while loop in disguise? Why use a
while loop when it is just a conditional goto and an unconditional goto
in disguise? Why use a do-while loop when it is just a conditional goto
in disguise? Why use a break when it is just a goto in disguise?
> If the release(NULL) technique
works, it seems better to dispense with try/catch altogether:

int typfun()
{
int rc = 0;
...
x=y=z=NULL;
do {
x = get_resource_one();
if(x==NULL){ rc = -1; break; }
y = get_resource_two();
if(y==NULL){ rc = -2; break; }
z = get_resource_three();
if(z==NULL){ rc = -3; break; }
} while(0);

release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

Or, if one had try/catch
int typfun()
{
int rc = 0;
...
x=y=z=NULL;
try {
x = get_resource_one();
if(x==NULL) throw -1;
y = get_resource_two();
if(y==NULL) throw -2;
z = get_resource_three();
if(z==NULL) throw -3;
}
catch( int i )
rc = i;

release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

I'm sure it is a few characters less typing ;-)
[*] For performance reasons, among others.

Premature optimisation is the root of quite a lot of problems. Anyway,
as someone else suggested you can always nest the blocks.

try/catch which propagates outside the function can be even more useful.
Especially for library functions.

int mylibfunc(whatever)
{
/* do stuff */
if (condition)
/* This is a fundamental problem and it is not safe to continue
doing anything unless it is dealt with */
throw 1;
}

Unlike the return value if the caller ignores it then it propagates
until the program exits with an error code or it is caught. I've done a
lot of programming in a Pascal variant that had this and made a lot of
use of it and it makes handling exceptional conditions a lot easier.
Like most things it can also be abused ;-)
 
C

Chris Torek

(this needs a new "subject" line but I could not think of something
suitable yet short)

The pattern I was talking about looks something like
the following:

int typfun()
{
int rc;
...
x = get_resource_one();
if(x==NULL){ rc = -1; goto BAIL1; }

y = get_resource_two();
if(y==NULL){ rc = -2; goto BAIL2; }

z = get_resource_three();
if(z==NULL){ rc = -3; goto BAIL3; }

rc = 0;
release_resource(z);

BAIL3:
release_resource(y);

BAIL2:
release_resource(x);

BAIL3:
return rc;
}

Obviously there are variations, and I've written
the if()'s on one line to save space, but I
think you get the idea.

A pattern like this doesn't map very well onto
try/catch blocks, or other exception handling
mechanisms. ...

Maybe not; but over time I have been convinced to (usually) rewrite
the above as (note that most of the "get resource" functions in this
particular system return an error code, so take an address for their
"successful result" if any):

int typfun()
{
int error = 0;
T x = NULL, y = NULL, z = NULL;
...
error = get_resource_one(&x);
if (error == 0)
error = get_resource_two(&y);
if (error == 0)
error = get_resource_three(&y);
if (error == 0)
... do the work ...
release_resource(z);
release_resource(y);
release_resource(x);
return error;
}

This is "less efficient" in the error case (because "if (error==0)"
test is repeated, assuming the compiler does not rearrange it away)
but "equally efficient" in the non-error case (because all three
tests are required no matter what). Thus, if the error case is a
little slower ... well, this is often not a big deal. :)
 
A

av

The exp() routine does start to lose digits as the argument gets higher
and the output has very large magnitude. I don't know if this due to
propagated rounding error in Pete's code, or if this is just the nature
of the beast when dealing with the long double type on my platform.

i have the same problem. it seems it is common problem for the "pow"
functions. The only solution i find is a "steps function" for grow the
precision in the way at end the result should be exact in the request
digit precision. (but i think it is not 100% ok for all input in "my"
function pow())
 
J

jaysome

On Wed, 09 Aug 2006 20:05:11 +0100, Flash Gordon

[snip]
Or, if one had try/catch
int typfun()
{
int rc = 0;
...
x=y=z=NULL;
try {
x = get_resource_one();
if(x==NULL) throw -1;
y = get_resource_two();
if(y==NULL) throw -2;
z = get_resource_three();
if(z==NULL) throw -3;
}
catch( int i )
rc = i;

release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

I'm sure it is a few characters less typing ;-)

Admittedly better. I retained the assignment to rc to strengthen the
parallelism. And to further the improvements, this is what I would do:

if (!x)

instead of

if (x==NULL)

The C standard guarantees that the two expressions yield identical
results, and there's even an FAQ on this.
[*] For performance reasons, among others.

Premature optimisation is the root of quite a lot of problems. Anyway,
as someone else suggested you can always nest the blocks.

Indeed. Probably the biggest problem with premature optimization is a
waste of time. And that can figure significantly into missing a
schedule deadline.

On my current main project, we still compile with the debug option. So
far so good. Should the day come where there is a throughput problem,
the first step I'll perform is to make a simple change to scripts and
project settings that result in compilation without the debug option
and optimizations enabled. I've already tested this, and am confident
that the only change will be in increased throughput. In the meantime,
I have to deal with the possibility that someone else screws up and
I'll be the one troubleshooting the crash. Hence debug with no
optimizations--core dumps and crashes need debuggers.
 
P

pete

jaysome wrote:
And to further the improvements, this is what I would do:

if (!x)

instead of

if (x==NULL)

The C standard guarantees that the two expressions yield identical
results, and there's even an FAQ on this.

That doesn't explain why you think (!x) is better than (x==NULL).

(x==NULL) gives me enough context to know that x is a pointer.

(!x) only tells me that x is a scalar type.
 
E

ena8t8si

Chris said:
(this needs a new "subject" line but I could not think of something
suitable yet short)



Maybe not; but over time I have been convinced to (usually) rewrite
the above as (note that most of the "get resource" functions in this
particular system return an error code, so take an address for their
"successful result" if any):

int typfun()
{
int error = 0;
T x = NULL, y = NULL, z = NULL;
...
error = get_resource_one(&x);
if (error == 0)
error = get_resource_two(&y);
if (error == 0)
error = get_resource_three(&y);
if (error == 0)
... do the work ...
release_resource(z);
release_resource(y);
release_resource(x);
return error;
}

This is "less efficient" in the error case (because "if (error==0)"
test is repeated, assuming the compiler does not rearrange it away)
but "equally efficient" in the non-error case (because all three
tests are required no matter what). Thus, if the error case is a
little slower ... well, this is often not a big deal. :)

Yes, where workable a form like the above is preferable.
My intention was to talk about cases where it isn't
workable, but I agree here wholeheartedly.
 
E

ena8t8si

Flash said:
jaysome said:
On 8 Aug 2006 23:21:07 -0700, (e-mail address removed) wrote:

Keith Thompson wrote:
(e-mail address removed) writes:
Keith Thompson wrote:
In my humble opinion, most instances of goto statements point to a
missing feature in the language. In C, the major missing features are
named break (which could be used to break out of a specified loop
rather than the nearest enclosing one) and a decent exception
mechanism.
I don't agree with the basic premise, but for the
sake of discussion let's say I do. Do you really
think most gotos would be eliminated by C having
the features you named? In my experience most gotos
arise in one of three circumstances: bad coding,
branch to end of function to preserve single return
point, and machine generated C code (eg, YACC/LEX).
Breaking out of multiple loops seems like a distant
fourth (and usually remediable by putting the multiple
loops in their own function and using return); and
exception handling, it's hard to see how that's even
on the radar. It may be that C would benefit from
these features (personally I don't think it would,
but that's a separate issue), but even if it had
them it doesn't seem like goto usage would be affected
much.

My question above wasn't meant to be rhetorical;
I'm interested to hear your reactions.
Branching to the end of a function (for example because you need to
execute some cleanup code rather than doing an immediate return) is
something that's usually done in, ahem, *exceptional* circumstances.
I'm not sure that C++-style exceptions would be a good fit for C. As
I recall, any C++ object can be thrown as an exception. Ada's
exception mechanism might be worth considering. In the 1983 version
of the language, it's simpler than C++'s mechanism; an exception is
just an exception, and a handler can handle either named exception or
all exceptions. Of course, any such mechanism would have to be very
lightweight.

The idea is to work with named entities that relate to the problem
domain rather than jumping to a named point in the code.
The pattern I was talking about looks something like
the following:

int typfun()
{
int rc;
...
x = get_resource_one();
if(x==NULL){ rc = -1; goto BAIL1; }

y = get_resource_two();
if(y==NULL){ rc = -2; goto BAIL2; }

z = get_resource_three();
if(z=NULL){ rc = -3; goto BAIL3; }

rc = 0;
release_resource(z);

BAIL3:
release_resource(y);

BAIL2:
release_resource(x);

BAIL3:
return rc;
}

Obviously there are variations, and I've written
the if()'s on one line to save space, but I
think you get the idea.

A pattern like this doesn't map very well onto
try/catch blocks, or other exception handling
mechanisms.
This pattern maps very well onto try/catch blocks. First consider a
re-write of your example code (z=NULL corrected).

Yes thank you for the correction.
int typfun(void)
{
int rc;
...
x=y=z=NULL;
x = get_resource_one();
if(x==NULL){ rc = -1; goto CLEANUP; }
y = get_resource_two();
if(y==NULL){ rc = -2; goto CLEANUP; }
z = get_resource_three();
if(z==NULL){ rc = -3; goto CLEANUP; }

rc = 0;

CLEANUP:
release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

Now consider how it might be written in a language that provides
try/catch, and assumes release_resource() handles NULL, like it
should, like free() and delete and delete [] do:

int typfun()
{
int rc = 0;
...
x=y=z=NULL;
try
{
x = get_resource_one();
if(x==NULL){ rc = -1; throw rc; }
y = get_resource_two();
if(y==NULL){ rc = -2; throw rc; }
z = get_resource_three();
if(z==NULL){ rc = -3; throw rc; }
}
catch(int i)
{
rc = i;
}

release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

There's not much difference.

Two comments. First, not all resource allocation/release can be
rewritten in the style you suggest using release(NULL). [*]
Second, why would someone use throw when what's it's doing
basically just a goto in disguise?

Those are reasonable questions, but most of them have obvious
answers.

A reason for preferring goto to throw (when possible) is that
goto is guaranteed to be local; throw isn't. I don't see
any reason to use throw, except to avoid the bugaboo of using
goto. And that doesn't strike me as much of a reason.
Why use a for loop when it is just a while loop in disguise? Why use a
while loop when it is just a conditional goto and an unconditional goto
in disguise? Why use a do-while loop when it is just a conditional goto
in disguise? Why use a break when it is just a goto in disguise?


Or, if one had try/catch
int typfun()
{
int rc = 0;
...
x=y=z=NULL;
try {
x = get_resource_one();
if(x==NULL) throw -1;
y = get_resource_two();
if(y==NULL) throw -2;
z = get_resource_three();
if(z==NULL) throw -3;
}
catch( int i )
rc = i;

release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

I'm sure it is a few characters less typing ;-)

Same comments as above apply here. More mental
effort is required for try/throw/catch than
for do/break/while(0);
[*] For performance reasons, among others.

Premature optimisation is the root of quite a lot of problems.

The optimization was not premature in the cases
I was referring to.
Anyway,
as someone else suggested you can always nest the blocks.

Yes, and nesting the blocks produces a less satisfactory
result, as my response to that suggestion explained.
 
F

Flash Gordon

Two comments. First, not all resource allocation/release can be
rewritten in the style you suggest using release(NULL). [*]
Second, why would someone use throw when what's it's doing
basically just a goto in disguise?

Those are reasonable questions, but most of them have obvious
answers.

A reason for preferring goto to throw (when possible) is that
goto is guaranteed to be local; throw isn't. I don't see
any reason to use throw, except to avoid the bugaboo of using
goto. And that doesn't strike me as much of a reason.

To me throw would be the more natural. The problem is you have hit an
exceptional situation that you have to deal with not that you need to
clean up. I can accept, however, that others may not see it that way. I
also don't see the locality as a problem because with any sensible (to
me) sized code block you can see at a glance that it is enclosed in a
local try block.

I'm not saying you are wrong, this is a matter of personal preference in
my opinion, not who is right or wrong.
Same comments as above apply here. More mental
effort is required for try/throw/catch than
for do/break/while(0);

For me it does not require more mental effort. If anything it is less
because after seeing the do I don't have to check the end to know it is
just there to allow breaking out.

Of course, I spent years using a try/catch type system so I'm so
familiar with it that it requires no more thinking than understanding
for (;;) {
/* whatever */
}
[*] For performance reasons, among others.
Premature optimisation is the root of quite a lot of problems.

The optimization was not premature in the cases
I was referring to.

That was not clear in your previous post. You've since said that you had
found you had a performance problem, measured, and found this a
significant saving. In such conditions it is reasonable to make the
optimisation.
Yes, and nesting the blocks produces a less satisfactory
result, as my response to that suggestion explained.

Again, very much a matter of personal preference.
 
L

lcw1964

Dann said:
I think Moshier's code is beautiful. It was originally written in 1984, and
later reworked so that you could compile it with ANSI style prototypes.

At the top of every file is a detailed explanation of what the code does,
which equations are used to solve the problem, and what the measured errors
were in calibration of the function's useful range.

I am a very amateur hobbyist program so I am not qualified to comment
on either the aesthetics of the code or the virtues (or not) of goto
statements, but I know enough to be impressed by the math of it.

Mr. Corbit was quite correct to comment earlier in the thread that the
qlib package was easy to make, and, with a little research on my part,
is not so inscrutable to use. I have been particularly impressed with
Moshier's code for the high precision version of the gamma function.
This function is not something that is easily computed to very high
precision--the asymptotic Stirling series uses Bessel numbers which in
the higher terms get huge--but Moshier's code is painstakingly
thorough, with the requisite constants to dozes of digits rendered in
the code.

With a little practice I have been able to write a little
implementation that computes this function to over 100 digits. That
impresses me. As a user, I think I could forgive the evil gotos if
they get the job done :)

Les
 
E

ena8t8si

Flash said:
Flash said:
(e-mail address removed) wrote:
jaysome wrote:
Two comments. First, not all resource allocation/release can be
rewritten in the style you suggest using release(NULL). [*]
Second, why would someone use throw when what's it's doing
basically just a goto in disguise?

Those are reasonable questions, but most of them have obvious
answers.

A reason for preferring goto to throw (when possible) is that
goto is guaranteed to be local; throw isn't. I don't see
any reason to use throw, except to avoid the bugaboo of using
goto. And that doesn't strike me as much of a reason.

To me throw would be the more natural. The problem is you have hit an
exceptional situation that you have to deal with not that you need to
clean up. I can accept, however, that others may not see it that way. I
also don't see the locality as a problem because with any sensible (to
me) sized code block you can see at a glance that it is enclosed in a
local try block.

I'm not saying you are wrong, this is a matter of personal preference in
my opinion, not who is right or wrong.
Same comments as above apply here. More mental
effort is required for try/throw/catch than
for do/break/while(0);

For me it does not require more mental effort. If anything it is less
because after seeing the do I don't have to check the end to know it is
just there to allow breaking out.

Of course, I spent years using a try/catch type system so I'm so
familiar with it that it requires no more thinking than understanding
for (;;) {
/* whatever */
}
[*] For performance reasons, among others.
Premature optimisation is the root of quite a lot of problems.

The optimization was not premature in the cases
I was referring to.

That was not clear in your previous post. You've since said that you had
found you had a performance problem, measured, and found this a
significant saving. In such conditions it is reasonable to make the
optimisation.
Yes, and nesting the blocks produces a less satisfactory
result, as my response to that suggestion explained.

Again, very much a matter of personal preference.

Reasonable comments.

Just a few points in reply.

It's true for short functions that there isn't much difference
between the try/catch form and the goto form (or do/while(0)
form). Unfortunately the real cases where these come up (based on
my experience) tend to have longer than average function bodies,
and it isn't always easy to scan the whole function.

Two, whatever one's personal reaction, adding exception handling
to C would produce a bigger language than C is now. A bigger
language means more mental effort to understand programs written
in that language.

Three, exceptions are as easy to misuse as goto is, and in my
experience misused more often.

Adding these up, getting rid of gotos still doesn't make a good
argument for introducing exception handling into C. It might
(or might not) be good to introduce it for other reasons, but
getting rid of gotos isn't one of them.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top