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.
Szabó László Zoltán
2012-05-28
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.
Donal K. Fellows
2012-05-28
Donal K. Fellows
2012-05-28
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).