Beispiel #1
0
def speedDemo():
    """calculate indicative speed of floating-point operations"""

    print('=== speed test ===')
    for res, count in [ (16, 10000), (32, 10000),
                        (64, 10000), (128, 10000),
                        (256, 10000), (512, 10000) ]:
        fam = FXfamily(res)
        x = fam(0.5)
        lmb = fam(3.6)
        one = fam(1.0)
        t0 = time.perf_counter()
        for i in range(count):
            # use logistic-map in chaotic region:
            x = lmb * x * (one - x)
        t1 = time.perf_counter()
        ops = count * 3
        Dt = t1 - t0
        print('{0} {1}-bit arithmetic operations in {2:.2f}s ~ {3:.2g} FLOPS' \
                .format(ops, res, Dt, (ops / Dt)))

    for res, count in [ (4, 10000), (8, 10000), (12, 10000),
                        (24, 10000), (48, 10000), (128, 10000),
                        (512, 10000) ]:
        fam = FXfamily(res, 4)
        x = fam(2)
        t0 = time.perf_counter()
        for i in range(count):
            y = x.sqrt()
        t1 = time.perf_counter()
        Dt = (t1 - t0)
        print('{} {}-bit square-roots in {:.3g}s ~ {:.3g}/ms' \
                .format(count, res, Dt, count*1e-3/Dt))
Beispiel #2
0
    def testCrudeSqrt(self):
        """Check initialization of sqrt() initializing approximation"""
        fam24 = FXfamily(24)

        self.assertLess(abs(FXnum(2, fam24)._init_sqrt() - 1.5), 0.55)
        self.assertEqual(FXnum(4, fam24)._init_sqrt(), 2)
        self.assertEqual(FXnum(16, fam24)._init_sqrt(), 4)
        self.assertLess(abs(FXnum(120, fam24)._init_sqrt() - 12.0), 4.05)

        self.assertLess(abs(FXnum(0.5, fam24)._init_sqrt() - 0.7), 0.31)
        self.assertEqual(FXnum(0.0625, fam24)._init_sqrt(), 0.25)
        self.assertLess(abs(FXnum(0.002, fam24)._init_sqrt() - 0.046), 0.017)
        self.assertLess(abs(FXnum(0.0001, fam24)._init_sqrt() - 0.011), 0.005)

        fam23 = FXfamily(23)

        self.assertLess(abs(FXnum(2, fam23)._init_sqrt() - 1.5), 0.55)
        self.assertEqual(FXnum(4, fam23)._init_sqrt(), 2)
        self.assertEqual(FXnum(16, fam23)._init_sqrt(), 4)
        self.assertLess(abs(FXnum(120, fam23)._init_sqrt() - 12.0), 4.05)

        self.assertLess(abs(FXnum(0.5, fam23)._init_sqrt() - 0.7), 0.31)
        self.assertEqual(FXnum(0.0625, fam23)._init_sqrt(), 0.25)
        self.assertLess(abs(FXnum(0.002, fam23)._init_sqrt() - 0.046), 0.017)
        self.assertLess(abs(FXnum(0.0001, fam23)._init_sqrt() - 0.011), 0.005)
Beispiel #3
0
    def testNumCreateRounding(self):
        """Check rounding behaviour on FXnum creation"""
        fam = FXfamily(3)
        self.assertEqual(FXnum(0.375, fam).scaledval, 3)
        self.assertEqual(FXnum(0.437, fam).scaledval, 3)
        self.assertEqual(FXnum(0.438, fam).scaledval, 4)
        self.assertEqual(FXnum(0.46, fam).scaledval, 4)

        fam = FXfamily(4)
        self.assertEqual(FXnum(-0.75, fam).scaledval, -12)
        self.assertEqual(FXnum(-0.78124, fam).scaledval, -12)
        self.assertEqual(FXnum(-0.78126, fam).scaledval, -13)
        self.assertEqual(FXnum(-0.8125, fam).scaledval, -13)
Beispiel #4
0
    def testConstPrecision(self):
        """Check claimed precision of constants such as pi, log2, etc."""

        extra_bits = 64
        for res in (8, 16, 32, 64, 256, 1024):
            fam0 = FXfamily(res)
            fam_extra = FXfamily(res + extra_bits)

            for field in ('exp1', 'log2', 'pi', 'sqrt2'):
                x0 = getattr(fam0, field).scaledval
                x_extra = getattr(fam_extra, field).scaledval

                self.assertEqual(x0, x_extra >> extra_bits)
