Is there a way, in Tcl, to avoid throwing an exception for arithmetic
underflow in Tcl and instead to set the value to 0.0. I saw this
interesting comment on another topic:
> This has been important in my work to permit replacing some of
> Tcl's built-in math functions with others that have floating point
> exception handling more suitable for my needs. (Silently flatten a
> value to 0.0 rather than crash the program with an underflow exception,
> for example).
> --
> | Don Porter Mathematical and Computational Sciences Division |
What's the oldest version of Tcl you need the solution to work for?
--
| Don Porter Mathematical and Computational Sciences Division |
| donald...@nist.gov Information Technology Laboratory |
| http://math.nist.gov/~DPorter/ NIST |
|______________________________________________________________________|
Ok, so the fact that underflow issues are solved by Tcl 8.5 won't
be good enough for you then.
Use Tcl_CreateMathFunc() to replace any underflow-crashing functions
with replacements that tolerate the underflow.
http://tmml.sourceforge.net/doc/tcl/CrtMathFnc.html
That solution will continue to work with Tcl 8.5, even though it's
no longer needed there.
for { set i 0 } { $i < $count} { incr i } {
if { [ catch {
set slice [ expr { <expr that might underflow> } ]
} result ] } {
# an error has occurred
set slice 0.0
}
# do something else with slice
}
What happens in 8.5 that makes this better?
phil...@gmail.com wrote:
> I am trying to deal with this in a global way in a situation where my
> customers
> are writing Tcl code that might underflow, so I can't globally replace
> everything that they might use.
Not "everything they might use". Replace only those functions that
exhibit the underflow problem. In my experience, that's only the exp()
and pow() functions, and even then only on some platforms.
Tcl_CreateMathFunc() does operate "in a global way", unlike your advice
to wrap every use of [expr]essions.
> What happens in 8.5 that makes this better?
After math function evaluations that return double, errno is tested, and
underflow is automatically flattened to 0.0
> > What happens in 8.5 that makes this better?
>
> After math function evaluations that return double, errno is tested, and
> underflow is automatically flattened to 0.0
So there won't be TCL_ERROR for any underflow from then on?
That is correct.
Don Porter wrote:
> That is correct.
That's at least our intention. Whether we get thwarted by broken
C libraries remains to be seen. But we did make a conscious
decision that quiet underflow was what we wanted.
--
73 de ke9tv/2, Kevin
> Don Porter wrote:
> Not "everything they might use". Replace only those functions that
> exhibit the underflow problem. In my experience, that's only the exp()
> and pow() functions, and even then only on some platforms.
>
Which platforms exhibit this behaviour? (I have never encountered
underflow errors, as far as I can remember, with Tcl)
Regards,
Arjen
Arjen Markus wrote:
> Which platforms exhibit this behaviour?
Here's a session on Solaris 9 for one example:
% info patch
8.4.14
% expr {exp(-1000.)}
floating-point value too small to represent
Use that sample script yourself to check a platform of interest.
> >> Don Porter wrote:
> >> Not "everything they might use". Replace only those functions that
> >> exhibit the underflow problem. In my experience, that's only the exp()
> >> and pow() functions, and even then only on some platforms.
>
> Arjen Markus wrote:
> > Which platforms exhibit this behaviour?
>
> Here's a session on Solaris 9 for one example:
>
> % info patch
> 8.4.14
> % expr {exp(-1000.)}
> floating-point value too small to represent
>
> Use that sample script yourself to check a platform of interest.
>
Ah, I tried it on Windows and Linux - no problem. As I do not have
access to Solaris (anymore), that may very well explain why I
have never had problems with that.
Regards,
Arjen
from inside my application the printout from
puts "expr \{ ( exp(-10*($SCH_a_i+$LR_EXT_val)*1e6/$SCref)/10) \}"
is
expr { (
exp(-10*(2.5499999999999997e-06+9.9999999999999991e-05)*1e6/1.0)/10) }
The evaluation of the expr causes:
floating-point value too small to represent
while executing
"expr { ( exp(-10*($SCH_a_i+$LR_EXT_val)*1e6/$SCref)/10) } "
but in tclsh, I get:
% expr { (
exp(-10*(2.5499999999999997e-06+9.9999999999999991e-05)*1e6/1.0)/10) }
0.0
I am not sure what the difference is.
int
Oc_Exp(ClientData, Tcl_Interp *interp, Tcl_Value *args, Tcl_Value
*resultPtr)
{
errno = 0;
double result = exp(args[0].doubleValue);
if ((errno == ERANGE) && (result == 0.0)) {
// Special case. Underflow. Raise no exception.
} else if (errno != 0) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,"errno set to ",NULL);
switch (errno) {
case ERANGE:
Tcl_AppendResult(interp,"ERANGE",NULL);
case EDOM:
Tcl_AppendResult(interp,"EDOM",NULL);
default:
Tcl_AppendResult(interp,"unexpected value",NULL);
}
Tcl_AppendResult(interp," by exp()",NULL);
return TCL_ERROR;
}
resultPtr->doubleValue = result;
resultPtr->type = TCL_DOUBLE;
return TCL_OK;
}
int
Oc_Pow(ClientData, Tcl_Interp *interp, Tcl_Value *args, Tcl_Value
*resultPtr)
{
errno = 0;
double result = pow(args[0].doubleValue,args[1].doubleValue);
if ((errno == ERANGE) && (result == 0.0)) {
// Special case. Underflow. Raise no exception.
} else if (errno != 0) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,"errno set to ",NULL);
switch (errno) {
case ERANGE:
Tcl_AppendResult(interp,"ERANGE",NULL);
case EDOM:
Tcl_AppendResult(interp,"EDOM",NULL);
default:
Tcl_AppendResult(interp,"unexpected value",NULL);
}
Tcl_AppendResult(interp," by pow()",NULL);
return TCL_ERROR;
}
resultPtr->doubleValue = result;
resultPtr->type = TCL_DOUBLE;
return TCL_OK;