Menu

#4550 expr abs(0.0) is -0.0

obsolete: 8.5.8
closed-fixed
7
2010-02-23
2010-02-19
No

% expr abs(0.0)
-0.0

Tcl version is 8.5.5, but it guess it's also in CVS (core-8-5-branch):

tclBasic.c (abs function)
7437 if (d <= 0.0) {
7438 Tcl_SetObjResult(interp, Tcl_NewDoubleObj(-d));
7439 } else {
7440 Tcl_SetObjResult(interp, objv[1]);
7441 }

should be

7437 if (d < 0.0) {
7438 Tcl_SetObjResult(interp, Tcl_NewDoubleObj(-d));
7439 } else {
7440 Tcl_SetObjResult(interp, objv[1]);
7441 }

Discussion

  • Jan Nijtmans

    Jan Nijtmans - 2010-02-19

    Yes, this problem is in head as well.

    And the same for TCL_NUMBER_LONG. There
    the "<=" should be "<" as well. The effect is only
    the unnecessary creation of an object, but still.....

     
  • Don Porter

    Don Porter - 2010-02-19

    Please fix. Thanks!

     
  • Don Porter

    Don Porter - 2010-02-19
    • assigned_to: dgp --> nijtmans
     
  • Jan Nijtmans

    Jan Nijtmans - 2010-02-19

    Turns out not that trivial to fix. See: also [Bug 1893815]
    tcl::mathfunc commands and non-canonical string reps

     
  • Jan Nijtmans

    Jan Nijtmans - 2010-02-21

    Fixed in HEAD, to be backported to 8.5 and 8.4

     
  • Donal K. Fellows

    • milestone: --> 874763
    • priority: 5 --> 7
    • status: open --> open-fixed
     
  • Jan Nijtmans

    Jan Nijtmans - 2010-02-22

    Added some more tests, just to prove that the TCL_NUMBER_LONG was not quite right either. The problem
    is that in ieee floating point math, -0.0 == 0.0 gives true! This means that you cannot really distinguish
    -0.0 and 0.0 in floating point math.

    Looking at the test cases, the rule seems to be:
    - If the input looks negative, take the negative of the output and take that as a result.
    - otherwise, take the unchanged input.

    No, what looks negative? For example, -0.0 and -0 look negative, but really are
    not: they are both forms of zero! Still, we want to output resp. 0.0 and 0 in those
    cases. So, we need to distinguish between -0.0 and 0.0 (in the float case) and
    between 0 and -0 (in the long case). How do we do that.

    In the float case, we can use memcmp(). In the long case, I see no other way to look
    for ´-´ characters (if there is a string representation). Anyway, this way I could
    make all test cases pass.

    For 8.4 the story is a little bit different. The only 'mistake' was that abs(-0.0) returns
    -0.0, which is in fact correct, but not expected regarding the above rules. Numbers
    like 1e-324 result in an underflow immediately in 8.4, it seems not worth to
    fix that. But the abs(-0.0) case still can be fixed, therefore leaving this issue open.

     
  • Jan Nijtmans

    Jan Nijtmans - 2010-02-22
    • milestone: 874763 --> obsolete: 8.5.8
     
  • Donal K. Fellows

    In the 'long' case, if you've got -0 then you're on a ones-complement machine and we no longer guarantee Tcl to work right. :-)

     
  • Jan Nijtmans

    Jan Nijtmans - 2010-02-22

    >In the 'long' case, if you've got -0 then you're on a ones-complement
    >machine and we no longer guarantee Tcl to work right. :-)

    What happened, is that:
    expr {abs(0x0)} --> 0
    expr {abs(0x1)} --> 0x1
    I would at least expect the two answers to
    have the same form.... That's what this fix
    is about in the "long" case

     
  • Jan Nijtmans

    Jan Nijtmans - 2010-02-22

    Oh no, I meant
    ::tcl::mathfunc::abs 0x0 --> 0 (old output) 0x0 (new output)
    ::tcl::mathfunc::abs 0x1 --> 0x1
    That's what this fix is about regarding longs in Tcl 8.5/8.6. In
    Tcl 8.4 there is no ::tcl::mathfunc::abs, so this is no issue.

     
  • Jan Nijtmans

    Jan Nijtmans - 2010-02-23
    • status: open-fixed --> closed-fixed
     
  • Jan Nijtmans

    Jan Nijtmans - 2010-02-23

    Relevant test cases backported to Tcl 8.4 as well, and minor
    fix applied to tclExecute.c to make them all pass.
    DONE