round number to 2 decimal places - tcl

I need to round a number to two decimal places.
Right now the following rounds to the nearest integer I guess
puts [expr {round($total_rate)}]
If I do something like below it does not work. Is there another way around?
puts [expr {round($total_rate,2)}]

The simplest way to round to a specific number of decimal places is with format:
puts [format "%.2f" $total_rate]
Be aware that if you're using the rounded value for further calculations instead of display to users, most values that you print using rounding to X decimal places will not have an exact representation in binary arithmetic (which Tcl uses internally, like vast numbers of other programming languages). It's best to reserve rounding to a specific number of DPs to the point where you're showing values to people.

expr {double(round(100*$total_rate))/100}
example
% set total_rate 1.5678
1.5678
% expr {double(round(100*$total_rate))/100}
1.57
% set total_rate 1.4321
1.4321
% expr {double(round(100*$total_rate))/100}
1.43

puts [format "%.2f" $total_rate]
By using format, we can see the result in output but how to use the same value in the program, i.e., we can see 1.448 as 1.45 in the output but can we use 1.45 in the program then.

It is unclear whether the original question "I need to round a number" really was "I need to print out a rounded-off value of a number". The latter is really best answered with a [format ...], but the former could be interpreted as a need for a number of significant digits, i.e. how to adjust the number itself, and not just to format the printout string. I think the only answer that serves this purpose so far is the elegant one Donal Fellows has provided. However, for "significant digits" instead of "digits after the decimal" I think a small modification is in order: get the number to be between 1 and 10 first (or between 0.1 and 1, if that is your convention), then trim the number of digits after the decimal. Without that, something like roundto(0.00000001234567,4) will get you a zero.
proc tcl::mathfunc::roundto {value sigfigs} {
set pow [expr ($sigfigs-1)-floor(log10($value))]
expr {round(10**$pow*$value)/10.0**$pow}
}
expr roundto(0.000000123456789,5)
produces a value rounded off to 5 significant figures:
1.2346e-7

Related

Regex for float(x,y) possible?

In the following, float(x,y) means a number with x total digits and y decimals.
I am trying to do client side validation for an HTML Input field. The field corresponds to a MySQL column with data type float(x,y). I know I can define a pattern like float(5,2) with lots of 'ORs'. Is there an efficient way of generating a Regex for this such that I can encode it in my web document?
Something of a workaround is to specify \d+(\.\d{1,y})? and then set maxlength=x+1. Should be x+1 because the decimal place is counted. This would then allow the submit of an integer of length x+1 contrary to specification. I realize I can do JavaScript validation but I would like to achieve the desired with HTML validation.
You can first check the total length with a lookahead and then check for the length of numbers after the decimal point.
If you want X total number of digits and at most Y decimal points, you can use:
^(?=.{X+1}$)([1-9]\d*|0)\.\d{1,Y}$
Explanation:
^ asserts you are in the start position of the line
(?= lookahead (zero length) match for:
.{X + 1} X+1 characters
$ end of line //now you have asserted the total length
the whole part either
0 is a single zero
[1-9]\d* more than a single digit and does not start with zero
\. a dot for the decimal point
\d{1,Y} at least 1 and at most Y digits
$ asserts end of line
Note that you do not need to check the length of the whole part since you are already checking for the total length and the length of digits after the decimal so the part before the decimal point is automatically correct.
Example:
For X = 5 and Y = 2, you will have:
^(?=.{8}$)([1-9]\d*|0)\.\d{1,2}$
Regex101 demo

In tcl how do I get fractional part of given number

In tcl code, I want to get fractional part of given number.
I tried following code
set a 2.9999383
expr {fmod($a,1)} gives me 0.9999383000000002
How do I get correct fractional part without additional decimal digits ?
Thanks
You've discovered the fun to be had with floating point numbers! The trick is to get a guess of how many digits there are after the floating point (doesn't have to be too accurate!) and use that with format to do the rounding off.
format "%.*g" [string length $a] [expr {fmod($a, 1.0)}]
That produces 0.9999383 with your test data, and yet makes few assumptions about the input…
Floats are imprecise estimates. Those "extra digits" are simply a result of the system's best attempt to approximate a decimal in a base-two system.
You can round the float to get rid of the trailing 2:
format "%.2f" $a
You could use string split otherwise I guess:
set a 2.9999383
set fraction "0.[lindex [split $a "."] 1]"
puts $fraction
0.9999383
That'll avoid having to see whether the fraction got deformed and/or needs to be rounded or not.

How to configure Octave terminal to output numbers without scientific notation?