Beispiel #5
0
    def testFamEquality(self):
        """Check tests on equivalence of FXfamilies"""
        idxlist = [8, 16, 24, 33, 59]
        for idx in idxlist:
            fam0 = FXfamily(idx)
            for jdx in idxlist:
                fam1 = FXfamily(jdx)

                if idx == jdx:
                    self.assertTrue(fam0 == fam1)
                    self.assertFalse(fam0 != fam1)
                else:
                    self.assertFalse(fam0 == fam1)
                    self.assertTrue(fam0 != fam1)
Beispiel #6
0
    def testIntRange(self):
        """Check detection of overflow of integer part."""
        for top in [-3, -2, 0, 2, 4, 6]:
            fam = FXfamily(16, top)
            a = FXnum(1.0 / 16.01, fam)
            zero = FXnum(0, fam)
            limit = 1 << (top + 4 - 1)  # Unlikely to be valid FXnum(,fam)

            cnt, x, y = 0, zero, zero
            while cnt < (limit + 5):
                cnt += 1

                try:
                    x += a
                except FXoverflowError:
                    if cnt <= limit: self.fail()
                else:
                    if cnt > limit: self.fail()

                try:
                    y -= a
                except FXoverflowError:
                    if cnt <= limit: self.fail()
                else:
                    if cnt > limit: self.fail()
Beispiel #7
0
 def testOctalPi(self):
     # Value from http://turner.faculty.swau.edu/mathematics/materialslibrary/pi/pibases.html:
     piOctal = '3.1103755242102643021514230630505600670163211220111602105147630720020273724616611633104505120207461615'
     for res in range(3, 300, 9):
         printed = FXfamily(res + 2).pi.toBinaryString(3)[:-1]
         self.assertEqual(piOctal[:len(printed)], printed,
                          'Octal printing failed for res={}'.format(res))
Beispiel #8
0
    def testBinarySeries(self):
        """Check binary printing of enumerated signed integers."""
        for res in range(1, 5):
            fam = FXfamily(res)
            for scaled in range(1 << (res + 4)):
                pos = FXnum(family=fam, scaled_value=scaled)

                for sign in ((1, -1) if scaled > 0 else (1, )):
                    printed = (sign * pos).toBinaryString()

                    if sign > 0:
                        x = scaled
                    else:
                        if scaled < (1 << res):
                            shift = res + 1
                        else:
                            shift = math.ceil(math.log2(scaled)) + 1
                        x = (1 << shift) - scaled
                    binstr = bin(x)[2:]
                    pad = res + 1 - len(binstr)
                    if pad > 0: binstr = '0' * pad + binstr
                    binstr = binstr[:-res] + '.' + binstr[-res:]
                    self.assertEqual(binstr, printed,
                                     'Binary printing failed for {}, res={}' \
                                        .format(float(sign * pos), res))
Beispiel #9
0
 def testFamilyProtection(self):
     """Check that arithmetic operators do not transmute resolution families"""
     famlist = [FXfamily(res) for res in [8, 16, 40, 90]]
     for fam0 in famlist:
         for fam1 in famlist:
             x = FXnum(2, fam0)
             y = FXnum(3, fam1)
             try:
                 a = x + y
             except FXfamilyError:
                 self.assertFalse(fam0 is fam1)
             else:
                 self.assertTrue(fam0 is fam1)
             try:
                 a = x - y
             except FXfamilyError:
                 self.assertFalse(fam0 is fam1)
             else:
                 self.assertTrue(fam0 is fam1)
             try:
                 a = x * y
             except FXfamilyError:
                 self.assertFalse(fam0 is fam1)
             else:
                 self.assertTrue(fam0 is fam1)
             try:
                 a = x / y
             except FXfamilyError:
                 self.assertFalse(fam0 is fam1)
             else:
                 self.assertTrue(fam0 is fam1)
Beispiel #10
0
    def testTwosComplement(self):
        """Check conversion to twos-complement for binary/hex printing"""
        fam = FXfamily(3)
        self.assertEqual(fam(0.25)._toTwosComplement(), (0x02, 1, 3))
        self.assertEqual(fam(0.125)._toTwosComplement(1), (0x01, 1, 3))
        self.assertEqual(fam(0.125)._toTwosComplement(4), (0x02, 1, 1))

        fam = FXfamily(4)
        self.assertEqual(fam(15.0625)._toTwosComplement(4), (0xf1, 1, 1))
        self.assertEqual(fam(-7.25)._toTwosComplement(4), (0x8c, 1, 1))
        self.assertEqual(fam(-25.0)._toTwosComplement(4), (0x0e70, 2, 1))
        self.assertEqual(fam(-128.0)._toTwosComplement(4), (0x0800, 2, 1))

        fam = FXfamily(5, 3)
        self.assertEqual(fam(3.625)._toTwosComplement(), (0x74, 3, 5))
        self.assertEqual(fam(-3.5)._toTwosComplement(), (0x90, 3, 5))
Beispiel #11
0
    def testDivision(self):
        """Division operators should promote & inverse-commute"""
        fam62 = FXfamily(62)
        scale = 0.125
        scale2 = scale * scale
        for a in range(-32, 32):
            if a == 0: continue
            fpa = FXnum(a * scale, fam62)
            for y in range(-16, 16):
                if y == 0: continue
                fpy = FXnum(y * scale, fam62)
                fpx = FXnum((y * a) * scale2, fam62)

                # compute various forms of a = (x / y):

                self.assertAlmostEqual(fpa, fpx / fpy)
                self.assertAlmostEqual(1 / fpa, fpy / fpx)
                self.assertAlmostEqual((a * scale), float(fpx / fpy))

                tmp = fpx
                tmp /= fpy
                self.assertAlmostEqual(fpa, tmp)

                tmp = float(a * y * scale2) / fpy
                self.assertAlmostEqual(fpa, tmp)

                tmp = fpx / float(y * scale)
                self.assertAlmostEqual(fpa, tmp)
Beispiel #12
0
 def testHexPi(self):
     # Value from https://sourceforge.net/projects/hexpi/:
     piHex = '3.243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89452821e638d01377be5466cf34e90c6cc0ac29b7c97c50dd3f84d5b5b54709179216d5d98979fb1bd1310ba698dfb5ac2ffd72dbd01adfb7b8e1afed6a267e96ba7c9045f12c7f9924a19947b3916cf70801f2e2858efc16636920d871574e69a458fea3f4933d7e0d95748f728eb658718bcd588215'
     self.maxDiff = 900
     for res in range(32, 1200, 64):
         printed = FXfamily(res + 2).pi.toBinaryString(4)[:-1]
         self.assertEqual(piHex[:len(printed)], printed,
                          'Hex printing failed for res={}'.format(res))
Beispiel #13
0
 def testMathConsts(self):
     """Check various mathematical constants against math module."""
     for ident, target in [('unity', 1.0), ('exp1', math.e),
                           ('log2', math.log(2)), ('pi', math.pi),
                           ('sqrt2', math.sqrt(2))]:
         self.assertAlmostEqual(getattr(FXfamily(64), ident),
                                target,
                                places=15)
Beispiel #14
0
    def testMonoInt(self):
        """Check printing of numbers with single non-fractional bit"""
        fam = FXfamily(4, 1)

        self.assertEqual(fam(-0.75).toBinaryString(), '1.0100')
        self.assertEqual(fam(-0.25).toBinaryString(), '1.1100')
        self.assertEqual(fam(0.5).toBinaryString(), '0.1000')
        self.assertEqual(fam(0.825).toBinaryString(), '0.1101')
Beispiel #15
0
 def testRawBuild(self):
     """Check equivalence of FXnum._rawbuild() and FXnum()."""
     fam = FXfamily(10, 5)
     x = FXnum(val=9.7531, family=fam)
     xraw = FXnum._rawbuild(fam, x.scaledval)
     self.assertEqual(x, xraw)
     self.assertIsInstance(x, FXnum)
     self.assertIsInstance(xraw, FXnum)
     self.assertIsNot(x, xraw)
Beispiel #16
0
 def testExpLog(self):
     """exp and log methods should be inverses & agree with math.*"""
     fam62 = FXfamily(62)
     scale = 0.27
     for i in range(-32, 32):
         x = i * scale
         exp = FXnum(x, fam62).exp()
         logexp = exp.log()
         self.assertAlmostEqual(x, float(logexp))
Beispiel #17
0
 def testExp(self):
     """Exponent method should agree with math.exp"""
     fam62 = FXfamily(62)
     scale = 0.23
     for i in range(-32, 32):
         x = i * scale
         exp_true = math.exp(x)
         exp = FXnum(x, fam62).exp()
         self.assertAlmostEqual(exp_true, exp)
Beispiel #18
0
    def draw(cls):
        losses = []
        for bits in range(4, 500, 4):
            fam_acc = FXfamily(bits + 40)
            fam = FXfamily(bits)
            const_true = cls.calcConsts(fam_acc, famOnly=True)[0]

            losses.append([ bits ] +
                          [ cls.lostbits(apx, const_true)
                                for apx in cls.calcConsts(fam) ])
        losses = numpy.array(losses)

        plt.xlabel('resolution bits')
        plt.ylabel('error bits')
        plt.grid(True)
        for colno, label in enumerate(cls.getLabels(), 1):
            plt.plot(losses[:,0], losses[:,colno], label=label)
        plt.legend(loc='best', fontsize='small')
        plt.show()
Beispiel #19
0
    def testTwosCompCreate(self):
        """Check creation of FXnum from two's complement representation"""
        fam = FXfamily(2, 6)
        self.assertEqual(fam.from2c(0), fam.zero)
        self.assertEqual(fam.from2c(4), fam.unity)
        self.assertEqual(fam.from2c(127), fam(31.75))
        self.assertEqual(fam.from2c(128), fam(-32))
        self.assertEqual(fam.from2c(255), fam(-0.25))
        self.assertRaises(FXdomainError, fam.from2c, -1)
        self.assertRaises(FXdomainError, fam.from2c, 256)

        fam = FXfamily(3)
        self.assertEqual(fam.from2c(1023, 7), fam(-0.125))
        self.assertEqual(fam.from2c(511, 7), fam(63.875))
        self.assertRaises(FXfamilyError, fam.from2c, 0)
        self.assertRaises(FXfamilyError, fam.from2c, 0, None)
Beispiel #20
0
def piPlot():
    """Plot graph of approximations to Pi"""

    b_min, b_max = 8, 25
    pi_true = FXfamily(b_max + 40).pi
    pipoints = []
    for res in range(b_min, b_max+1):
        val = 4 * FXnum(1, FXfamily(res)).atan()
        pipoints.append([res, val])
    pipoints = numpy.array(pipoints)
    truepoints = numpy.array([[b_min, pi_true], [b_max, pi_true]])

    plt.xlabel('bits')
    plt.ylabel(r'$4 \tan^{-1} 1$')
    plt.xlim([b_min, b_max])
    plt.ylim([3.13, 3.16])
    plt.grid(True)
    for arr, style in ((truepoints, '--'), (pipoints, '-')):
        plt.plot(arr[:,0], arr[:,1], ls=style)
    plt.show()
Beispiel #21
0
    def testBitShifts(self):
        """Check effects of left & right shift operators."""
        fam = FXfamily(32)

        self.assertEqual(FXnum(1, fam) << 2, 4)
        self.assertEqual(FXnum(3, fam) << 4, 48)
        self.assertEqual(FXnum(-7, fam) << 8, -7 * 256)

        self.assertEqual(FXnum(1, fam) >> 1, 0.5)
        self.assertEqual(FXnum(12, fam) >> 2, 3)
        self.assertEqual(FXnum(-71 * 1024, fam) >> 12, -17.75)
Beispiel #22
0
    def testArctan(self):
        """atan method agree with math.sin/cos"""
        fam62 = FXfamily(62)
        scale = 0.277

        self.assertEqual(FXnum(0, fam62), 0)

        for i in range(-32, 32):
            tan = i * scale
            ang_true = math.atan(tan)
            ang = FXnum(tan, fam62).atan()
            self.assertAlmostEqual(ang_true, ang)
            self.assertAlmostEqual(float(ang.tan()), tan)
Beispiel #23
0
 def testLog(self):
     """Logarithm method agree with math.log"""
     fam62 = FXfamily(62)
     base = 1.5
     for i in range(1, 32):
         for j in range(0, 2):
             if j == 0:
                 x = 1.0 / (base**i)
             else:
                 x = base**i
             log_true = math.log(x)
             log = FXnum(x, fam62).log()
             self.assertAlmostEqual(log_true, log)
Beispiel #24
0
    def testPow(self):
        """Check raising FXnums to powers."""
        fam62 = FXfamily(62)
        scale = 0.205
        scale2 = 0.382
        for i in range(1, 32):
            x = i * scale

            for j in range(-16, 16):
                y = j * scale2
                pwr_true = math.pow(x, y)
                pwr = FXnum(x, fam62)**y
                self.assertAlmostEqual(pwr_true, pwr)
Beispiel #25
0
def basicDemo():
    """Basic demonstration of roots & exponents at various accuracies"""

    for resolution in [8, 32, 80, 274]:
        family = FXfamily(resolution)
        val = 2

        print('=== {0} bits ==='.format(resolution))
        rt = family(val).sqrt()
        print('sqrt(' + str(val) + ')~ ' + str(rt))
        print('sqrt(' + str(val) + ')^2 ~ ' + str(rt * rt))
        print('exp(1) ~ ' + str(family.exp1))
        print()
Beispiel #26
0
 def testNegating(self):
     """Check prefix operators"""
     fam17 = FXfamily(17)
     for i in range(-32, 32):
         x = i * 0.819
         fx = fam17(x)
         zero = fam17(0)
         try:
             self.assertEqual(zero, fx + (-fx))
             self.assertEqual(zero, -fx + fx)
             self.assertEqual((-1 * fx), -fx)
             self.assertEqual(zero, (-1 * fx) + (-fx) + 2 * (+fx))
         except FXexception:
             self.fail()
Beispiel #27
0
    def testNegatives(self):
        fam = FXfamily(3)

        x2 = FXnum(-0.25, fam)
        self.assertEqual(x2.toBinaryString(), '1.110')
        self.assertEqual(x2.toBinaryString(twosComp=False), '-0.010')

        x3 = FXnum(-0.625, fam)
        self.assertEqual(x3.toBinaryString(logBase=3), '7.3')
        self.assertEqual(x3.toBinaryString(3, twosComp=False), '-0.5')

        x4 = FXnum(-0.875, fam)
        self.assertEqual(x4.toBinaryString(4), 'f.2')
        self.assertEqual(x4.toBinaryString(4, twosComp=False), '-0.e')
Beispiel #28
0
def printBaseDemo():
    res = 60
    pi = FXfamily(res).pi

    print('==== Pi at {}-bit resolution ===='.format(res))
    print('decimal: {}'.format(pi.toDecimalString()))
    print('binary: {}'.format(pi.toBinaryString()))
    print('octal: {}'.format(pi.toBinaryString(3)))
    print('hex: {}'.format(pi.toBinaryString(4)))
Beispiel #29
0
    def testDecimalRound(self):
        third = FXnum(1, FXfamily(200)) / 3
        x23 = 2 * third

        self.assertEqual(third.toDecimalString(precision=5), '0.33333')
        self.assertEqual(third.toDecimalString(precision=8, round10=True),
                         '0.33333333')

        self.assertEqual(x23.toDecimalString(precision=4), '0.6666')
        self.assertEqual(x23.toDecimalString(precision=7, round10=True),
                         '0.6666667')

        self.assertEqual(x23.toDecimalString()[:42], '0.' + '6' * 40)
        self.assertEqual(x23.toDecimalString(precision=50), '0.' + '6' * 50)
        self.assertEqual(x23.toDecimalString(precision=50, round10=True),
                         '0.' + '6' * 49 + '7')
Beispiel #30
0
 def testSqrt(self):
     """sqrt method should find square-roots"""
     fam62 = FXfamily(62)
     scale = 0.94
     for i in range(-40, 40):
         x = i * scale
         fx = fam62(x)
         try:
             rt = fx.sqrt()
         except FXdomainError:
             self.assertFalse(x >= 0)
         else:
             rt2 = float(rt * rt)
             self.assertAlmostEqual(x, rt2)
             if i == 0:
                 self.assertEqual(FXnum(0, fam62), rt)