Version 0 of expr problems with int

Updated 1999-08-20 19:57:49

Richard Suchenwirth - Mathematics with expr has some problems coming from the C implementation. On my NT box, and on most present-day computers, int is represented as a 32-bit signed "long". This means there is a limit, a.k.a. MAXINT, to what an integer can express:

 % expr 2147483647
 2147483647
 % expr 2147483648
 -2147483648

Probably not what was intended. From the given threshold, positives are recast to negatives, up to

 % expr 4294967295
 -1

and then you run into

 % expr 4294967296
 error: integer value too large to represent

You might consider using the multiple-precision extension called Mpexpr, which can handle integer and floating point numbers with large numbers of digits.

As an alternative, you gain some more computing power by converting such strings to floating-point variables. You gain the advantage of a wider range of values and (usually) more significant digits, but you do not have unlimited precision. (You can't count all the way to 10e300 by ones.) You also lose the ability to use the [incr] command, but you can always use [expr].

You cannot use expr's double() function to perform the conversion, because expr fails with the same integer conversion error (as above) before calling double().

One simple way of casting an "integerstring" to a "doublestring" is to append a dot:

 set x $i. ;# or: append i "."

This may however produce an ill-formed number if the numberstring contained a dot already. Hume Smith gave a clever solution in news:comp.lang.tcl :

 append i "e0"

makes it look like scientific notation, meaning "multiplied by 10 to the 0th power, which is 1", which forces the string to a floatstring (i.e. that expr interprets as double) with pure string manipulation. If there is the slightest possibility that scientific notation occurs in the input, make it bullet-proof like

 if ![regexp "e" $i] {append i "e0"}

Here's a solution from Donal Fellows that checks the error reason:

   # The absence of {curlies} from [expr] is crucial!
   if {[catch {expr double($int)} float]} {
       if {[string equal [lrange $::errorCode 0 1] "ARITH IOVERFLOW"]} {
           # We know we've got an int value now!
           set float [expr double($int.0)]
       } else {
           error "attempted conversion of non-numeric to float"
       }
   }

See also Bag of algorithms - Bag of Tk algorithms