In my script I have to convert a number to a multiple of 1024. I have
run into a problem whereby tcl seems to think any number below 1 is the
integer zero.
Example, if $x = 1043, my formula is:
[1] set $y [expr $x / 53 * 48 /1000 ] = 0.9446~, but returns zero
I then want to go on to:
[2] set $z [expr round($y)] = 1
[3] set $newx [expr $z * 1024] = 1024
(I am sure these steps can be condensed but just to illustrate what I
have to do)
How can I get tcl to return the value 1 for step [1]?
cheers,
Ben
p.s. I can actually see now that ANY number less than the integer gets
rounded DOWN, i.e 2.944 = 2, 3.123 = 3 etc.
Can I get around this?
> >
> > p.s. I can actually see now that ANY number less than the integer gets
> > rounded DOWN, i.e 2.944 = 2, 3.123 = 3 etc.
> > Can I get around this?
> >
> >
> Just figured out if you make one of the number a decimal (e.g. 1000.0)
> then it gives you the correct answer.
Yes, the problem is that integers divided by another integer come out
as integers again. This is a very deliberate design choice - it is
consistent with most programming languages, but it can be a surprise
to someone new to programming (*).
The Wiki (<http://wiki.tcl.tk>) has a lot of information on dealing
with numbers (both integer and real), but it is a wee bit scattered
(**)
To summarise:
- integer divides are truncated
- Use the double() and round() functions to achieve other modes
of operation.
For instance:
set tcl_precision 17 ;# Expressly: to show imperfections with real
numbers!
expr {4/3} ==> 1
expr {4/-3} ==> -1
expr {double(4)/3} ==> 1.3333333333333333
expr {3*(double(4)/30) } ==> 0.40000000000000002 ;# 0.4 can not be
represented exactly
Welcome to the wonderful world of computer arithmetic :)
Regards,
Arjen
(*) I have been dealing with integers and reals for some two decades
now, but even
I stumble into this trap at times ;)
(**) Mental note: how about a concise explanation on the Wiki and in the
tutorial
>> p.s. I can actually see now that ANY number less than the integer gets
>> rounded DOWN, i.e 2.944 = 2, 3.123 = 3 etc.
>> Can I get around this?
>Just figured out if you make one of the number a decimal (e.g. 1000.0)
>then it gives you the correct answer.
Just for the record: You can get integer division to do
round-to-nearest instead of round-towards-minus-infinity, by
this simple trick:
To get round-to-nearest you need to add 0.5 to the result. For
the division calculation Q=N/M we can get the same effect thus:
Q(rounded) = (N+M/2)/M
= (2*N+M)/(2*M)
This final version of the calculation can be done entirely in
integer arithmetic, and will successfully yield the nearest integer
to the required quotient. The multiplications by 2 are, of course,
simply left shifts - which makes them very cheap if you are trying
to do this in hand-coded assembler on a nasty little 8-bit micro,
as I have done for my sins very many times in the past :-(
--
Jonathan Bromley, Consultant
DOULOS - Developing Design Know-how
VHDL, Verilog, SystemC, Perl, Tcl/Tk, Verification, Project Services
Doulos Ltd. Church Hatch, 22 Market Place, Ringwood, BH24 1AW, UK
Tel: +44 (0)1425 471223 mail:jonathan...@doulos.com
Fax: +44 (0)1425 471573 Web: http://www.doulos.com
The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
B> Ben wrote:
B> > I am fairly new to programming languages although I have been playing
B> > with expect/tcl for 6 months.
B> >
B> > In my script I have to convert a number to a multiple of 1024. I have
B> > run into a problem whereby tcl seems to think any number below 1 is the
B> > integer zero.
B> >
B> > Example, if $x = 1043, my formula is:
B> >
B> > [1] set $y [expr $x / 53 * 48 /1000 ] = 0.9446~, but returns zero
B> >
B> > I then want to go on to:
B> >
B> > [2] set $z [expr round($y)] = 1
B> > [3] set $newx [expr $z * 1024] = 1024
B> >
B> > (I am sure these steps can be condensed but just to illustrate what I
B> > have to do)
B> >
B> > How can I get tcl to return the value 1 for step [1]?
B> >
B> > cheers,
B> >
B> > Ben
B> >
B> > p.s. I can actually see now that ANY number less than the integer gets
B> > rounded DOWN, i.e 2.944 = 2, 3.123 = 3 etc.
B> > Can I get around this?
B> >
B> >
B> Just figured out if you make one of the number a decimal (e.g. 1000.0)
B> then it gives you the correct answer.
This forces the math to use floating pointing numbers. You can also use
the double() function to do this also:
set $y [expr double($x / double(53 * 48)) / double(1000) ]
B>
\/
Robert Heller ||InterNet: hel...@cs.umass.edu
http://vis-www.cs.umass.edu/~heller || hel...@deepsoft.com
http://www.deepsoft.com /\FidoNet: 1:321/153
> Example, if $x = 1043, my formula is:
>
> [1] set $y [expr $x / 53 * 48 /1000 ] = 0.9446~, but returns zero
>
Just make one number a "Real" number:
"set $y [expr $x / 53.0 * 48 /1000 ]" will do the trick ;-)
Shin - A.k.a. Thomas Braun