/usr/share/tcltk/tcllib1.17/math/machineparameters.tcl is in tcllib 1.17-dfsg-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | # machineparameters.tcl --
# Compute double precision machine parameters.
#
# Description
# This the Tcl equivalent of the DLAMCH LAPCK function.
# In floating point systems, a floating point number is represented
# by
# x = +/- d1 d2 ... dt basis^e
# where digits satisfy
# 0 <= di <= basis - 1, i = 1, t
# with the convention :
# - t is the size of the mantissa
# - basis is the basis (the "radix")
#
# References
#
# "Algorithms to Reveal Properties of Floating-Point Arithmetic"
# Michael A. Malcolm
# Stanford University
# Communications of the ACM
# Volume 15 , Issue 11 (November 1972)
# Pages: 949 - 951
#
# "More on Algorithms that Reveal Properties of Floating
# Point Arithmetic Units"
# W. Morven Gentleman, University of Waterloo
# Scott B. Marovich, Purdue University
# Communications of the ACM
# Volume 17 , Issue 5 (May 1974)
# Pages: 276 - 277
#
# Example
#
# In the following example, one compute the parameters of a desktop
# under Linux with the following Tcl 8.4.19 properties :
#
#% parray tcl_platform
#tcl_platform(byteOrder) = littleEndian
#tcl_platform(machine) = i686
#tcl_platform(os) = Linux
#tcl_platform(osVersion) = 2.6.24-19-generic
#tcl_platform(platform) = unix
#tcl_platform(tip,268) = 1
#tcl_platform(tip,280) = 1
#tcl_platform(user) = <username>
#tcl_platform(wordSize) = 4
#
# The following example creates a machineparameters object,
# computes the properties and displays it.
#
# set pp [machineparameters create %AUTO%]
# $pp compute
# $pp print
# $pp destroy
#
# This prints out :
#
# Machine parameters
# Epsilon : 1.11022302463e-16
# Beta : 2
# Rounding : proper
# Mantissa : 53
# Maximum exponent : 1024
# Minimum exponent : -1021
# Overflow threshold : 8.98846567431e+307
# Underflow threshold : 2.22507385851e-308
#
# That compares well with the results produced by Lapack 3.1.1 :
#
# Epsilon = 1.11022302462515654E-016
# Safe minimum = 2.22507385850720138E-308
# Base = 2.0000000000000000
# Precision = 2.22044604925031308E-016
# Number of digits in mantissa = 53.000000000000000
# Rounding mode = 1.00000000000000000
# Minimum exponent = -1021.0000000000000
# Underflow threshold = 2.22507385850720138E-308
# Largest exponent = 1024.0000000000000
# Overflow threshold = 1.79769313486231571E+308
# Reciprocal of safe minimum = 4.49423283715578977E+307
#
# Copyright 2008 Michael Baudin
#
package require snit
package provide math::machineparameters 0.1
snit::type machineparameters {
# Epsilon is the smallest value so that 1+epsilon>1 is false
variable epsilon 0
# basis is the basis of the floating-point representation.
# basis is usually 2, i.e. binary representation (for example IEEE 754 machines),
# but some machines (like HP calculators for example) uses 10, or 16, etc...
variable basis 0
# The rounding mode used on the machine.
# The rounding occurs when more than t digits would be required to
# represent the number.
# Two modes can be determined with the current system :
# "chop" means than only t digits are kept, no matter the value of the number
# "proper" means that another rounding mode is used, be it "round to nearest",
# "round up", "round down".
variable rounding ""
# the size of the mantissa
variable mantissa 0
# The first non-integer is A = 2^m with m is the
# smallest positive integer so that fl(A+1)=A
variable firstnoninteger 0
# Maximum number of iterations in loops
option -maxiteration 10000
# Set to 1 to enable verbose logging
option -verbose -default 0
# The largest positive exponent before overflow occurs
variable exponentmax 0
# The largest negative exponent before (gradual) underflow occurs
variable exponentmin 0
# Largest positive value before overflow occurs
variable vmax
# Largest negative value before (gradual) underflow occurs
variable vmin
#
# compute --
# Computes the machine parameters.
#
method compute {} {
$self log "compute"
$self computeepsilon
$self computefirstnoninteger
$self computebasis
$self computerounding
$self computemantissa
$self computeemax
$self computeemin
return ""
}
#
# computeepsilon --
# Find epsilon the minimum value for which 1.0 + epsilon > 1.0
#
method computeepsilon {} {
$self log "computeepsilon"
set factor 2.
set epsilon 0.5
for {set i 0} {$i<$options(-maxiteration)} {incr i} {
$self log "$i/$options(-maxiteration) : $epsilon"
set epsilon [expr {$epsilon / $factor}]
set inequality [expr {1.0+$epsilon>1.0}]
if {$inequality==0} then {
break
}
}
$self log "epsilon : $epsilon (after $i loops)"
return ""
}
#
# computefirstnoninteger --
# Compute the first positive non-integer real.
# It is the smallest a such that (a+1)-a is different from 1
#
method computefirstnoninteger {} {
$self log "computefirstnoninteger"
set firstnoninteger 2.
for {set i 0} {$i < $options(-maxiteration)} {incr i} {
$self log "$i/$options(-maxiteration) : $firstnoninteger"
set firstnoninteger [expr {2.*$firstnoninteger}]
set one [expr {($firstnoninteger+1.)-$firstnoninteger}]
if {$one!=1.} then {
break
}
}
$self log "Found firstnoninteger : $firstnoninteger"
return ""
}
#
# computebasis --
# Compute the basis (basis)
#
method computebasis {} {
$self log "computebasis"
#
# Compute b where b is the smallest real so that fl(a+b)> a,
# where a is the first non integer.
# Note :
# With floating point numbers, a+1==a !
# b is denoted by "B" in Malcolm's algorithm
#
set b 1
for {set i 0} {$i < $options(-maxiteration)} {incr i} {
$self log "$i/$options(-maxiteration) : $b"
set basis [expr {int(($firstnoninteger+$b)-$firstnoninteger)}]
if {$basis!=0.} then {
break
}
incr b
}
$self log "Found basis : $basis"
return ""
}
#
# computerounding --
# Compute the rounding mode.
# Note:
# This corresponds to DLAMCH implementation (DLAMC1 exactly).
#
method computerounding {} {
$self log "computerounding"
# Now determine whether rounding or chopping occurs, by adding a
# bit less than beta/2 and a bit more than beta/2 to a (=firstnoninteger).
set F [expr {$basis/2.0 - $basis/100.0}]
set C [expr {$F + $firstnoninteger}]
if {$C==$firstnoninteger} then {
set rounding "proper"
} else {
set rounding "chop"
}
set F [expr {$basis/2.0 + $basis/100.0}]
set C [expr {$F + $firstnoninteger}]
if {$rounding=="proper" && $C==$firstnoninteger} then {
set rounding "chop"
}
$self log "Found rounding : $rounding"
return ""
}
#
# computemantissa --
# Compute the mantissa size
#
method computemantissa {} {
$self log "computemantissa"
set a 1.
set mantissa 0
for {set i 0} {$i < $options(-maxiteration)} {incr i} {
incr mantissa
$self log "$i/$options(-maxiteration) : $mantissa"
set a [expr {$a * double($basis)}]
set one [expr {($a+1)-$a}]
if {$one!=1.} then {
break
}
}
$self log "Found mantissa : $mantissa"
return ""
}
#
# computeemax --
# Compute the maximum exponent before overflow
#
method computeemax {} {
$self log "computeemax"
set vmax 1.
set exponentmax 1
for {set i 0} {$i < $options(-maxiteration)} {incr i} {
$self log "Iteration #$i , exponentmax = $exponentmax, vmax = $vmax"
incr exponentmax
# Condition #1 : no exception is generated
set errflag [catch {
set new [expr {$vmax * $basis}]
}]
if {$errflag!=0} then {
break
}
# Condition #2 : one can recover the original number
if {$new / $basis != $vmax} then {
break
}
set vmax $new
}
incr exponentmax -1
$self log "Exponent maximum : $exponentmax"
$self log "Value maximum : $vmax"
return ""
}
#
# computeemin --
# Compute the minimum exponent before underflow
#
method computeemin {} {
$self log "computeemin"
set vmin 1.
set exponentmin 1
for {set i 0} {$i < $options(-maxiteration)} {incr i} {
$self log "Iteration #$i , exponentmin = $exponentmin, vmin = $vmin"
incr exponentmin -1
# Condition #1 : no exception is generated
set errflag [catch {
set new [expr {$vmin / $basis}]
}]
if {$errflag!=0} then {
break
}
# Condition #2 : one can recover the original number
if {$new * $basis != $vmin} then {
break
}
set vmin $new
}
incr exponentmin +1
# See in DMALCH.f, DLAMC2 relative to IEEE machines.
# TODO : what happens on non-IEEE machine ?
set exponentmin [expr {$exponentmin - 1 + $mantissa}]
set vmin [expr {$vmin * pow($basis,$mantissa-1)}]
$self log "Exponent minimum : $exponentmin"
$self log "Value minimum : $vmin"
return ""
}
#
# log --
# Puts the given message on standard output.
#
method log {msg} {
if {$options(-verbose)==1} then {
puts "(mp) $msg"
}
return ""
}
#
# get --
# Return value for key
#
method get {key} {
$self log "get $key"
switch -- $key {
-epsilon {
set result $epsilon
}
-rounding {
set result $rounding
}
-basis {
set result $basis
}
-mantissa {
set result $mantissa
}
-exponentmax {
set result $exponentmax
}
-exponentmin {
set result $exponentmin
}
-vmax {
set result $vmax
}
-vmin {
set result $vmin
}
default {
error "Unknown key $key"
}
}
return $result
}
#
# print --
# Print machine parameters on standard output
#
method print {} {
set str [$self tostring]
puts "$str"
return ""
}
#
# tostring --
# Return a report for machine parameters
#
method tostring {} {
set str ""
append str "Machine parameters\n"
append str "Epsilon : $epsilon\n"
append str "Basis : $basis\n"
append str "Rounding : $rounding\n"
append str "Mantissa : $mantissa\n"
append str "Maximum exponent before overflow : $exponentmax\n"
append str "Minimum exponent before underflow : $exponentmin\n"
append str "Overflow threshold : $vmax\n"
append str "Underflow threshold : $vmin\n"
return $str
}
}
|