#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
Determine machine-specific parameters affecting floating-point
arithmetic.
Function to determine machine-specific parameters affecting
floating-point arithmetic.
* This is build after "NUMERICAL RECIPES in C", second edition,
Reprinted 1996, pp. 889.
"""
# Standard library imports.
import math
from functools import lru_cache
__date__ = "2022/07/30 19:09:33 hoel"
__author__ = "Berthold Höllmann"
__copyright__ = "Copyright © 1999, 2000,2018 by Berthold Höllmann"
__credits__ = ["Berthold Höllmann"]
__maintainer__ = "Berthold Höllmann"
__email__ = "bhoel@starship.python.net"
[docs]def machar():
"""
Determines and returns machine-specific parameters affecting
floating-point arithmetic.
Returns:
dict: Values in result dictionary are:
``ibeta`` (int)
The radix in which numbers are represented, almost
always 2, but occasionally 16, or even 10
``it`` (int)
The number of base-``ibeta`` digits in the floating point
mantissa
``machep`` (int)
Is the exponent of the smallest (most negative) power if ``ibeta``
that, added to 1.0 gives something different from 1.0.
``eps`` (float)
Is the floating-point number ``ibeta`` ** ``machdep``, loosly
referred to as the *floating-point precision*.
``negep`` (int)
Is the exponenet of the smalles power of ``ibeta`` that, subtracted from
1.0, gives something different from 1.0.
``epsneg`` (float)
Is ``ibeta`` ** ``negep``, another way of defining floating-point precision.
Not infrequently ``epsneg`` is 0.5 times ``eps``; occasionally ``eps`` and ``epsneg``
are equal.
``iexp`` (int)
Is the number of bits in the exponent (including its sign or bias)
``minexp`` (int)
Is the smallest (most negative) power if ``ibeta`` consistent with there no
leading zeros in the mantissa.
``xmin`` (float)
Is the floating-point number ``ibeta`` ** ``minexp``, generally the smallest
(in magnitude) usable floating value
``maxexp`` (int)
Is the smallest (positive) power of ``ibeta`` that causes overflow.
``xmax`` (float)
Is (1 - ``epsneg``) x ``ibeta`` ** ``maxexp``, generally the largest (in magnitude)
usable floating value.
``irnd`` (int)
Returns a code in the range 0...5, giving information on what kind of rounding is done
in addition, and on how underflow is handled.
If ``irnd`` returns 2 or 5, then your computer is compilant with the IEEE standard for
rounding. If it returns 1 or 4, then it is doing some kind of rounding, but not the IEEE
standard. If ``irnd`` returns 0 or 3, then it is truncating the result, not rounding it.
``ngrd`` (int)
Is the number of *guard digits* used when truncating the product of two mantissas to fit
the representation
This is taken from "NUMERICAL RECIPES in C", second edition,
Reprinted 1996.
"""
one = float(1)
two = one + one
zero = one - one
# Determine ``ibeta`` and ``beta`` by the method of M. Malcom.
a = temp1 = one
while temp1 - one == zero:
a += a
temp = a + one
temp1 = temp - a
b = one
itemp = 0
while itemp == 0:
b += b
temp = a + b
itemp = int(temp - a)
ibeta = itemp
beta = float(ibeta)
# Determine ``it`` and ``irnd``.
it = 0
b = temp1 = one
while temp1 - one == zero:
it = it + 1
b = beta * b
temp = b + one
temp1 = temp - b
irnd = 0
betah = beta / two
temp = a + betah
if temp - a != zero:
irnd = 1
tempa = a + beta
temp = tempa + betah
if irnd == 0 and temp - tempa != zero:
irnd = 2
# Determine ``negep`` und ``epsneg``.
negep = it + 3
betain = one / beta
a = one
i = 1
while i <= negep:
i = i + 1
a = betain * a
b = a
while 1:
temp = one - a
if temp - one != zero:
break
a = beta * a
negep = negep - 1
negep = -negep
epsneg = a
# Determine ``machdep`` and ``eps``.
machdep = -it - 3
a = b
while 1:
temp = one + a
if temp - one != zero:
break
a = a * beta
machdep = machdep + 1
eps = a
# Deterrmine ``ngrd``.
ngrd = 0
temp = one + eps
if irnd == 0 and temp * one - one != zero:
ngrd = 1
# Determine ``iexp``.
i = 0
k = 1
z = betain
t = one + eps
nxres = 0
while 1: # Loop until underflow ocurs, then exit.
y = z
z = y * y
a = z * one # check for underflow
temp = z * t
if a + a == zero or math.fabs(z) >= y:
break
temp1 = temp * betain
if temp1 * beta == z:
break
i = i + 1
k = k + k
if ibeta != 10:
iexp = i + 1
mx = k + k
else: # For decimal machines only
iexp = i + i
iz = ibeta
while k >= iz:
iz = ibeta * iz
iexp = iexp + 1
mx = iz + iz - 1
# To determine ``minexp`` and ``xmin``, loop until an underflow
# occurs, then exit.
while 1:
xmin = y
y = betain * y
a = y * one # Check here for the underflow
temp = y * t
if a + a != zero or math.fabs(y) < xmin:
k = k + 1
temp1 = temp * betain
if temp1 * beta == y and temp != y:
nxres = 3
xmin = y
break
else:
break
minexp = -k
# Determine maxexp, xmax.
if mx <= k + k + 3 and ibeta != 10:
mx = mx + mx
iexp = iexp + 1
maxexp = mx + minexp
irnd = nxres + irnd # Adjust ``irnd`` to reflect partial underflow
if irnd >= 2:
maxexp = maxexp - 2 # Adjust for IEEE-stype machines
i = maxexp + minexp
# Adjust for machines with implicit leading bit in binary mantissa,
# and machines with radix point at extreme right of mantissa.
if ibeta == 2 and not i:
maxexp = maxexp - 1
if i > 20:
maxexp = maxexp - 1
if a != y:
maxexp = maxexp - 2
xmax = one - epsneg
if xmax * one != xmax:
xmax = one - beta * epsneg
xmax = xmax / (xmin * beta * beta * beta)
i = maxexp + minexp + 3
j = 1
while j <= i:
j = j + 1
if ibeta == 2:
xmax = xmax + xmax
else:
xmax = xmax * beta
return {
"ibeta": ibeta,
"it": it,
"irnd": irnd,
"ngrd": ngrd,
"machdep": machdep,
"negep": negep,
"iexp": iexp,
"minexp": minexp,
"maxexp": maxexp,
"eps": eps,
"epsneg": epsneg,
"xmin": xmin,
"xmax": xmax,
}
__tmp = machar()
ibeta = __tmp["ibeta"]
"""``ibeta`` (int)
The radix in which numbers are represented, almost
always 2, but occasionally 16, or even 10
"""
it = __tmp["it"]
"""``it`` (int)
The number of base-``ibeta`` digits in the floating point
mantissa
"""
machdep = __tmp["machdep"]
"""``machep`` (int)
Is the exponent of the smallest (most negative) power if ``ibeta``
that, added to 1.0 gives something different from 1.0.
"""
eps = __tmp["eps"]
"""``eps`` (float)
Is the floating-point number ``ibeta`` ** ``machdep``, loosly
referred to as the *floating-point precision*.
"""
negep = __tmp["negep"]
"""``negep`` (int)
Is the exponenet of the smalles power of ``ibeta`` that, subtracted from
1.0, gives something different from 1.0.
"""
epsneg = __tmp["epsneg"]
"""``epsneg`` (float)
Is ``ibeta`` ** ``negep``, another way of defining floating-point precision.
Not infrequently ``epsneg`` is 0.5 times ``eps``; occasionally ``eps`` and ``epsneg``
are equal.
"""
iexp = __tmp["iexp"]
"""``iexp`` (int)
Is the number of bits in the exponent (including its sign or bias)
"""
minexp = __tmp["minexp"]
"""``minexp`` (int)
Is the smallest (most negative) power if ``ibeta`` consistent with there no
leading zeros in the mantissa.
"""
xmin = __tmp["xmin"]
"""``xmin`` (float)
Is the floating-point number ``ibeta`` ** ``minexp``, generally the smallest
(in magnitude) usable floating value
"""
maxexp = __tmp["maxexp"]
"""``maxexp`` (int)
Is the smallest (positive) power of ``ibeta`` that causes overflow.
"""
xmax = __tmp["xmax"]
"""``xmax`` (float)
Is (1 - ``epsneg``) x ``ibeta`` ** ``maxexp``, generally the largest (in magnitude)
usable floating value.
"""
irnd = __tmp["irnd"]
"""``irnd`` (int)
Returns a code in the range 0...5, giving information on what kind of rounding is done
in addition, and on how underflow is handled.
If ``irnd`` returns 2 or 5, then your computer is compilant with the IEEE standard for
rounding. If it returns 1 or 4, then it is doing some kind of rounding, but not the IEEE
standard. If ``irnd`` returns 0 or 3, then it is truncating the result, not rounding it.
"""
ngrd = __tmp["ngrd"]
"""``ngrd`` (int)
Is the number of *guard digits* used when truncating the product of two mantissas to fit
the representation"
"""
# Local Variables:
# mode: python
# compile-command: "python ../../setup.py test"
# time-stamp-pattern: "30/__date__ = \"%:y/%02m/%02d %02H:%02M:%02S %u\""
# End: