% set begin 6658020034
6658020034
% set end 658020034
658020034
% expr abs($end - $begin)
integer value too large to represent
% expr { abs($end - $begin) }
can't use floating-point value as operand of "-"
% expr { abs(658020034 - 6658020034) }
integer value too large to represent
Can someone explain where Tcl thinks the floating
point value is? And why is a floating point value
not a valid operand of "-"?
- Phil Ehrens
This is just an example of too much sharing of a
common routine for producing an error message.
There's one routine for generating the "illegal
operand" error message, and by the time it is called,
the context isn't around any more to tailor the
message precisely. So the error message generator
knows that "658020034" was "bad", and it can see that
that is a legal floating-point value, so it assumes
that the error is that a floating-point value was used
where it should not be. Go ahead and file a bug report
under the "ByteCode Compiler" Category.
- Don Porter
Logged In: YES
user_id=148712
Note that this particular example fails to produce the error
in tcl8.5 (Donal's 64 bit arithmetic), but it can be
reproduced by going beyong the 64-bit limit:
set begin 665802003400000000000000
Logged In: YES
user_id=148712
Note that 'abs' has nothing to do with it
% set begin 665802003400000000000000
665802003400000000000000
% expr $begin - 1
integer value too large to represent
% expr {$begin - 1}
can't use floating-point value as operand of "-"
Logged In: YES
user_id=148712
Related bug (the relationship is in the cause, not the symptom):
% set begin 665802003400000000000000
665802003400000000000000
% expr {1 && $begin}
1
% expr 1 && $begin
integer value too large to represent
Logged In: YES
user_id=148712
Another sibling is
% set a 08
08
% expr $a+1
"08" is an invalid octal number
% expr {$a+1}
can't use invalid octal number as operand of "+"
Logged In: YES
user_id=148712
More ...
% set a 08
08
% expr abs($a)
"08" is an invalid octal number
% expr {abs($a)}
argument to math function was an invalid octal number
The error cases follow a different path, and produce
different results.In this particular case, I like the second
one better ...
Logged In: YES
user_id=75003
Why is that a sibling ?
The leading 0 tells tcl to interpret 08 as an octal number,
but 8 is not a valid octal digit, Hence it is an invalid
octal number, and the message is essentially correct in
both cases. Or is the problem that the message is different
for the two cases ?
Logged In: YES
user_id=148712
Yes, in my mind (and in the evolving patch), the problem to
fix is "both paths should produce the same error messages,
but don't". All of these fall in *that* category, although
some are less severe as they produce different but correct
messages. Maybe it is not necessary to produce the same
error message,as long as it is a correct one?
Logged In: YES
user_id=75003
Ok. I also prefer that the path should produce the same
message. If that is not possible I am willing to settle for
different yet correct messages.
Logged In: YES
user_id=148712
Are these bugs too?
% set a 08
08
% expr $a
"08" is an invalid octal number
% expr {$a}
08
% set b 665802003400000000000000
665802003400000000000000
% expr $b
integer value too large to represent
% expr {$b}
665802003400000000000000
Logged In: YES
user_id=72656
No, those are being treated as normal strings. That has
always been a behavior of expr.
Logged In: YES
user_id=148712
According to expr.n:
"If no numeric interpretation is possible, then an operand
is left as a string (and only a limited set of operators
may be applied to it)."
As I understand that, the following is indeed a bug:
% set a 08
08
% expr $a
"08" is an invalid octal number
% expr 08
"08" is an invalid octal number
The source of misunderstanding is obviously in "no numeric
representation is possible": tcl seems to say that "08" can
be represented as a number, which happens to be invalid -
I'd rather say that 08 cannot be represented as a number.
In the same vein, how should we interpret a string of digits
that is too large to represent as an integer: "an integer
too large to represent", or "a string that cannot be
represented as a number"?
Logged In: YES
user_id=72656
I don't think you are reading the docs right (or they
aren't written clearly). 'expr foo' fails as well, but
expr {"foo"} and expr {"08"} are both OK.
Logged In: NO
Boy, if I went so far off-topic in one of my bug reports
here I would be flayed alive.
The problem, whatever caused it, is that the error message
reported per my original bug report is wrong by anybody's
measure of wrongness... except possibly Ariel Sharon,
whose measure seems to have a directional component which
makes it unreliable.
Logged In: YES
user_id=148712
Indeed; the cause of the bug is that the error handler for
operations in the bc engine (IllegalExprOperandType) assumes
that it can only get empty strings, bad octals or (default)
floating point values. So, a superficial fix just touches that.
The issue that is worrying me is: is this really a "bad
operand" issue, or should the error have been caught
earlier? As there are two different execution paths for
[expr] (braced vs unbraced), and they seem to behave
differently ...
Anyway, I'll fix the immediate issue and log a new bug
report with the deeper one. Sorry for messing up the discussion.
Logged In: YES
user_id=72656
I believe the reason that the compiled object version fails
with a different message is that it will first try and get
it with GetIntFromObj, which fails. It then tries
GetDoubleFromObj, which succeeds (because strtod has larger
range acceptance), but then fails as doubles (floats)
aren't accepted for abs.
In the static case, it fails because it succeeds the
LooksLikeInt, which means it is either an acceptable int or
one too large to represent.
Quite simple, no?
In the first case, it's Tcl that sub's end and begin, not
the expr parser, so you get the too large int again.
Logged In: YES
user_id=148712
No, it never gets to 'abs'; note that it is '-' complaining
about a non valid operand. Doubles are acceptable operands
for 'abs'.
Look at what is happening in INST_SUB: TclLooksLikeInt
returns 1, so GetIntFromObj is called and it fails, so that
IllegalExprOperandType gets called. GetDoubleFromObj is
never called (it is called only when TclLooksLikeInt fails).
The problem is indeed that IllegalExprOperandType is not
expecting to receive "too large integers". The local fix
there will produce something like
% expr { abs($end - $begin) }
can't use integer value too large to represent as operand of
"-"
The case
% expr abs($end - $begin)
integer value too large to represent
is caught earlier, before subtraction is ever attempted.
Logged In: YES
user_id=79902
Problem is really that GET_WIDE_OR_INT (really just
Tcl_Get(Wide)IntFromObj) is failing due to integer range
overflow, and the code as it stands does not check for that
error case. However, you can't always feed the value to
parse into Tcl_GetDoubleFromObj when GET_WIDE_OR_INT fails
due to things like invalid octal. What's worse, the nature
of the failure has vanished at this point because
GET_WIDE_OR_INT does not use an interpreter, and
Tcl_Get(Wide)IntFromObj resets errno... :^(
Logged In: YES
user_id=148712
Enclosing a patch for tcl8.3 sources that fixes the
immediate issue.
Logged In: YES
user_id=148712
Patch for tcl8.4 attached; committed to both HEAD and
core-8-3-1-branch.
The initial issue is solved; bug report #545661 was opened
for the dependence of [expr]'s error handling on the timeof
compilation.