Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

## #619 New function in "expr": sgn()

open
5
2012-05-28
2012-05-26
No

There are functions double, int, floor and ceil for rounding floating point values in various mode, but e.g. floor(\$num) and ceil(\$num) are equivalent with round(\$num -+ 0.5). But the signum function can be implemented only with longer constructs.

## Discussion

• I would take back my example: "floor(\$num) and ceil(\$num) are equivalent with round(\$num -+ 0.5)" it is not right.
But not this is the point now.

• summary: New funcion in "expr": sgn() --> New function in "expr": sgn()

• Here's a complete workaround (modulo ensuring that \$x is numeric and handling NaN):

proc tcl::mathfunc::sgn {x} {
expr {\$x < 0 ? -1 : \$x > 0 ? 1 : 0}
}

The only question is whether Tcl should provide such a thing by default.

• Twylite
2012-05-28

is sgn() meant to be "sign()" as in DKF's example, or is it meant to be "round to a number of significant digits" as discussed below?

In Excel for example, =FLOOR(1.134, 0.01) rounds 1.134 down to the nearest multiple of 0.01, giving 1.13. Similarly =FLOOR(1.5, 0.4) gives 1.2. The =ROUND() function rounds to a number of digits, e.g. =ROUND(1.135, 2) gives 1.14.

The Excel functions combine a mathematical operation and an output formatting operation. The result of =FLOOR(1.134, 0.01) may not be accurately represented by a float or a double, so the floating point value is truncated for display purposes.

Rounding to a significant number of digits (as in =ROUND) as opposed to an exact significance (as in =FLOOR) is quite easy in Tcl:

proc round {d sgn} { format %0.\${sgn}f \$d }

Computing and displaying floor or ceiling to a specific precision is more complicated:

proc floor {d sgn} {
set prec [expr { int(ceil(-log(\$sgn)/log(10))) }]
format %0.\${prec}f [expr { floor(\$d / \$sgn) * \$sgn }]
}

A compromise may be to extend round, floor and ceil to take an optional second parameter (significance), and implement equivalent to:

proc round {d {sgn 1}} { expr { round(\$d / \$sgn) * \$sgn } }
proc floor {d {sgn 1}} { expr { floor(\$d / \$sgn) * \$sgn } }

This gives a mathematically accurate answer (within the constraints of floating point arithmetic), but does not attempt to format/truncate the output. This would be appropriate behaviour for [expr] in my opinion (but including formatting behaviour would not be appropriate).