From: Bill Zorn Date: Thu, 27 Sep 2018 23:56:10 +0000 (-0700) Subject: beginning to add tests X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=44e367a4225200fe0dc796f0ace2b5748e6a90b5;p=sfpy.git beginning to add tests --- diff --git a/testing.py b/testing.py index eecca9a..e6306d8 100644 --- a/testing.py +++ b/testing.py @@ -1,127 +1,336 @@ +import multiprocessing +import time +import itertools +import re +import math +import random + +import numpy + import sfpy +import softfloat +import softposit -print('testing Poist8 neg / abs...') -for i in range(1 << 8): - x = sfpy.Posit8(i) - neg_x = -x - minus_x = x * sfpy.Posit8(-1.0) +posit_derepr = re.compile(r'Posit[0-9]+\((.*)\)') - if not neg_x.bits == minus_x.bits: - print('-', x, neg_x, minus_x) +def posit_get_classes(nbits): + if nbits == 8: + return sfpy.Posit8, softposit.posit8 + elif nbits == 16: + return sfpy.Posit16, softposit.posit16 + elif nbits == 32: + return sfpy.Posit32, softposit.posit32 + else: + raise ValueError('no representation of {}-bit posits'.format(repr(nbits))) + +def posit_get_fn(mod, nbits, fn): + return getattr(mod, 'p' + str(nbits) + '_' + fn) + +def posit_get_rounding_arguments(nbits, extra=False): + sfpy_cls, sp_cls = posit_get_classes(nbits) + mask = (1 << nbits) - 1 + inf = float('inf') + ninf = float('-inf') + + cases = set() + for i in range(1 - (1<<(nbits-1)), (1<<(nbits-1)) - 1): + f1 = float(sfpy_cls(i & mask)) + f2 = float(sfpy_cls((i+1) & mask)) + mean = (f1 + f2) / 2 + geomean = math.sqrt(f1 * f2) + + cases.add(f1) + cases.add(float(numpy.nextafter(f1, ninf))) + cases.add(float(numpy.nextafter(f1, inf))) + cases.add(mean) + cases.add(float(numpy.nextafter(mean, ninf))) + cases.add(float(numpy.nextafter(mean, inf))) + cases.add(geomean) + cases.add(float(numpy.nextafter(geomean, ninf))) + cases.add(float(numpy.nextafter(geomean, inf))) + + cases.add(f2) + cases.add(float(numpy.nextafter(f2, ninf))) + cases.add(float(numpy.nextafter(f2, inf))) + + if extra: + morecases = set() + for case in cases: + if case != 0: + morecases.add(1 / case) + morecases.add(-case) + + cases.update(morecases) + + return sorted(cases) + + +def posit_test_representation_bits(nbits, it): + sfpy_cls, sp_cls = posit_get_classes(nbits) + for i in it: + sfpy_1 = sfpy_cls(i) + sfpy_2 = sfpy_cls.from_bits(i) + sp_1 = sp_cls(0) + sp_1.fromBits(i) + + if not ( + sfpy_1.bits == sfpy_2.bits == sp_1.v.v + and float(sfpy_1) == float(sfpy_2) == float(sp_1) + # problem: nan + # and int(sfpy_1) == int(sfpy_2) == int(sp_1) + ): + print('representation mismatch on bits: {}'.format(repr(i))) + return True + + sfpy_3 = sfpy_cls(float(str(sfpy_1))) + sfpy_4 = sfpy_cls(float(str(sfpy_2))) + sfpy_5 = sfpy_cls(float(posit_derepr.match(repr(sfpy_1)).group(1))) + sfpy_6 = sfpy_cls(float(posit_derepr.match(repr(sfpy_2)).group(1))) + # problem: 'NaR' strings + # sp_2 = sp_cls(float(str(sp_1))) + # sp_3 = sp_cls(float(repr(sp_1))) + + if not ( + sfpy_1.bits == sfpy_3.bits == sfpy_4.bits == sfpy_5.bits == sfpy_6.bits # == sp_2.v.v == sp_3.v.v + ): + print('string representation mismatch on bits: {}'.format(repr(i))) + return True + + return False + +def posit_test_representation_floats(nbits, it): + sfpy_cls, sp_cls = posit_get_classes(nbits) + for f in it: + sfpy_1 = sfpy_cls(f) + sfpy_2 = sfpy_cls.from_double(f) + sp_1 = sp_cls(f) + + if not ( + sfpy_1.bits == sfpy_2.bits == sp_1.v.v + ): + print('bit representation mismatch on float: {}'.format(repr(i))) + return True + + return False + + +def posit_test_neg(nbits, it): + fname = 'neg' + sfpy_cls, sp_cls = posit_get_classes(nbits) + fn = posit_get_fn(sfpy.posit, nbits, fname) + for i in it: + sfpy_0 = sfpy_cls(i) + sfpy_1 = -sfpy_0 + sfpy_2 = sfpy_0.neg() + sfpy_3 = sfpy_cls(i) + sfpy_3.ineg() + sfpy_4 = fn(sfpy_0) + + sp_0 = sp_cls(0) + sp_0.fromBits(i) + sp_1 = -sp_0 + + if not ( + sp_1.v.v == sfpy_1.bits == sfpy_2.bits == sfpy_3.bits == sfpy_4.bits + ): + print('{} mismatch on bits: {}'.format(fname, repr(i))) + return True + + return False + + +def dispatch_test(pool, workers, n, test, nbits, *it): + print('running {}'.format(repr(test))) + if not it: + return False + + idx = 0 + work_slots = [] + + for i in range(workers): + new_idx = idx + n + it0 = it[0][idx:new_idx] + if it0: + print(' dispatch {:d}:{:d}'.format(idx, new_idx)) + work_slots.append(pool.apply_async(test, (nbits, it0, *(it[1:])))) + idx = new_idx + + # crude sleep-wait loop to redispatch + working = True + while working: + for i, result in enumerate(work_slots): + if result.ready(): + failed = result.get() + if failed: + return True + else: + new_idx = idx + n + it0 = it[0][idx:new_idx] + if it0: + print(' dispatch {:d}:{:d}'.format(idx, new_idx)) + work_slots[i] = pool.apply_async(test, (nbits, it0, *(it[1:]))) + else: + working = False + break + idx = new_idx + time.sleep(0.1) + + for result in work_slots: + result.wait() + failed = result.get() + if failed: + return True + + return False + + +if __name__ == '__main__': + import os + workers = os.cpu_count() - neg_x2 = sfpy.posit.p8_neg(x) + pool = multiprocessing.Pool(processes=workers, maxtasksperchild=1) - if not neg_x2.bits == minus_x.bits: - print('p8_neg', x, neg_x2, minus_x) + failed = ( + dispatch_test(pool, workers, 256, posit_test_representation_bits, 8, range(1 << 8)) + or dispatch_test(pool, workers, 10000, posit_test_representation_bits, 16, range(1 << 16)) + ) - x.ineg() + args = posit_get_rounding_arguments(8, True) + dispatch_test(pool, workers, 10000, posit_test_representation_floats, 8, args) + args = posit_get_rounding_arguments(16, True) + dispatch_test(pool, workers, 100000, posit_test_representation_floats, 16, args) - if not x.bits == minus_x.bits: - print('ineg', x, minus_x) + failed = failed or ( + dispatch_test(pool, workers, 256, posit_test_neg, 8, range(1 << 8)) + or dispatch_test(pool, workers, 10000, posit_test_neg, 16, range(1 << 16)) + ) + + + + print('Failed?', failed) + # print('testing Poist8 neg / abs...') + # for i in range(1 << 8): + # x = sfpy.Posit8(i) + # neg_x = -x + # minus_x = x * sfpy.Posit8(-1.0) - y = sfpy.Posit8(i) - abs_y = abs(y) - if y < sfpy.Posit8(0): - ifneg_y = y * sfpy.Posit8(-1.0) - else: - ifneg_y = y * sfpy.Posit8(1.0) + # if not neg_x.bits == minus_x.bits: + # print('-', x, neg_x, minus_x) - if not abs_y.bits == ifneg_y.bits: - print('abs', y, abs_y, ifneg_y) + # neg_x2 = sfpy.posit.p8_neg(x) - abs_y2 = sfpy.posit.p8_abs(y) + # if not neg_x2.bits == minus_x.bits: + # print('p8_neg', x, neg_x2, minus_x) - if not abs_y2.bits == ifneg_y.bits: - print('p8_abs', y, abs_y2, ifneg_y) + # x.ineg() - y.iabs() + # if not x.bits == minus_x.bits: + # print('ineg', x, minus_x) - if not y.bits == ifneg_y.bits: - print('iabs', y, ifneg_y) + # y = sfpy.Posit8(i) + # abs_y = abs(y) + # if y < sfpy.Posit8(0): + # ifneg_y = y * sfpy.Posit8(-1.0) + # else: + # ifneg_y = y * sfpy.Posit8(1.0) -print('testing Poist16 neg / abs...') -for i in range(1 << 16): - x = sfpy.Posit16(i) - neg_x = -x - minus_x = x * sfpy.Posit16(-1.0) + # if not abs_y.bits == ifneg_y.bits: + # print('abs', y, abs_y, ifneg_y) - if not neg_x.bits == minus_x.bits: - print('-', x, neg_x, minus_x) + # abs_y2 = sfpy.posit.p8_abs(y) - neg_x2 = sfpy.posit.p16_neg(x) + # if not abs_y2.bits == ifneg_y.bits: + # print('p8_abs', y, abs_y2, ifneg_y) - if not neg_x2.bits == minus_x.bits: - print('p16_neg', x, neg_x2, minus_x) + # y.iabs() - x.ineg() + # if not y.bits == ifneg_y.bits: + # print('iabs', y, ifneg_y) - if not x.bits == minus_x.bits: - print('ineg', x, minus_x) + # print('testing Poist16 neg / abs...') + # for i in range(1 << 16): + # x = sfpy.Posit16(i) + # neg_x = -x + # minus_x = x * sfpy.Posit16(-1.0) - y = sfpy.Posit16(i) - abs_y = abs(y) - if y < sfpy.Posit16(0): - ifneg_y = y * sfpy.Posit16(-1.0) - else: - ifneg_y = y * sfpy.Posit16(1.0) + # if not neg_x.bits == minus_x.bits: + # print('-', x, neg_x, minus_x) - if not abs_y.bits == ifneg_y.bits: - print('abs', y, abs_y, ifneg_y) + # neg_x2 = sfpy.posit.p16_neg(x) - abs_y2 = sfpy.posit.p16_abs(y) + # if not neg_x2.bits == minus_x.bits: + # print('p16_neg', x, neg_x2, minus_x) - if not abs_y2.bits == ifneg_y.bits: - print('p16_abs', y, abs_y2, ifneg_y) + # x.ineg() - y.iabs() + # if not x.bits == minus_x.bits: + # print('ineg', x, minus_x) - if not y.bits == ifneg_y.bits: - print('iabs', y, ifneg_y) + # y = sfpy.Posit16(i) + # abs_y = abs(y) + # if y < sfpy.Posit16(0): + # ifneg_y = y * sfpy.Posit16(-1.0) + # else: + # ifneg_y = y * sfpy.Posit16(1.0) -print('testing Poist32 neg / abs...') -for i in range(1 << 32): - x = sfpy.Posit32(i) - neg_x = -x - minus_x = x * sfpy.Posit32(-1.0) + # if not abs_y.bits == ifneg_y.bits: + # print('abs', y, abs_y, ifneg_y) - if not neg_x.bits == minus_x.bits: - print('-', x, neg_x, minus_x) + # abs_y2 = sfpy.posit.p16_abs(y) - neg_x2 = sfpy.posit.p32_neg(x) + # if not abs_y2.bits == ifneg_y.bits: + # print('p16_abs', y, abs_y2, ifneg_y) - if not neg_x2.bits == minus_x.bits: - print('p32_neg', x, neg_x2, minus_x) + # y.iabs() - x.ineg() + # if not y.bits == ifneg_y.bits: + # print('iabs', y, ifneg_y) - if not x.bits == minus_x.bits: - print('ineg', x, minus_x) + # print('testing Poist32 neg / abs...') + # for i in range(1 << 32): + # x = sfpy.Posit32(i) + # neg_x = -x + # minus_x = x * sfpy.Posit32(-1.0) - y = sfpy.Posit32(i) - abs_y = abs(y) - if y < sfpy.Posit32(0): - ifneg_y = y * sfpy.Posit32(-1.0) - else: - ifneg_y = y * sfpy.Posit32(1.0) + # if not neg_x.bits == minus_x.bits: + # print('-', x, neg_x, minus_x) + + # neg_x2 = sfpy.posit.p32_neg(x) + + # if not neg_x2.bits == minus_x.bits: + # print('p32_neg', x, neg_x2, minus_x) + + # x.ineg() + + # if not x.bits == minus_x.bits: + # print('ineg', x, minus_x) + + + # y = sfpy.Posit32(i) + # abs_y = abs(y) + # if y < sfpy.Posit32(0): + # ifneg_y = y * sfpy.Posit32(-1.0) + # else: + # ifneg_y = y * sfpy.Posit32(1.0) - if not abs_y.bits == ifneg_y.bits: - print('abs', y, abs_y, ifneg_y) + # if not abs_y.bits == ifneg_y.bits: + # print('abs', y, abs_y, ifneg_y) - abs_y2 = sfpy.posit.p32_abs(y) + # abs_y2 = sfpy.posit.p32_abs(y) - if not abs_y2.bits == ifneg_y.bits: - print('p32_abs', y, abs_y2, ifneg_y) + # if not abs_y2.bits == ifneg_y.bits: + # print('p32_abs', y, abs_y2, ifneg_y) - y.iabs() + # y.iabs() - if not y.bits == ifneg_y.bits: - print('iabs', y, ifneg_y) + # if not y.bits == ifneg_y.bits: + # print('iabs', y, ifneg_y) -print('...done.') + # print('...done.')