Source code for berhoel.helper.machar

#! /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: