Welcome, guest | Sign In | My Account | Store | Cart

Implements bitwise operations for real numbers by using an infinite one's complement representation.

Python, 120 lines
  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
"""This module defines bitwise operations on floating point numbers by pretending that they consist of an infinite sting of bits extending to the left as well as to the right.
More precisely the infinite string of bits b = [...,b[-2],b[-1],b[0],b[1],b[2],...] represents the number x = sum( b[i]*2**i for i in range(-inf,inf) ). Negative numbers are represented in one's complement. The identity 0.111... == 1.0 creates an ambiquity in the representation. To avoid it positive numbers are defined to be padded with zeros in both directions while negative numbers are padded with ones in both directions. This choice leads to the useful identity ~a == -a and allows +0 == ...000.000... to be the |-identity and -0 == ...111.111... to be the &-identity. Unfortunately the choice breaks compatibility with integer bitwise operations involving negative numbers."""

from math import frexp, copysign
from sys import float_info

__author__ = "Pyry Pakkanen"
__copyright__ = "Copyright 2011"
__credits__ = ["Pyry Pakkanen"]
__license__ = "MIT"
__version__ = "0.1"
__maintainer__ = "Pyry Pakkanen"
__email__ = "frostburn@suomi24.fi"
__status__ = "initial release"

fmax, max_exp, max_10_exp, fmin, min_exp, min_10_exp, dig, mant_dig, epsilon, radix, rounds = float_info

def ifrexp(x):
    """Get the mantissa and exponent of a floating point number as integers."""
    m,e = frexp(x)
    return int(m*2**mant_dig),e

def float_not(a):
    """~a"""
    return -a

def float_and(a,b):
    """a & b"""
    if a==0.0:
        if copysign(1.0,a)==1.0:
            return 0.0
        else:
            return b
    if b==0.0:
        return float_and(b,a)

    if a<0 and b<0:
        return -float_or(-a,-b)

    if abs(a)>=abs(b):
        return float_and_(a,b)
    else:
        return float_and_(b,a)    

def float_or(a,b):
    """a | b"""
    if a==0.0:
        if copysign(1.0,a)==1.0:
            return b
        else:
            return -0.0
    if b==0.0:
        return float_or(b,a)

    if a<0 and b<0:
        return -float_and(-a,-b)
        
    if abs(a)>=abs(b):
        return float_or_(a,b)
    else:
        return float_or_(b,a)


def float_xor(a,b):
    """a ^ b"""
    if a==0.0:
        if copysign(1.0,a)==1.0:
            return b
        else:
            return -b
    if b==0.0:
        return float_xor(b,a)

    if a<0:
        if b<0:
            return float_xor(-a,-b)
        else:
            return -float_xor(-a,b)
    if b<0:
        return -float_xor(a,-b)
            
    if abs(a)>=abs(b):
        return float_xor_(a,b)
    else:
        return float_xor_(b,a)

#The helper functions assume that exponent(a) >= exponent(b).
#The operation lambda x: ~(-x) converts between two's complement and one's complement representation of a negative number. One's complement is more natural for floating point numbers because the zero is signed.

def float_and_(a,b):
    ma,ea = ifrexp(a)
    mb,eb = ifrexp(b)

    mb = mb>>(ea-eb)

    if ma<0:
        return ( mb&~(-ma) )*2**(ea-mant_dig)
    if mb<0:
        return ( ~(-mb)&ma )*2**(ea-mant_dig)
    return ( mb&ma )*2**(ea-mant_dig)

def float_or_(a,b):
    ma,ea = ifrexp(a)
    mb,eb = ifrexp(b)

    mb = mb>>(ea-eb)

    if ma<0:
        return ( -(~( mb|~(-ma) )) )*2**(ea-mant_dig)
    if mb<0:
        return ( -(~( ~(-mb)|ma )) )*2**(ea-mant_dig)
    return ( mb|ma )*2**(ea-mant_dig)

def float_xor_(a,b):
    ma,ea = ifrexp(a)
    mb,eb = ifrexp(b)

    mb = mb>>(ea-eb)

    return ( mb^ma )*2**(ea-mant_dig)