I am trying to print a long table of numbers in octave terminal.
disp(vec);
What I get
7.0931e-01
6.2041e-05
9.7740e-01
9.9989e-01
8.8428e-01
9.0524e-01
...
Such numerical notation is a pain to read. How can I set octave terminal to output numbers normally as 0.7, 0.014, 0.95?
You can use format short g to display each number is a more logical format
format short g
disp(vec)
% 0.70931
% 6.2041e-05
% 0.9774
% 0.99989
% 0.88428
% 0.90524
Using 'fprintf' could help in such cases
a=0.0001234;
fprintf('%.3f\n',a)
But here the limitation is that number of decimal points would be fixed so in some numbers it will display zeros at the end while for some numbers it might cut off the number.

Expr for float values in TCL

Calculating float values
tclsh
% expr 0.2+0.2
0.4
% expr 0.2+0.1
0.30000000000000004
%
Why not 0.3??
Am i missing some thing.
thanks in advance.
Neither 0.1 or 0.2 have an exact representation in IEEE double precision binary floating point arithmetic (which Tcl uses internally for expressions involving fractional values, as there's good hardware support for them). This means that the values you are computing with are never exactly what you think they are; instead, they're both very slightly more (as it happens; they could also have been slightly less in general). When you add 0.2+ε1+0.1+ε2, it can happen that ε1+ε2 can add up to more than the threshold where 0.3 (another imprecisely represented value) becomes the next exactly represented value above it. This is what you have observed. It's also inherent in the way floating point mathematics works in a vast array of languages; only integer arithmetic (or fractional arithmetic capable of being expressed as exact multiples of some power of 2, e.g., 0.5, 0.25, 0.125) is guaranteed to be exact.
The only interesting thing of note here is that Tcl 8.5 and 8.6 prefer to render floating point numbers with the minimal number of digits required to get the exact value back when re-parsed. If you want to get a fixed number of digits (e.g., 8) try using format when converting:
format %.8f [expr 0.2+0.1]
This behavior exists in almost all programming languages, e.g. Ruby, Python, etc.
The suggestion here is try to avoid storing numbers in floating points, use integer whenever possible. The bottom line is do not use floating points in a comparison.

Is there a "native" way to convert from numbers to dB in Tcl

dB or decibel is a unit that is used to show ratio in logarithmic scale, and specifecly, the definition of dB that I'm interested in is X(dB) = 20log(x) where x is the "normal" value, and X(dB) is the value in dB. When wrote a code converted between mil. and mm, I noticed that if I use the direct approach, i.e., multiplying by the ratio between the units, I got small errors on the opposite conversion, i.e.: to_mil [to_mm val_in_mil] wasn't equal to val_in_mil and the same with mm. The library units has solved this problem, as the conversions done by it do not have that calculation error. But the specifically doesn't offer (or I didn't find) the option to convert a number to dB in the library.
Is there another library / command that can transform numbers to dB and dB to numbers without calculation errors?
I did an experiment with using the direct math conversion, and I what I got is:
>> set a 0.005
0.005
>> set b [expr {20*log10($a)}]
-46.0205999133
>> expr {pow(10,($b/20))}
0.00499999999999
It's all a matter of precision. We often tend to forget that floating point numbers are not real numbers (in the mathematical sense of ℝ).
How many decimal digit do you need?
If you, for example, would only need 5 decimal digits, rounding 0.00499999999999 will give you 0.00500 which is what you wanted.
Since rounding fp numbers is not an easy task and may generate even more troubles, you might just change the way you determine if two numbers are equal:
>> set a 0.005
0.005
>> set b [expr {20*log10($a)}]
-46.0205999133
>> set c [expr {pow(10,($b/20))}]
0.00499999999999
>> expr {abs($a - $c) < 1E-10}
1
>> expr {abs($a - $c) < 1E-20}
0
>> expr {$a - $c}
8.673617379884035e-19
The numbers in your examples can be considered "equal" up to an error or 10-18. Note that this is just a rough estimate, not a full solution.
If you're really dealing with problems that are sensitive to numerical errors propagation you might look deeper into "numerical analysis". The article What Every Computer Scientist Should Know About Floating-Point Arithmetic or, even better, this site: http://floating-point-gui.de might be a start.
In case you need a larger precision you should drop your "native" requirement.
You may use the BigFloat offered by tcllib (http://tcllib.sourceforge.net/doc/bigfloat.html or even use GMP (the GNU multiple precision arithmetic library) through ffidl (http://elf.org/ffidl). There's an interface already defined for it: gmp.tcl
With the way floating point numbers are stored, every log10(...) can't correspond to exactly one pow(10, ...). So you lose precision, just like the integer divisions 89/7 and 88/7 both are 12.
When you put a value into floating point format, you should forget the ability to know it's exact value anymore unless you keep the old, exact value too. If you want exactly 1/200, store it as the integer 1 and the integer 200. If you want exactly the ten-logarithm of 1/200, store it as 1, 200 and the info that a ten-logarithm has been done on it.
You can fill your entire memory with the first x decimal digits of the square root of 2, but it still won't be the square root of 2 you store.