1
% expr 60.9-59.7
1.1999999999999957

It seems that in the above example expr outputs the result of the floating point operation in higher precision that it computes.

For something that simple I would expect a more reasonable output, such as output by this C++ code:

#include <iostream>
int main() 
{
    double a = 60.9;
    a -= 59.7;
    std::cout << "double a = " << a << std::endl;
    float b = 60.9;
    b -= 59.7;
    std::cout << "float b = " << b << std::endl;  
}

Output:

double a = 1.2
float b = 1.2

Thus the questions:

Why does TCL output the expr results in higher precision than it computes them, thus causing lsb artifacts?

Is it possible to prevent that travesty, perhaps by setting something like a global precision variable or global output resolution variable or something like that?

Michael
  • 5,775
  • 2
  • 34
  • 53
  • 2
    It's simply because in C and C++ the default precision is 6, therefore after rounding to 6 decimal digits, 1.1999999... become 1.2. It's not because tcl is calculating in higher precision – phuclv Jul 03 '15 at 03:44

3 Answers3

2

There is a global variable that controls how many places of precision Tcl uses when converting to strings: tcl_precision. However, looking it up for this answer, I discovered that since last I used it that it's been deprecated, and that display control using the format command is preferred. See http://wiki.tcl.tk/1650 for details on how to use it and why you shouldn't.

Note that you will have the same issue with C++; this is an issue with the IEEE format of floating point numbers, not with Tcl. The "excess" precision you're complaining about is merely the effect of displaying the exact value of the output without formatting it to meet your needs. The difference here between C/C++ & Tcl is that the default precision of formatted C output is 6 digits.

Erik Johnson
  • 1,136
  • 6
  • 17
1

This answer indicates that, for C++, this issue comes up too.

You have no control over the value of the result. You want to control how you output it:

% expr 60.9-59.7
1.1999999999999957
% puts [format {%.2f} [expr {60.9-59.7}]]
1.20
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
0

Floating point arithmetic is performed by Tcl's runtime, which is compiled from C. It works exactly the same as floating point arithmetic in any other executable compiled from C/C++. However, in Tcl, unlike C/C++, the string representation might be used for further calculations*, which means that arbitrary loss of precision would be a Bad Thing.

You can replace the normal puts command with a command that basically looks like this (just a proof-of-concept: in practice you would need a bit more infrastructure to 1) deal with extra arguments, to 2) avoid it working differently in puts-capturing shells, and 3) to return some control over this to the programmer, but it's quite feasible):

proc _puts str {
    if {[string is double -strict $str]} {
        puts [format %g $str]
    } else {
        puts $str
    }
}

This would print rounded floating point numbers by default.

*) Since a few decades back, Tcl code is byte-compiled to use actual floating point values stored together with their string representations, but the compiler still bows to the programmer's wishes if they decide to go with the s.r. for some reason. The ability to trust the s.r. to be "lossless" is a part of the contract between the language and the programmer and is unlikely to change.

Peter Lewerin
  • 13,140
  • 1
  • 24
  • 27