├── Makefile ├── dist └── .keep ├── docs ├── conf.py └── index.rst ├── requirements.txt ├── src └── sgposit │ ├── __init__.py │ ├── bitops.py │ ├── pcposit.py │ └── coder.py ├── MANIFEST.in ├── setup.cfg ├── .gitignore ├── tests ├── __init__.py ├── test_python_int.py ├── test_bitops.py ├── test_coder.py ├── test_coding_symmetry.py ├── test_pcposit_exhaustive.py └── test_pcposit.py ├── .travis.yml ├── appveyor.yml ├── setup.py ├── LICENSE ├── samples └── pcposit_sample.py └── README.rst /Makefile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sgposit/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.rst 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | sgposit.egg-info/ 4 | __pycache__/ 5 | *.pyc 6 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | def sgposit_testsuite(): 5 | loader = unittest.TestLoader() 6 | suite = loader.discover('.', pattern='test_*.py') 7 | return suite 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | matrix: 3 | include: 4 | - python: 2.7 5 | - python: 3.6 6 | 7 | branches: 8 | only: 9 | - master 10 | - devtest 11 | 12 | install: 13 | - pip install -r requirements.txt 14 | - python setup.py install 15 | 16 | script: python setup.py test 17 | -------------------------------------------------------------------------------- /tests/test_python_int.py: -------------------------------------------------------------------------------- 1 | # Basic arithmetic __add__, __sub__, __mul__, __floordiv__ 2 | # Dynamic large number. 3 | # Access to binary bits: bits for positive numbers and bits for 2's complement negative numbers. 4 | # Signed extended shift operations: <<, >> 5 | # Bit-wise operations: &, |, ^, ~ 6 | 7 | # Operations and behaviors that are not supported shall be complemented with other functions. 8 | 9 | # Pass by value. 10 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - PYTHON: "C:\\Python27-x64" 4 | - PYTHON: "C:\\Python36-x64" 5 | 6 | branches: 7 | only: 8 | - master 9 | - devtest 10 | 11 | before_build: 12 | after_build: 13 | build_script: 14 | 15 | build: off 16 | 17 | install: 18 | - "python -m pip install -r requirements.txt" 19 | - "python setup.py install" 20 | 21 | test_script: 22 | - "python setup.py test" 23 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | 4 | setup( 5 | name='sgposit', 6 | version='0.0.1.dev6', 7 | description='Posit arithmetic library for python', 8 | keywords='posit arithmetic', 9 | author='SpeedGo Computing', 10 | author_email='shinyee@speedgocomputing.com', 11 | url='https://github.com/xman/sgpositpy', 12 | license='MIT', 13 | install_requires=[], 14 | extras_require={ 15 | 'dev' : [], 16 | 'test': ['nose'], 17 | }, 18 | tests_require=['mpmath'], 19 | test_suite="tests", 20 | packages=find_packages('src'), 21 | package_dir={'': 'src'}, 22 | ) 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 SpeedGo Computing 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /samples/pcposit_sample.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2018 SpeedGo Computing 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | # Run: PYTHONPATH=../src python pcposit_sample.py 25 | 26 | 27 | from sgposit.pcposit import PCPosit 28 | 29 | 30 | a = PCPosit(0x0C, mode='bits', nbits=6, es=2) 31 | b = PCPosit(0x0F, mode='bits', nbits=6, es=2) 32 | 33 | c = a + b 34 | print("{} + {} => {}".format(a, b, c)) 35 | 36 | d = a - b 37 | print("{} - {} => {}".format(a, b, d)) 38 | 39 | e = a * b 40 | print("{} * {} => {}".format(a, b, e)) 41 | 42 | f = a / b 43 | print("{} / {} => {}".format(a, b, f)) 44 | 45 | g = -a 46 | print("uminus {} => {}".format(a, g)) 47 | -------------------------------------------------------------------------------- /tests/test_bitops.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2018 SpeedGo Computing 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | import unittest 25 | 26 | from sgposit.bitops import * 27 | 28 | 29 | class TestBitops(unittest.TestCase): 30 | 31 | def setUp(self): 32 | pass 33 | 34 | 35 | def tearDown(self): 36 | pass 37 | 38 | 39 | def test_create_mask(self): 40 | mask = create_mask(10) 41 | self.assertEqual(mask, 0x03FF) 42 | 43 | mask = create_mask(17) 44 | self.assertEqual(mask, 0x1FFFF) 45 | 46 | 47 | def test_get_int_bits(self): 48 | bits = get_int_bits(0x00FF, 3, 7) 49 | self.assertEqual(bits, 0x01F) 50 | 51 | bits = get_int_bits(0xFF0F, 4, 11) 52 | self.assertEqual(bits, 0x0F0) 53 | 54 | 55 | def test_count_leading_bits(self): 56 | bits = 0b0111110000 57 | self.assertEqual(count_leading_bits(bits, 1, 8), 5) 58 | 59 | bits = 0b0110001111 60 | self.assertEqual(count_leading_bits(bits, 0, 5), 2) 61 | 62 | bits = 0b0110001111 63 | self.assertEqual(count_leading_bits(bits, 1, 5), 0) 64 | 65 | 66 | if __name__ == '__main__': 67 | unittest.main() 68 | -------------------------------------------------------------------------------- /src/sgposit/bitops.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2018 SpeedGo Computing 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | """ 25 | Create a mask with n ones. 26 | """ 27 | def create_mask(n): 28 | if n <= 0: 29 | return 0 30 | return (1 << n) - 1 31 | 32 | 33 | """ 34 | Get bits in integer v from bit ifirst to bit ilast, inclusive. 35 | Integer v = b_n-1, ..., b_1, b_0 36 | The bit position is 0-based and starts from the least significant bit. 37 | """ 38 | def get_int_bits(v, ifirst, ilast=None): 39 | if ilast is None: ilast = ifirst 40 | 41 | assert ifirst >= 0 and ifirst <= ilast 42 | 43 | mask = create_mask(ilast-ifirst+1) 44 | v >>= ifirst 45 | v &= mask 46 | 47 | return v 48 | 49 | 50 | """ 51 | Count the number of leading bits with value b, from bit ilast down to bit 0. 52 | Integer v = b_n-1, ..., b_1, b_0 53 | The bit position is 0-based and starts from the least significant bit. 54 | """ 55 | def count_leading_bits(bits, b, ilast): 56 | assert ilast >= 0 57 | 58 | count = 0 59 | for i in range(ilast, -1, -1): 60 | if get_int_bits(bits, i) == b: 61 | count += 1 62 | else: 63 | break 64 | 65 | return count 66 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | sgpositpy 2 | ========= 3 | .. image:: https://badges.gitter.im/sgpositpy/Lobby.svg 4 | :alt: Join the chat at https://gitter.im/sgpositpy/Lobby 5 | :target: https://gitter.im/sgpositpy/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge 6 | 7 | .. image:: https://travis-ci.org/xman/sgpositpy.svg?branch=master 8 | :alt: sgpositpy regression test status on Travis CI 9 | :target: https://travis-ci.org/xman/sgpositpy 10 | 11 | .. image:: https://ci.appveyor.com/api/projects/status/3t1q732w1cf4somj/branch/master?svg=true 12 | :alt: sgpositpy regression test status on Appveyor 13 | :target: https://ci.appveyor.com/project/xman/sgpositpy 14 | 15 | .. image:: https://img.shields.io/badge/License-MIT-yellow.svg 16 | :alt: sgpositpy under MIT license 17 | :target: https://github.com/xman/sgpositpy/blob/master/LICENSE 18 | 19 | Posit is a new binary format for representing decimal numbers, an alternative to 20 | IEEE 754 floating-point number. Different configurations on the number bit size 21 | and the scaling are possible. Details can be found at the posithub_ and the 22 | `notebook on posit`_. 23 | 24 | We are interested to experiment with different posit configurations the `nbits` 25 | and the `es` sizes, and attempt to use smaller bit sizes in our applications 26 | while achieving the required accuracy to operate. However, an implementation 27 | conforming to the posit design is still lacking for popular programming 28 | languages. 29 | 30 | This project, *sgpositpy*, is our attempt to develop a prototype implementation 31 | that is correct by the posit design. This can then serve as a reference for 32 | subsequent development of performance optimized posit library. Hence, the 33 | computation efficiency is currently not the focus of the project. 34 | 35 | .. _posithub: https://posithub.org 36 | .. _notebook on posit: https://posithub.org/docs/Posits4.pdf 37 | 38 | 39 | Current status 40 | ============== 41 | The current implementation is research oriented and experimental at pre-alpha stage. 42 | This is **NOT** currently suitable for production use. 43 | 44 | 45 | Install 46 | ======= 47 | Install from PyPI 48 | 49 | .. code:: bash 50 | 51 | $ pip install sgposit 52 | 53 | 54 | Install from code repository 55 | 56 | .. code:: bash 57 | 58 | $ git clone https://github.com/xman/sgpositpy 59 | $ cd sgpositpy 60 | $ pip install -r requirements.txt 61 | $ python setup.py install 62 | 63 | # Run regression tests. 64 | $ python setup.py test 65 | 66 | # Enable long running tests. 67 | $ SGPOSIT_LONG_TESTS=1 python setup.py test 68 | 69 | 70 | Getting started 71 | =============== 72 | The `PCPosit` class is our reference implementation with extensive regression 73 | tests. We shall have performance optimized version in `Posit` class for general 74 | use in the future. 75 | 76 | The following code snippet creates posit objects from the given bit patterns, 77 | and the posit configuration, `nbits` and `es`. 78 | 79 | .. code:: python 80 | 81 | # file: samples/pcposit_sample.py 82 | 83 | from sgposit.pcposit import PCPosit 84 | 85 | a = PCPosit(0x0C, mode='bits', nbits=6, es=2) 86 | b = PCPosit(0x0F, mode='bits', nbits=6, es=2) 87 | 88 | c = a + b 89 | print("{} + {} => {}".format(a, b, c)) 90 | 91 | d = a - b 92 | print("{} - {} => {}".format(a, b, d)) 93 | 94 | e = a * b 95 | print("{} * {} => {}".format(a, b, e)) 96 | 97 | f = a / b 98 | print("{} + {} => {}".format(a, b, f)) 99 | 100 | g = -a 101 | print("uminus {} => {}".format(a, g)) 102 | 103 | 104 | .. code:: bash 105 | 106 | $ python samples/pcposit_sample.py 107 | 1/4 + 3/4 => 1 108 | 1/4 - 3/4 => -1/2 109 | 1/4 * 3/4 => 3/16 110 | 1/4 / 3/4 => 3/8 111 | uminus 1/4 => -1/4 112 | 113 | 114 | License 115 | ======= 116 | *sgpositpy* is licensed under MIT License. 117 | -------------------------------------------------------------------------------- /tests/test_coder.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2018 SpeedGo Computing 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | import unittest 25 | 26 | from sgposit.coder import * 27 | 28 | 29 | class TestCoder(unittest.TestCase): 30 | 31 | def setUp(self): 32 | self.posit_n6e0_some_bits = 0x0022 33 | self.posit_n6e2_m128_bits = 0x0025 # bits=0x0025, nbits=6, es=2, value=-128 34 | self.posit_n6e2_3o32_bits = 0x0009 # bits=0x0009, nbits=6, es=2, value=3/32 35 | self.posit_n6e2_6_bits = 0x0015 # bits=0x0015, nbits=6, es=2, value=6 36 | 37 | self.posit_n8e1_zero_bits = 0 38 | 39 | self.posit_n10e3_cinf_bits = 0x0200 40 | 41 | self.posit_n16e2_some_bits = 0x00AC 42 | self.posit_n16e3_cinf_bits = 0x8000 43 | 44 | self.posit_n19e1_some_bits = 0x60000 45 | 46 | self.posit_n23e1_cinf_bits = 0x400000 47 | 48 | 49 | def tearDown(self): 50 | pass 51 | 52 | 53 | def test_decode_posit_binary_special(self): 54 | # zero 55 | rep = decode_posit_binary(0, 8, 1) 56 | self.assertEqual(rep['t'], 'z') 57 | 58 | rep = decode_posit_binary(self.posit_n16e2_some_bits, 16, 2) 59 | self.assertNotEqual(rep['t'], 'z') 60 | 61 | # cinf 62 | rep = decode_posit_binary(self.posit_n16e3_cinf_bits, 16, 3) 63 | self.assertEqual(rep['t'], 'c') 64 | 65 | rep = decode_posit_binary(self.posit_n23e1_cinf_bits, 23, 1) 66 | self.assertEqual(rep['t'], 'c') 67 | 68 | rep = decode_posit_binary(self.posit_n19e1_some_bits, 19, 1) 69 | self.assertNotEqual(rep['t'], 'c') 70 | 71 | rep = decode_posit_binary(self.posit_n6e0_some_bits, 6, 0) 72 | self.assertNotEqual(rep['t'], 'c') 73 | 74 | 75 | def test_decode_posit_binary_normal(self): 76 | rep = decode_posit_binary(self.posit_n6e2_m128_bits, 6, 2) 77 | self.assertEqual(rep, { 's': 1, 'k': 1, 'e': 3, 'f': 0, 'h': 0, 'nbits': 6, 'es': 2, 't': 'n' }) 78 | 79 | rep = decode_posit_binary(self.posit_n6e2_3o32_bits, 6, 2) 80 | self.assertEqual(rep, { 's': 0, 'k': -1, 'e': 0, 'f': 1, 'h': 1, 'nbits': 6, 'es': 2, 't': 'n' }) 81 | 82 | rep = decode_posit_binary(self.posit_n6e2_6_bits, 6, 2) 83 | self.assertEqual(rep, { 's': 0, 'k': 0, 'e': 2, 'f': 1, 'h': 1, 'nbits': 6, 'es': 2, 't': 'n' }) 84 | 85 | 86 | def test_encode_posit_binary_special(self): 87 | # zero 88 | rep = { 's': 1, 'k': 1, 'e': 3, 'f': 0, 'h': 0, 'nbits': 6, 'es': 2, 't': 'z' } 89 | bits = encode_posit_binary(rep) 90 | self.assertEqual(bits, 0) 91 | 92 | rep = { 's': 0, 'k': -1, 'e': 0, 'f': 1, 'h': 1, 'nbits': 6, 'es': 2, 't': 'n' } 93 | bits = encode_posit_binary(rep) 94 | self.assertNotEqual(bits, 0) 95 | 96 | # cinf 97 | rep = { 's': 0, 'k': 0, 'e': 0, 'f': 0, 'h': 0, 'nbits': 10, 'es': 3, 't': 'c' } 98 | bits = encode_posit_binary(rep) 99 | self.assertEqual(bits, self.posit_n10e3_cinf_bits) 100 | 101 | rep = { 's': 1, 'k': 1, 'e': 0, 'f': 0, 'h': 0, 'nbits': 10, 'es': 3, 't': 'n' } 102 | bits = encode_posit_binary(rep) 103 | self.assertNotEqual(bits, self.posit_n10e3_cinf_bits) 104 | 105 | 106 | def test_encode_posit_binary_normal(self): 107 | rep = { 's': 1, 'k': 1, 'e': 3, 'f': 0, 'h': 0, 'nbits': 6, 'es': 2, 't': 'n' } 108 | bits = encode_posit_binary(rep) 109 | self.assertEqual(bits, self.posit_n6e2_m128_bits) 110 | 111 | rep = { 's': 0, 'k': -1, 'e': 0, 'f': 1, 'h': 1, 'nbits': 6, 'es': 2, 't': 'n' } 112 | bits = encode_posit_binary(rep) 113 | self.assertEqual(bits, self.posit_n6e2_3o32_bits) 114 | 115 | rep = { 's': 0, 'k': 0, 'e': 2, 'f': 1, 'h': 1, 'nbits': 6, 'es': 2, 't': 'n' } 116 | bits = encode_posit_binary(rep) 117 | self.assertEqual(bits, self.posit_n6e2_6_bits) 118 | 119 | 120 | def test_positrep_to_str(self): 121 | rep = { 's': 1, 'k': 1, 'e': 3, 'f': 0, 'h': 0, 'nbits': 6, 'es': 2, 't': 'n' } 122 | repstr = positrep_to_str(rep) 123 | self.assertEqual(repstr, '-128') 124 | 125 | rep = { 's': 0, 'k': -1, 'e': 0, 'f': 1, 'h': 1, 'nbits': 6, 'es': 2, 't': 'n' } 126 | repstr = positrep_to_str(rep) 127 | self.assertEqual(repstr, '3/32') 128 | 129 | rep = { 's': 0, 'k': 0, 'e': 2, 'f': 1, 'h': 1, 'nbits': 6, 'es': 2, 't': 'n' } 130 | repstr = positrep_to_str(rep) 131 | self.assertEqual(repstr, '6') 132 | 133 | rep = { 's': 0, 'k': 0, 'e': 0, 'f': 1, 'h': 1, 'nbits': 6, 'es': 2, 't': 'n' } 134 | repstr = positrep_to_str(rep) 135 | self.assertEqual(repstr, '1+1/2') 136 | 137 | rep = { 's': 0, 'k': 0, 'e': 0, 'f': 0, 'h': 0, 'nbits': 10, 'es': 3, 't': 'c' } 138 | repstr = positrep_to_str(rep) 139 | self.assertEqual(repstr, 'cinf') 140 | 141 | rep = { 's': 1, 'k': 1, 'e': 3, 'f': 0, 'h': 0, 'nbits': 6, 'es': 2, 't': 'z' } 142 | repstr = positrep_to_str(rep) 143 | self.assertEqual(repstr, '0') 144 | 145 | 146 | def test_create_zero_positrep(self): 147 | nbits = 6 148 | es = 2 149 | rep = create_zero_positrep(nbits, es) 150 | self.assertEqual(rep['t'], 'z') 151 | 152 | bits = encode_posit_binary(rep) 153 | self.assertEqual(bits, 0) 154 | 155 | 156 | def test_create_cinf_positrep(self): 157 | nbits = 6 158 | es = 2 159 | rep = create_cinf_positrep(nbits, es) 160 | self.assertEqual(rep['t'], 'c') 161 | 162 | bits = encode_posit_binary(rep) 163 | self.assertEqual(bits, 1 << (nbits-1)) 164 | 165 | 166 | def test_copy_positrep(self): 167 | nbits = 6 168 | es = 2 169 | rep1 = create_positrep() 170 | rep2 = copy_positrep(rep1) 171 | self.assertEqual(rep1, rep2) 172 | self.assertIsNot(rep1, rep2) 173 | 174 | 175 | if __name__ == '__main__': 176 | unittest.main() 177 | -------------------------------------------------------------------------------- /tests/test_coding_symmetry.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2018 SpeedGo Computing 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | import os 25 | import unittest 26 | 27 | from sgposit.coder import * 28 | 29 | 30 | class TestCodingSymmetry(unittest.TestCase): 31 | 32 | _multiprocess_can_split_ = True 33 | 34 | 35 | def run_encoding_decoding_symmetry(self, nbits=None, es=None): 36 | for bits in range(2**nbits): 37 | rep = decode_posit_binary(bits, nbits, es) 38 | encoded_bits = encode_posit_binary(rep) 39 | self.assertEqual(encoded_bits, bits) 40 | 41 | 42 | def test_encoding_decoding_symmetry_n2e0(self): 43 | self.run_encoding_decoding_symmetry(nbits=2, es=0) 44 | def test_encoding_decoding_symmetry_n2e1(self): 45 | self.run_encoding_decoding_symmetry(nbits=2, es=1) 46 | def test_encoding_decoding_symmetry_n2e2(self): 47 | self.run_encoding_decoding_symmetry(nbits=2, es=2) 48 | def test_encoding_decoding_symmetry_n2e3(self): 49 | self.run_encoding_decoding_symmetry(nbits=2, es=3) 50 | 51 | def test_encoding_decoding_symmetry_n3e0(self): 52 | self.run_encoding_decoding_symmetry(nbits=3, es=0) 53 | def test_encoding_decoding_symmetry_n3e1(self): 54 | self.run_encoding_decoding_symmetry(nbits=3, es=1) 55 | def test_encoding_decoding_symmetry_n3e2(self): 56 | self.run_encoding_decoding_symmetry(nbits=3, es=2) 57 | def test_encoding_decoding_symmetry_n3e3(self): 58 | self.run_encoding_decoding_symmetry(nbits=3, es=3) 59 | def test_encoding_decoding_symmetry_n3e4(self): 60 | self.run_encoding_decoding_symmetry(nbits=3, es=4) 61 | 62 | def test_encoding_decoding_symmetry_n4e0(self): 63 | self.run_encoding_decoding_symmetry(nbits=4, es=0) 64 | def test_encoding_decoding_symmetry_n4e1(self): 65 | self.run_encoding_decoding_symmetry(nbits=4, es=1) 66 | def test_encoding_decoding_symmetry_n4e2(self): 67 | self.run_encoding_decoding_symmetry(nbits=4, es=2) 68 | def test_encoding_decoding_symmetry_n4e3(self): 69 | self.run_encoding_decoding_symmetry(nbits=4, es=3) 70 | def test_encoding_decoding_symmetry_n4e4(self): 71 | self.run_encoding_decoding_symmetry(nbits=4, es=4) 72 | def test_encoding_decoding_symmetry_n4e5(self): 73 | self.run_encoding_decoding_symmetry(nbits=4, es=5) 74 | 75 | def test_encoding_decoding_symmetry_n5e0(self): 76 | self.run_encoding_decoding_symmetry(nbits=5, es=0) 77 | def test_encoding_decoding_symmetry_n5e1(self): 78 | self.run_encoding_decoding_symmetry(nbits=5, es=1) 79 | def test_encoding_decoding_symmetry_n5e2(self): 80 | self.run_encoding_decoding_symmetry(nbits=5, es=2) 81 | def test_encoding_decoding_symmetry_n5e3(self): 82 | self.run_encoding_decoding_symmetry(nbits=5, es=3) 83 | def test_encoding_decoding_symmetry_n5e4(self): 84 | self.run_encoding_decoding_symmetry(nbits=5, es=4) 85 | def test_encoding_decoding_symmetry_n5e5(self): 86 | self.run_encoding_decoding_symmetry(nbits=5, es=5) 87 | def test_encoding_decoding_symmetry_n5e6(self): 88 | self.run_encoding_decoding_symmetry(nbits=5, es=6) 89 | 90 | def test_encoding_decoding_symmetry_n6e0(self): 91 | self.run_encoding_decoding_symmetry(nbits=6, es=0) 92 | def test_encoding_decoding_symmetry_n6e1(self): 93 | self.run_encoding_decoding_symmetry(nbits=6, es=1) 94 | def test_encoding_decoding_symmetry_n6e2(self): 95 | self.run_encoding_decoding_symmetry(nbits=6, es=2) 96 | def test_encoding_decoding_symmetry_n6e3(self): 97 | self.run_encoding_decoding_symmetry(nbits=6, es=3) 98 | def test_encoding_decoding_symmetry_n6e4(self): 99 | self.run_encoding_decoding_symmetry(nbits=6, es=4) 100 | def test_encoding_decoding_symmetry_n6e5(self): 101 | self.run_encoding_decoding_symmetry(nbits=6, es=5) 102 | def test_encoding_decoding_symmetry_n6e6(self): 103 | self.run_encoding_decoding_symmetry(nbits=6, es=6) 104 | def test_encoding_decoding_symmetry_n6e7(self): 105 | self.run_encoding_decoding_symmetry(nbits=6, es=7) 106 | 107 | def test_encoding_decoding_symmetry_n16e0(self): 108 | self.run_encoding_decoding_symmetry(nbits=16, es=0) 109 | def test_encoding_decoding_symmetry_n16e1(self): 110 | self.run_encoding_decoding_symmetry(nbits=16, es=1) 111 | def test_encoding_decoding_symmetry_n16e2(self): 112 | self.run_encoding_decoding_symmetry(nbits=16, es=2) 113 | def test_encoding_decoding_symmetry_n16e3(self): 114 | self.run_encoding_decoding_symmetry(nbits=16, es=3) 115 | def test_encoding_decoding_symmetry_n16e4(self): 116 | self.run_encoding_decoding_symmetry(nbits=16, es=4) 117 | def test_encoding_decoding_symmetry_n16e5(self): 118 | self.run_encoding_decoding_symmetry(nbits=16, es=5) 119 | def test_encoding_decoding_symmetry_n16e6(self): 120 | self.run_encoding_decoding_symmetry(nbits=16, es=6) 121 | def test_encoding_decoding_symmetry_n16e7(self): 122 | self.run_encoding_decoding_symmetry(nbits=16, es=7) 123 | def test_encoding_decoding_symmetry_n16e8(self): 124 | self.run_encoding_decoding_symmetry(nbits=16, es=8) 125 | def test_encoding_decoding_symmetry_n16e9(self): 126 | self.run_encoding_decoding_symmetry(nbits=16, es=9) 127 | def test_encoding_decoding_symmetry_n16e10(self): 128 | self.run_encoding_decoding_symmetry(nbits=16, es=10) 129 | def test_encoding_decoding_symmetry_n16e11(self): 130 | self.run_encoding_decoding_symmetry(nbits=16, es=11) 131 | def test_encoding_decoding_symmetry_n16e12(self): 132 | self.run_encoding_decoding_symmetry(nbits=16, es=12) 133 | def test_encoding_decoding_symmetry_n16e13(self): 134 | self.run_encoding_decoding_symmetry(nbits=16, es=13) 135 | def test_encoding_decoding_symmetry_n16e14(self): 136 | self.run_encoding_decoding_symmetry(nbits=16, es=14) 137 | def test_encoding_decoding_symmetry_n16e15(self): 138 | self.run_encoding_decoding_symmetry(nbits=16, es=15) 139 | def test_encoding_decoding_symmetry_n16e16(self): 140 | self.run_encoding_decoding_symmetry(nbits=16, es=16) 141 | def test_encoding_decoding_symmetry_n16e17(self): 142 | self.run_encoding_decoding_symmetry(nbits=16, es=17) 143 | 144 | 145 | if __name__ == '__main__': 146 | unittest.main() 147 | -------------------------------------------------------------------------------- /src/sgposit/pcposit.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2018 SpeedGo Computing 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | import numbers 25 | import operator 26 | 27 | from sgposit import coder 28 | 29 | 30 | """ 31 | Provably correct posit number arithmetic. 32 | """ 33 | class PCPosit: 34 | 35 | def __init__(self, v=None, mode=None, nbits=None, es=None): 36 | nbits_given = True 37 | es_given = True 38 | if nbits is None: 39 | nbits_given = False 40 | nbits = 32 41 | if es is None: 42 | es_given = False 43 | es = 2 44 | 45 | if v is None: 46 | self.rep = coder.create_zero_positrep(nbits=nbits, es=es) 47 | return 48 | elif isinstance(v, PCPosit): 49 | if nbits_given and v.rep['nbits'] != nbits: 50 | raise NotImplementedError('Mismatched nbits posit conversion is not implemented.') 51 | if es_given and v.rep['es'] != es: 52 | raise NotImplementedError('Mismatched es posit conversion is not implemented.') 53 | self.rep = coder.copy_positrep(v.rep) 54 | return 55 | elif mode == 'bits': 56 | if isinstance(v, numbers.Integral): 57 | self.rep = coder.decode_posit_binary(v, nbits=nbits, es=es) 58 | return 59 | elif isinstance(v, str): 60 | raise NotImplementedError('Binary bit string posit conversion is not implemented.') 61 | elif isinstance(v, str): 62 | if v == 'cinf': 63 | self.rep = coder.create_cinf_positrep(nbits=nbits, es=es) 64 | elif v == '0': 65 | self.rep = coder.create_zero_positrep(nbits=nbits, es=es) 66 | else: 67 | raise ValueError('Expect 0 or cinf posit consntant from the input string.') 68 | 69 | return 70 | 71 | raise ValueError('Input is not supported.') 72 | 73 | 74 | def __add__(self, other): 75 | if self.rep['t'] == 'z': 76 | return PCPosit(other) 77 | elif other.rep['t'] == 'z': 78 | return PCPosit(self) 79 | elif self.rep['t'] == 'c' or other.rep['t'] == 'c': 80 | return PCPosit('cinf', nbits=self.rep['nbits'], es=self.rep['es']) 81 | 82 | assert self.rep['t'] == 'n' and other.rep['t'] == 'n' 83 | 84 | (xa,ma) = self._fixedpoint() 85 | (xb,mb) = other._fixedpoint() 86 | 87 | m = max(ma, mb) 88 | xc = xa*2**(m-mb) + xb*2**(m-ma) 89 | mc = ma + mb - m 90 | 91 | return self._fixedpoint_to_posit(xc, mc, nbits=self.rep['nbits'], es=self.rep['es']) 92 | 93 | 94 | def __sub__(self, other): 95 | p = -PCPosit(other) 96 | return self + p 97 | 98 | 99 | def __neg__(self): 100 | p = PCPosit(self) 101 | if p.rep['t'] == 'n': 102 | p.rep['s'] = p.rep['s'] ^ 1 103 | return p 104 | 105 | 106 | def __mul__(self, other): 107 | if self.rep['t'] == 'c' or other.rep['t'] == 'c': 108 | return PCPosit('cinf', nbits=self.rep['nbits'], es=self.rep['es']) 109 | elif self.rep['t'] == 'z' or other.rep['t'] == 'z': 110 | return PCPosit('0', nbits=self.rep['nbits'], es=self.rep['es']) 111 | 112 | assert self.rep['t'] == 'n' and other.rep['t'] == 'n' 113 | 114 | (xa,ma) = self._fixedpoint() 115 | (xb,mb) = other._fixedpoint() 116 | 117 | xc = xa * xb 118 | mc = ma + mb 119 | 120 | return self._fixedpoint_to_posit(xc, mc, nbits=self.rep['nbits'], es=self.rep['es']) 121 | 122 | 123 | def __div__(self, other): 124 | return self.__truediv__(other) 125 | 126 | 127 | def __truediv__(self, other): 128 | if self.rep['t'] == 'c' or other.rep['t'] == 'z': 129 | return PCPosit('cinf', nbits=self.rep['nbits'], es=self.rep['es']) 130 | elif self.rep['t'] == 'z' or other.rep['t'] == 'c': 131 | return PCPosit('0', nbits=self.rep['nbits'], es=self.rep['es']) 132 | 133 | assert self.rep['t'] == 'n' and other.rep['t'] == 'n' 134 | 135 | (xa,ma) = self._fixedpoint() 136 | (xb,mb) = other._fixedpoint() 137 | 138 | nbits = self.rep['nbits'] 139 | es = self.rep['es'] 140 | sign = 1 141 | if (xa < 0)^(xb < 0): sign = -1 142 | if xa < 0: xa = -xa 143 | if xb < 0: xb = -xb 144 | 145 | g = ma - mb + (2**es)*(nbits-2) + nbits - 1 146 | g = max(0, g) 147 | xc = (xa * 2**g) // xb 148 | mc = ma - mb - g 149 | 150 | xc = max(xc, 1) # Posit never round to 0. 151 | xc *= sign 152 | 153 | return self._fixedpoint_to_posit(xc, mc, nbits=nbits, es=es) 154 | 155 | 156 | def __floordiv__(self, other): 157 | raise NotImplementedError 158 | 159 | 160 | def __eq__(self, other): 161 | a = self.rep 162 | b = other.rep 163 | 164 | if a['t'] == 'c' or b['t'] == 'c': 165 | return False 166 | 167 | elif a['t'] == 'z' or b['t'] == 'z': 168 | if a['t'] == b['t']: 169 | return True 170 | else: 171 | return False 172 | 173 | else: 174 | assert a['t'] == 'n' 175 | assert b['t'] == 'n' 176 | 177 | return a == b 178 | 179 | 180 | def __ne__(self, other): 181 | return not(self == other) 182 | 183 | 184 | def __lt__(self, other): 185 | return self._cmp_op(other, operator.lt) 186 | 187 | 188 | def __le__(self, other): 189 | return self._cmp_op(other, operator.le) 190 | 191 | 192 | def __gt__(self, other): 193 | return self._cmp_op(other, operator.gt) 194 | 195 | 196 | def __ge__(self, other): 197 | return self._cmp_op(other, operator.ge) 198 | 199 | 200 | def __str__(self): 201 | return coder.positrep_to_str(self.rep) 202 | 203 | 204 | def _cmp_op(self, other, op): 205 | a = self.rep 206 | b = other.rep 207 | 208 | if a['t'] == 'c' or b['t'] == 'c': 209 | return False 210 | 211 | (xa,ma) = self._fixedpoint() 212 | (xb,mb) = other._fixedpoint() 213 | 214 | m = max(ma, mb) 215 | xa <<= m - mb 216 | xb <<= m - ma 217 | 218 | return op(xa, xb) 219 | 220 | 221 | # Return (x,m) representing number = x * 2^m 222 | def _fixedpoint(self): 223 | rep = self.rep 224 | 225 | assert rep['t'] != 'c' 226 | 227 | if rep['t'] == 'z': 228 | x = 0 229 | m = 0 230 | else: 231 | assert rep['t'] == 'n' 232 | 233 | x = (-1)**rep['s'] * (2**rep['h'] + rep['f']) 234 | m = 2**rep['es'] * rep['k'] + rep['e'] - rep['h'] 235 | 236 | return (x,m) 237 | 238 | 239 | @classmethod 240 | def _fixedpoint_to_posit(cls, x, m, nbits=None, es=None): 241 | assert nbits is not None 242 | assert es is not None 243 | 244 | if x == 0: 245 | return PCPosit('0', nbits=nbits, es=es) 246 | 247 | p = PCPosit(nbits=nbits, es=es) 248 | p.rep['t'] = 'n' 249 | p.rep['s'] = 0 250 | 251 | if x < 0: 252 | x = -x 253 | p.rep['s'] = 1 254 | 255 | assert x != 0 256 | 257 | while x != 0 and x % 2 == 0: 258 | x >>= 1 259 | m += 1 260 | 261 | g = 0 262 | y = x 263 | while y >= 2: 264 | y >>= 1 265 | g -= 1 266 | 267 | assert y >= 1 and y < 2, "y={}".format(y) 268 | 269 | p.rep['e'] = (m - g) % 2**es 270 | p.rep['k'] = (m - g) // 2**es 271 | 272 | p.rep['h'] = -g 273 | p.rep['f'] = x - 2**p.rep['h'] 274 | 275 | bits = coder.encode_posit_binary(p.rep) 276 | p.rep = coder.decode_posit_binary(bits, nbits=nbits, es=es) 277 | 278 | return p 279 | -------------------------------------------------------------------------------- /src/sgposit/coder.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2018 SpeedGo Computing 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | import copy 25 | import numbers 26 | import sys 27 | 28 | if sys.version_info.major >= 3: 29 | from math import gcd 30 | else: 31 | from fractions import gcd 32 | 33 | from sgposit import bitops 34 | 35 | 36 | def create_positrep(nbits=32, es=2, s=0, k=0, e=0, f=0, h=0, t='n'): 37 | return { 's': s, 'k': k, 'e': e, 'f': f, 'h': h, 'nbits': nbits, 'es': es, 't': t } 38 | 39 | 40 | def create_zero_positrep(nbits=32, es=2): 41 | return create_positrep(nbits=nbits, es=es, s=0, k=0, e=0, f=0, h=0, t='z') 42 | 43 | 44 | def create_cinf_positrep(nbits=32, es=2): 45 | return create_positrep(nbits=nbits, es=es, s=0, k=0, e=0, f=0, h=0, t='c') 46 | 47 | 48 | def copy_positrep(rep): 49 | return copy.deepcopy(rep) 50 | 51 | 52 | def decode_posit_binary(bits, nbits, es): 53 | assert nbits >= 2 and es >= 0 54 | 55 | rep = create_positrep(nbits=nbits, es=es) 56 | 57 | if bits == 0: 58 | rep['t'] = 'z' 59 | return rep 60 | elif bits == (1 << (nbits-1)): 61 | rep['t'] = 'c' 62 | return rep 63 | 64 | assert rep['t'] == 'n' 65 | 66 | rep['s'] = bitops.get_int_bits(bits, nbits-1) 67 | 68 | if rep['s'] == 1: bits = -bits 69 | 70 | regime = bitops.get_int_bits(bits, nbits-2) 71 | nleads = bitops.count_leading_bits(bits, regime, nbits-2) 72 | 73 | if regime == 0: 74 | assert 1 <= nleads and nleads <= nbits-2 75 | rep['k'] = -nleads 76 | else: 77 | assert 1 <= nleads and nleads <= nbits-1 78 | rep['k'] = nleads - 1 79 | 80 | i = nbits - 1 - nleads - 1 - 1 # n - signbit - rs - rbar - nextbit 81 | 82 | e = 0 83 | nebits = 0 84 | while i >= 0 and nebits < es: 85 | e = 2*e | bitops.get_int_bits(bits, i) 86 | i -= 1 87 | nebits += 1 88 | e <<= es - nebits 89 | rep['e'] = e 90 | 91 | rep['h'] = max(0, i+1) # Remaining bits, and +1 since i is 0-based. 92 | if rep['h'] > 0: 93 | rep['f'] = bitops.get_int_bits(bits, 0, i) 94 | 95 | return rep 96 | 97 | 98 | def encode_posit_binary(rep): 99 | assert isinstance(rep['nbits'], numbers.Integral) and rep['nbits'] >= 2 100 | assert isinstance(rep['es' ], numbers.Integral) and rep['es'] >= 0 101 | assert isinstance(rep['s' ], numbers.Integral) and (rep['s'] == 0 or rep['s'] == 1) 102 | assert isinstance(rep['e' ], numbers.Integral) and rep['e'] >= 0 and rep['e'] <= 2**rep['es'] - 1 103 | assert isinstance(rep['h' ], numbers.Integral) and rep['h'] >= 0 104 | assert isinstance(rep['f' ], numbers.Integral) and rep['f'] >= 0 and rep['f'] <= 2**rep['h'] - 1 105 | assert rep['t'] in ['c', 'n', 'z'] 106 | 107 | if rep['t'] == 'z': 108 | return 0 109 | elif rep['t'] == 'c': 110 | return 1 << (rep['nbits']-1) 111 | 112 | assert rep['t'] == 'n' 113 | 114 | maxpos_bits = 2**(rep['nbits']-1) - 1 115 | 116 | n = rep['nbits'] - 1 # Remaining number of bits after reserving 1 for sign bit. 117 | bits = 0 118 | rounded = False 119 | 120 | if rep['k'] >= 0: 121 | if n >= rep['k'] + 1: 122 | bits = bitops.create_mask(rep['k'] + 1) 123 | n -= rep['k'] + 1 124 | 125 | assert n >= 0 126 | 127 | if n > 0: 128 | bits <<= 1 129 | n -= 1 130 | else: 131 | bits = bitops.create_mask(n) 132 | n = 0 133 | rounded = True 134 | else: 135 | bits = 1 136 | if n < -rep['k'] + 1: 137 | rounded = True 138 | n -= min(n, -rep['k'] + 1) 139 | 140 | assert n >= 0 141 | 142 | if n >= rep['es']: 143 | bits <<= rep['es'] 144 | bits |= rep['e'] 145 | n -= rep['es'] 146 | elif rounded == False: 147 | assert rep['es'] > 0 148 | 149 | m = rep['es'] - n # Number of exponent bits to truncate. 150 | te = rep['e'] >> m 151 | te <<= m # Rounded down exponent bits. 152 | 153 | value = rep['e'] * 2**rep['h'] + rep['f'] 154 | represented_value = te * 2**rep['h'] 155 | truncation = value - represented_value 156 | tie = 2**(m + rep['h'] - 1) 157 | 158 | te >>= m # Truncated exponent bits. 159 | bits <<= n 160 | bits |= te 161 | n = 0 162 | 163 | if truncation == tie: 164 | if bits & 0x01 and bits < maxpos_bits: 165 | bits += 1 166 | elif truncation > tie: 167 | if bits < maxpos_bits: 168 | bits += 1 169 | 170 | rounded = True 171 | 172 | assert n >= 0 173 | 174 | if n > rep['h']: 175 | bits <<= rep['h'] 176 | bits |= rep['f'] 177 | n -= rep['h'] 178 | 179 | bits <<= n 180 | n = 0 181 | 182 | elif rounded == False: 183 | m = rep['h'] - n # Number of fractional bits to truncate. 184 | tf = rep['f'] >> m 185 | tf <<= m # Rounded down fractional bits. 186 | 187 | value = rep['f'] 188 | represented_value = tf 189 | truncation = value - represented_value 190 | tie = 2**(m-1) 191 | 192 | tf >>= m # Truncated fractional bits. 193 | bits <<= n 194 | bits |= tf 195 | n = 0 196 | 197 | if truncation == tie: 198 | if bits & 0x01 and bits < maxpos_bits: 199 | bits += 1 200 | elif truncation > tie: 201 | if bits < maxpos_bits: 202 | bits += 1 203 | 204 | rounded = True 205 | 206 | assert n == 0 207 | 208 | if rep['s'] == 1: 209 | bits = -bits 210 | mask = bitops.create_mask(rep['nbits']) 211 | bits &= mask 212 | 213 | assert isinstance(bits, numbers.Integral) and bits >= 0 and bits <= bitops.create_mask(rep['nbits']) 214 | 215 | return bits 216 | 217 | 218 | # rep: normal posit representation, 219 | # return (sign, intpart, num, den) where number = sign*(intpart + num/den) 220 | def positrep_normal_to_rational(rep): 221 | assert rep['t'] == 'n' 222 | 223 | E = (2**rep['es'] * rep['k']) + rep['e'] 224 | V = (1 << rep['h']) + rep['f'] 225 | D = rep['h'] 226 | 227 | if E >= 0: 228 | V <<= E 229 | else: 230 | D += -E 231 | 232 | mask = bitops.create_mask(D) 233 | num = V & mask 234 | den = 1 << D 235 | intpart = V >> D 236 | 237 | g = gcd(num, den) 238 | num //= g 239 | den //= g 240 | sign = 1 if rep['s'] == 0 else -1 241 | 242 | assert sign == -1 or sign == 1 243 | assert intpart >= 0 244 | assert num >= 0 245 | assert den >= 1 246 | 247 | return (sign, intpart, num, den) 248 | 249 | 250 | # rational: (sign, intpart, num, den) where number = sign*(intpart + num/den) 251 | def rational_to_str(rational, separate_intpart=False): 252 | 253 | (sign, intpart, num, den) = rational 254 | 255 | assert sign == -1 or sign == 1 256 | assert intpart >= 0 257 | assert num >= 0 258 | assert den >= 1 259 | 260 | out = '' if sign > 0 else '-' 261 | 262 | if num == 0: 263 | out += str(intpart) 264 | else: 265 | if separate_intpart: 266 | if intpart != 0: 267 | out += str(intpart) 268 | out += '+' if sign > 0 else '-' 269 | else: 270 | num += den*intpart 271 | 272 | out += str(num) + '/' + str(den) 273 | 274 | return out 275 | 276 | 277 | def positrep_to_rational_str(rep, separate_intpart=False): 278 | if rep['t'] == 'z': 279 | return '0' 280 | elif rep['t'] == 'c': 281 | return 'cinf' 282 | 283 | assert rep['t'] == 'n' 284 | 285 | rational = positrep_normal_to_rational(rep) 286 | 287 | return rational_to_str(rational, separate_intpart=separate_intpart) 288 | 289 | 290 | def positrep_to_str(rep): 291 | return positrep_to_rational_str(rep, separate_intpart=True) 292 | -------------------------------------------------------------------------------- /tests/test_pcposit_exhaustive.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2018 SpeedGo Computing 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | from __future__ import division 25 | 26 | import os 27 | import unittest 28 | 29 | from mpmath import mp 30 | 31 | from sgposit import bitops 32 | from sgposit import coder 33 | from sgposit.pcposit import PCPosit 34 | 35 | 36 | class TestPCPositExhaustive(unittest.TestCase): 37 | 38 | _multiprocess_can_split_ = True 39 | 40 | 41 | def setUp(self): 42 | mp.dps = 1000 43 | 44 | self.nbits_range = range(2,9) 45 | self.es_range = range(0,3) 46 | 47 | 48 | def tearDown(self): 49 | pass 50 | 51 | 52 | def run_posit_1op_exhaustive(self, op_str=None, nbits_range=None, es_range=None): 53 | raise NotImplementedError 54 | 55 | 56 | # (a op b) rounded to nearest tests, with reference to mpmath computed results. 57 | def run_posit_2op_exhaustive(self, op_str=None, nbits_range=None, es_range=None): 58 | op = None 59 | mpop = None 60 | if op_str == '+': 61 | op = PCPosit.__add__ 62 | mpop = mp.mpf.__add__ 63 | elif op_str == '-': 64 | op = PCPosit.__sub__ 65 | mpop = mp.mpf.__sub__ 66 | elif op_str == '*': 67 | op = PCPosit.__mul__ 68 | mpop = mp.mpf.__mul__ 69 | elif op_str == '/': 70 | op = PCPosit.__truediv__ 71 | mpop = mp.mpf.__truediv__ 72 | else: 73 | raise NotImplementedError("op={}".format(op_str)) 74 | 75 | if nbits_range is None: 76 | nbits_range = self.nbits_range 77 | if es_range is None: 78 | es_range = self.es_range 79 | 80 | for nbits in nbits_range: 81 | mask = bitops.create_mask(nbits) 82 | cinf_bits = 1 << (nbits-1) 83 | is_special = lambda bits: bits == 0 or bits == cinf_bits 84 | is_normal = lambda bits: not is_special(bits) 85 | for es in es_range: 86 | for abits in range(2**nbits): 87 | for bbits in range(2**nbits): 88 | a = PCPosit(abits, nbits=nbits, es=es, mode='bits') 89 | b = PCPosit(bbits, nbits=nbits, es=es, mode='bits') 90 | c = op(a, b) 91 | cbits = coder.encode_posit_binary(c.rep) 92 | 93 | test_info = { 94 | 'nbits' : nbits, 95 | 'es' : es, 96 | 'a' : str(a), 97 | 'b' : str(b), 98 | 'c' : str(c), 99 | 'abits' : abits, 100 | 'bbits' : bbits, 101 | 'cbits' : cbits, 102 | 'arep' : a.rep, 103 | 'brep' : b.rep, 104 | 'crep' : c.rep, 105 | } 106 | 107 | if is_normal(abits) and is_normal(bbits) and cbits == 0: 108 | self.assertTrue(op_str in ['+', '-']) 109 | if op_str == '+': 110 | self.assertEqual(abits, -bbits & mask) 111 | else: # '-' 112 | self.assertEqual(abits, bbits) 113 | 114 | elif is_normal(abits) and is_normal(bbits): 115 | self.assertNotEqual(cbits, 0) 116 | self.assertNotEqual(cbits, cinf_bits) 117 | 118 | amp = mp.mpf(eval(coder.positrep_to_rational_str(a.rep))) 119 | bmp = mp.mpf(eval(coder.positrep_to_rational_str(b.rep))) 120 | c2mp = mpop(amp, bmp) 121 | 122 | c0bits = (cbits-1) & mask 123 | while c0bits == 0 or c0bits == cinf_bits: 124 | c0bits = (c0bits-1) & mask 125 | 126 | c1bits = (cbits+1) & mask 127 | while c1bits == 0 or c1bits == cinf_bits: 128 | c1bits = (c1bits+1) & mask 129 | 130 | c0 = PCPosit(c0bits, nbits=nbits, es=es, mode='bits') 131 | c1 = PCPosit(c1bits, nbits=nbits, es=es, mode='bits') 132 | 133 | test_info['c0' ] = str(c0) 134 | test_info['c1' ] = str(c1) 135 | test_info['c0bits'] = c0bits 136 | test_info['c1bits'] = c1bits 137 | test_info['c0rep' ] = c0.rep 138 | test_info['c1rep' ] = c1.rep 139 | 140 | rcmp = mp.mpf(eval(coder.positrep_to_rational_str(c.rep))) 141 | cratiodiffmp = mp.fabs(mp.log(rcmp/c2mp)) if c2mp != 0 else mp.fabs(rcmp - c2mp) 142 | cabsdiffmp = mp.fabs(rcmp - c2mp) 143 | 144 | c0mp = mp.mpf(eval(coder.positrep_to_rational_str(c0.rep))) 145 | c0ratiodiffmp = mp.fabs(mp.log(c0mp/c2mp)) if c2mp != 0 else mp.fabs(c0mp - c2mp) 146 | c0absdiffmp = mp.fabs(c0mp - c2mp) 147 | self.assertTrue(cratiodiffmp <= c0ratiodiffmp or cabsdiffmp <= c0absdiffmp, test_info) 148 | 149 | c1mp = mp.mpf(eval(coder.positrep_to_rational_str(c1.rep))) 150 | c1ratiodiffmp = mp.fabs(mp.log(c1mp/c2mp)) if c2mp != 0 else mp.fabs(c1mp - c2mp) 151 | c1absdiffmp = mp.fabs(c1mp - c2mp) 152 | self.assertTrue(cratiodiffmp <= c1ratiodiffmp or cabsdiffmp <= c1absdiffmp, test_info) 153 | 154 | elif abits == cinf_bits: 155 | self.assertTrue(op_str in ['+', '-', '*', '/']) 156 | self.assertEqual(cbits, cinf_bits) 157 | 158 | elif abits != cinf_bits and bbits == cinf_bits: 159 | self.assertTrue(op_str in ['+', '-', '*', '/']) 160 | if op_str == '/': 161 | self.assertEqual(cbits, 0) 162 | else: 163 | self.assertEqual(cbits, cinf_bits) 164 | 165 | elif abits == 0 and bbits == 0: 166 | self.assertTrue(op_str in ['+', '-', '*', '/']) 167 | if op_str == '/': 168 | self.assertEqual(cbits, cinf_bits) 169 | else: 170 | self.assertEqual(cbits, 0) 171 | 172 | elif is_normal(abits) and bbits == 0: 173 | if op_str == '+' or op_str == '-': 174 | self.assertEqual(cbits, abits) 175 | elif op_str == '*': 176 | self.assertEqual(cbits, 0) 177 | elif op_str == '/': 178 | self.assertEqual(cbits, cinf_bits) 179 | else: 180 | self.assertTrue(False) 181 | 182 | elif abits == 0 and is_normal(bbits): 183 | self.assertTrue(op_str in ['+', '-', '*', '/']) 184 | if op_str == '+': 185 | self.assertEqual(cbits, bbits) 186 | elif op_str == '-': 187 | self.assertEqual(cbits, -bbits & mask) 188 | else: 189 | self.assertEqual(cbits, 0) 190 | 191 | else: 192 | self.assertTrue(False) 193 | 194 | 195 | @unittest.skipUnless(os.environ.get('SGPOSIT_LONG_TESTS') == '1', 'Long test.') 196 | def test_add_exhaustive(self): 197 | self.run_posit_2op_exhaustive('+') 198 | 199 | @unittest.skipUnless(os.environ.get('SGPOSIT_LONG_TESTS') == '1', 'Long test.') 200 | def test_sub_exhaustive(self): 201 | self.run_posit_2op_exhaustive('-') 202 | 203 | @unittest.skipUnless(os.environ.get('SGPOSIT_LONG_TESTS') == '1', 'Long test.') 204 | def test_mul_exhaustive(self): 205 | self.run_posit_2op_exhaustive('*') 206 | 207 | @unittest.skipUnless(os.environ.get('SGPOSIT_LONG_TESTS') == '1', 'Long test.') 208 | def test_truediv_exhaustive(self): 209 | self.run_posit_2op_exhaustive('/') 210 | 211 | 212 | if __name__ == '__main__': 213 | unittest.main() 214 | -------------------------------------------------------------------------------- /tests/test_pcposit.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2018 SpeedGo Computing 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | import unittest 25 | 26 | from sgposit import coder 27 | from sgposit.pcposit import PCPosit 28 | 29 | 30 | class TestPCPosit(unittest.TestCase): 31 | 32 | def setUp(self): 33 | self.posit_n6e2_m1o16_bits = 0x38 34 | self.posit_n6e2_m1o2_bits = 0x32 35 | self.posit_n6e2_m1o64_bits = 0x3A 36 | self.posit_n6e2_m3o2_bits = 0x2F 37 | self.posit_n6e2_m3o4_bits = 0x31 38 | self.posit_n6e2_m3o8_bits = 0x33 39 | self.posit_n6e2_m3o16_bits = 0x35 40 | 41 | self.posit_n6e2_1_bits = 0x10 42 | self.posit_n6e2_1o2_bits = 0x0E 43 | self.posit_n6e2_1o4_bits = 0x0C 44 | self.posit_n6e2_1o8_bits = 0x0A 45 | self.posit_n6e2_2_bits = 0x12 46 | self.posit_n6e2_3_bits = 0x13 47 | self.posit_n6e2_3o2_bits = 0x11 48 | self.posit_n6e2_3o4_bits = 0x0F 49 | self.posit_n6e2_3o16_bits = 0x0B 50 | self.posit_n6e2_3o8_bits = 0x0D 51 | self.posit_n6e2_cinf_bits = 0x20 52 | 53 | 54 | def tearDown(self): 55 | pass 56 | 57 | 58 | def run_posit_op(self, abits=None, op_str=None, bbits=None, ref_cbits=None, nbits=None, es=None): 59 | a = PCPosit(abits, nbits=nbits, es=es, mode='bits') 60 | b = PCPosit(bbits, nbits=nbits, es=es, mode='bits') 61 | c = None 62 | 63 | if op_str == '+': 64 | c = a + b 65 | elif op_str == '-': 66 | c = a - b 67 | elif op_str == '*': 68 | c = a * b 69 | elif op_str == '/': 70 | c = a / b 71 | elif op_str == 'u-': 72 | c = -a 73 | else: 74 | raise NotImplementedError("op={}".format(op_str)) 75 | 76 | cbits = coder.encode_posit_binary(c.rep) 77 | self.assertEqual(cbits, ref_cbits) 78 | 79 | 80 | def test_add_simple(self): 81 | self.run_posit_op(self.posit_n6e2_3o2_bits, '+', self.posit_n6e2_3o2_bits, self.posit_n6e2_3_bits, 6, 2) 82 | self.run_posit_op(self.posit_n6e2_1o4_bits, '+', self.posit_n6e2_3o4_bits, self.posit_n6e2_1_bits, 6, 2) 83 | self.run_posit_op(self.posit_n6e2_1o8_bits, '+', self.posit_n6e2_m3o16_bits, self.posit_n6e2_m1o16_bits, 6, 2) 84 | self.run_posit_op(self.posit_n6e2_3o8_bits, '+', self.posit_n6e2_3o4_bits, self.posit_n6e2_1_bits, 6, 2) 85 | self.run_posit_op(self.posit_n6e2_3o2_bits, '+', self.posit_n6e2_1_bits, self.posit_n6e2_2_bits, 6, 2) 86 | 87 | 88 | def test_sub_simple(self): 89 | self.run_posit_op(self.posit_n6e2_3o2_bits, '-', self.posit_n6e2_3o2_bits, 0, 6, 2) 90 | self.run_posit_op(self.posit_n6e2_1o4_bits, '-', self.posit_n6e2_3o4_bits, self.posit_n6e2_m1o2_bits, 6, 2) 91 | self.run_posit_op(self.posit_n6e2_1o8_bits, '-', self.posit_n6e2_m3o16_bits, self.posit_n6e2_1o4_bits, 6, 2) # result: 5/16 ~> 1/4 92 | self.run_posit_op(self.posit_n6e2_3o8_bits, '-', self.posit_n6e2_3o4_bits, self.posit_n6e2_m3o8_bits, 6, 2) 93 | self.run_posit_op(self.posit_n6e2_3o2_bits, '-', self.posit_n6e2_1_bits, self.posit_n6e2_1o2_bits, 6, 2) 94 | 95 | 96 | def test_neg_simple(self): 97 | self.run_posit_op(self.posit_n6e2_3o2_bits, 'u-', None, self.posit_n6e2_m3o2_bits, 6, 2) 98 | self.run_posit_op(self.posit_n6e2_m3o16_bits, 'u-', None, self.posit_n6e2_3o16_bits, 6, 2) 99 | 100 | 101 | def test_mul_simple(self): 102 | self.run_posit_op(self.posit_n6e2_3o2_bits, '*', self.posit_n6e2_3o2_bits, self.posit_n6e2_2_bits, 6, 2) 103 | self.run_posit_op(self.posit_n6e2_1o4_bits, '*', self.posit_n6e2_3o4_bits, self.posit_n6e2_3o16_bits, 6, 2) 104 | self.run_posit_op(self.posit_n6e2_1o8_bits, '*', self.posit_n6e2_m3o16_bits, self.posit_n6e2_m1o64_bits, 6, 2) 105 | self.run_posit_op(self.posit_n6e2_3o8_bits, '*', self.posit_n6e2_3o4_bits, self.posit_n6e2_1o4_bits, 6, 2) 106 | self.run_posit_op(self.posit_n6e2_3o2_bits, '*', self.posit_n6e2_1_bits, self.posit_n6e2_3o2_bits, 6, 2) 107 | 108 | 109 | def test_truediv_simple(self): 110 | self.run_posit_op(self.posit_n6e2_3o2_bits, '/', self.posit_n6e2_3o2_bits, self.posit_n6e2_1_bits, 6, 2) 111 | self.run_posit_op(self.posit_n6e2_1o4_bits, '/', self.posit_n6e2_3o4_bits, self.posit_n6e2_3o8_bits, 6, 2) 112 | self.run_posit_op(self.posit_n6e2_1o8_bits, '/', self.posit_n6e2_m3o16_bits, self.posit_n6e2_m3o4_bits, 6, 2) 113 | self.run_posit_op(self.posit_n6e2_3o8_bits, '/', self.posit_n6e2_3o4_bits, self.posit_n6e2_1o2_bits, 6, 2) 114 | self.run_posit_op(self.posit_n6e2_3o2_bits, '/', self.posit_n6e2_1_bits, self.posit_n6e2_3o2_bits, 6, 2) 115 | 116 | 117 | def test_create_pcposit_from_large_int_bits(self): 118 | p0 = PCPosit(3**80, mode='bits', nbits=256, es=2) 119 | p1 = PCPosit(5**90, mode='bits', nbits=256, es=2) 120 | p2 = p0 + p1 121 | p3 = p0 - p1 122 | p4 = p0 * p1 123 | p5 = p0 / p1 124 | 125 | 126 | @unittest.skip("Not implemented.") 127 | def test_floordiv(self): 128 | raise NotImplementedError 129 | 130 | 131 | def run_posit_cmp_op(self, abits=None, op_str=None, bbits=None, ref_output=None, nbits=None, es=None): 132 | a = PCPosit(abits, nbits=nbits, es=es, mode='bits') 133 | b = PCPosit(bbits, nbits=nbits, es=es, mode='bits') 134 | out = None 135 | 136 | if op_str == '==': 137 | out = (a == b) 138 | elif op_str == '!=': 139 | out = (a != b) 140 | elif op_str == '<': 141 | out = (a < b) 142 | elif op_str == '<=': 143 | out = (a <= b) 144 | elif op_str == '>': 145 | out = (a > b) 146 | elif op_str == '>=': 147 | out = (a >= b) 148 | else: 149 | raise NotImplementedError("op={}".format(op_str)) 150 | 151 | self.assertEqual(out, ref_output) 152 | 153 | 154 | def test_eq(self): 155 | self.run_posit_cmp_op(0, '==', 0, True, 6, 2) 156 | self.run_posit_cmp_op(0, '==', self.posit_n6e2_cinf_bits, False, 6, 2) 157 | self.run_posit_cmp_op(0, '==', self.posit_n6e2_3o2_bits, False, 6, 2) 158 | self.run_posit_cmp_op(0, '==', self.posit_n6e2_m3o16_bits, False, 6, 2) 159 | 160 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '==', 0, False, 6, 2) 161 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '==', self.posit_n6e2_cinf_bits, False, 6, 2) 162 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '==', self.posit_n6e2_3o2_bits, False, 6, 2) 163 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '==', self.posit_n6e2_m3o16_bits, False, 6, 2) 164 | 165 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '==', 0, False, 6, 2) 166 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '==', self.posit_n6e2_cinf_bits, False, 6, 2) 167 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '==', self.posit_n6e2_3o2_bits, True, 6, 2) 168 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '==', self.posit_n6e2_m3o16_bits, False, 6, 2) 169 | 170 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '==', 0, False, 6, 2) 171 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '==', self.posit_n6e2_cinf_bits, False, 6, 2) 172 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '==', self.posit_n6e2_3o2_bits, False, 6, 2) 173 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '==', self.posit_n6e2_m3o16_bits, True, 6, 2) 174 | 175 | 176 | def test_ne(self): 177 | self.run_posit_cmp_op(0, '!=', 0, False, 6, 2) 178 | self.run_posit_cmp_op(0, '!=', self.posit_n6e2_cinf_bits, True, 6, 2) 179 | self.run_posit_cmp_op(0, '!=', self.posit_n6e2_3o2_bits, True, 6, 2) 180 | self.run_posit_cmp_op(0, '!=', self.posit_n6e2_m3o16_bits, True, 6, 2) 181 | 182 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '!=', 0, True, 6, 2) 183 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '!=', self.posit_n6e2_cinf_bits, True, 6, 2) 184 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '!=', self.posit_n6e2_3o2_bits, True, 6, 2) 185 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '!=', self.posit_n6e2_m3o16_bits, True, 6, 2) 186 | 187 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '!=', 0, True, 6, 2) 188 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '!=', self.posit_n6e2_cinf_bits, True, 6, 2) 189 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '!=', self.posit_n6e2_3o2_bits, False, 6, 2) 190 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '!=', self.posit_n6e2_m3o16_bits, True, 6, 2) 191 | 192 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '!=', 0, True, 6, 2) 193 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '!=', self.posit_n6e2_cinf_bits, True, 6, 2) 194 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '!=', self.posit_n6e2_3o2_bits, True, 6, 2) 195 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '!=', self.posit_n6e2_m3o16_bits, False, 6, 2) 196 | 197 | 198 | def test_lt(self): 199 | self.run_posit_cmp_op(0, '<', 0, False, 6, 2) 200 | self.run_posit_cmp_op(0, '<', self.posit_n6e2_cinf_bits, False, 6, 2) 201 | self.run_posit_cmp_op(0, '<', self.posit_n6e2_3o2_bits, True, 6, 2) 202 | self.run_posit_cmp_op(0, '<', self.posit_n6e2_m3o16_bits, False, 6, 2) 203 | 204 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '<', 0, False, 6, 2) 205 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '<', self.posit_n6e2_cinf_bits, False, 6, 2) 206 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '<', self.posit_n6e2_3o2_bits, False, 6, 2) 207 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '<', self.posit_n6e2_m3o16_bits, False, 6, 2) 208 | 209 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<', 0, False, 6, 2) 210 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<', self.posit_n6e2_cinf_bits, False, 6, 2) 211 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<', self.posit_n6e2_3o2_bits, False, 6, 2) 212 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<', self.posit_n6e2_m3o16_bits, False, 6, 2) 213 | 214 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<', 0, True, 6, 2) 215 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<', self.posit_n6e2_cinf_bits, False, 6, 2) 216 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<', self.posit_n6e2_3o2_bits, True, 6, 2) 217 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<', self.posit_n6e2_m3o16_bits, False, 6, 2) 218 | 219 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<', self.posit_n6e2_m1o16_bits, False, 6, 2) 220 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<', self.posit_n6e2_3_bits, True, 6, 2) 221 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<', self.posit_n6e2_1o2_bits, False, 6, 2) 222 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<', self.posit_n6e2_m3o4_bits, False, 6, 2) 223 | 224 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<', self.posit_n6e2_m1o16_bits, True, 6, 2) 225 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<', self.posit_n6e2_3_bits, True, 6, 2) 226 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<', self.posit_n6e2_1o2_bits, True, 6, 2) 227 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<', self.posit_n6e2_m3o4_bits, False, 6, 2) 228 | 229 | 230 | def test_le(self): 231 | self.run_posit_cmp_op(0, '<=', 0, True, 6, 2) 232 | self.run_posit_cmp_op(0, '<=', self.posit_n6e2_cinf_bits, False, 6, 2) 233 | self.run_posit_cmp_op(0, '<=', self.posit_n6e2_3o2_bits, True, 6, 2) 234 | self.run_posit_cmp_op(0, '<=', self.posit_n6e2_m3o16_bits, False, 6, 2) 235 | 236 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '<=', 0, False, 6, 2) 237 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '<=', self.posit_n6e2_cinf_bits, False, 6, 2) 238 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '<=', self.posit_n6e2_3o2_bits, False, 6, 2) 239 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '<=', self.posit_n6e2_m3o16_bits, False, 6, 2) 240 | 241 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<=', 0, False, 6, 2) 242 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<=', self.posit_n6e2_cinf_bits, False, 6, 2) 243 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<=', self.posit_n6e2_3o2_bits, True, 6, 2) 244 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<=', self.posit_n6e2_m3o16_bits, False, 6, 2) 245 | 246 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<=', 0, True, 6, 2) 247 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<=', self.posit_n6e2_cinf_bits, False, 6, 2) 248 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<=', self.posit_n6e2_3o2_bits, True, 6, 2) 249 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<=', self.posit_n6e2_m3o16_bits, True, 6, 2) 250 | 251 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<=', self.posit_n6e2_m1o16_bits, False, 6, 2) 252 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<=', self.posit_n6e2_3_bits, True, 6, 2) 253 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<=', self.posit_n6e2_1o2_bits, False, 6, 2) 254 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '<=', self.posit_n6e2_m3o4_bits, False, 6, 2) 255 | 256 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<=', self.posit_n6e2_m1o16_bits, True, 6, 2) 257 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<=', self.posit_n6e2_3_bits, True, 6, 2) 258 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<=', self.posit_n6e2_1o2_bits, True, 6, 2) 259 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '<=', self.posit_n6e2_m3o4_bits, False, 6, 2) 260 | 261 | 262 | def test_gt(self): 263 | self.run_posit_cmp_op(0, '>', 0, False, 6, 2) 264 | self.run_posit_cmp_op(0, '>', self.posit_n6e2_cinf_bits, False, 6, 2) 265 | self.run_posit_cmp_op(0, '>', self.posit_n6e2_3o2_bits, False, 6, 2) 266 | self.run_posit_cmp_op(0, '>', self.posit_n6e2_m3o16_bits, True, 6, 2) 267 | 268 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '>', 0, False, 6, 2) 269 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '>', self.posit_n6e2_cinf_bits, False, 6, 2) 270 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '>', self.posit_n6e2_3o2_bits, False, 6, 2) 271 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '>', self.posit_n6e2_m3o16_bits, False, 6, 2) 272 | 273 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>', 0, True, 6, 2) 274 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>', self.posit_n6e2_cinf_bits, False, 6, 2) 275 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>', self.posit_n6e2_3o2_bits, False, 6, 2) 276 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>', self.posit_n6e2_m3o16_bits, True, 6, 2) 277 | 278 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>', 0, False, 6, 2) 279 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>', self.posit_n6e2_cinf_bits, False, 6, 2) 280 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>', self.posit_n6e2_3o2_bits, False, 6, 2) 281 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>', self.posit_n6e2_m3o16_bits, False, 6, 2) 282 | 283 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>', self.posit_n6e2_m1o16_bits, True, 6, 2) 284 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>', self.posit_n6e2_3_bits, False, 6, 2) 285 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>', self.posit_n6e2_1o2_bits, True, 6, 2) 286 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>', self.posit_n6e2_m3o4_bits, True, 6, 2) 287 | 288 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>', self.posit_n6e2_m1o16_bits, False, 6, 2) 289 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>', self.posit_n6e2_3_bits, False, 6, 2) 290 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>', self.posit_n6e2_1o2_bits, False, 6, 2) 291 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>', self.posit_n6e2_m3o4_bits, True, 6, 2) 292 | 293 | 294 | def test_ge(self): 295 | self.run_posit_cmp_op(0, '>=', 0, True, 6, 2) 296 | self.run_posit_cmp_op(0, '>=', self.posit_n6e2_cinf_bits, False, 6, 2) 297 | self.run_posit_cmp_op(0, '>=', self.posit_n6e2_3o2_bits, False, 6, 2) 298 | self.run_posit_cmp_op(0, '>=', self.posit_n6e2_m3o16_bits, True, 6, 2) 299 | 300 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '>=', 0, False, 6, 2) 301 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '>=', self.posit_n6e2_cinf_bits, False, 6, 2) 302 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '>=', self.posit_n6e2_3o2_bits, False, 6, 2) 303 | self.run_posit_cmp_op(self.posit_n6e2_cinf_bits, '>=', self.posit_n6e2_m3o16_bits, False, 6, 2) 304 | 305 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>=', 0, True, 6, 2) 306 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>=', self.posit_n6e2_cinf_bits, False, 6, 2) 307 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>=', self.posit_n6e2_3o2_bits, True, 6, 2) 308 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>=', self.posit_n6e2_m3o16_bits, True, 6, 2) 309 | 310 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>=', 0, False, 6, 2) 311 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>=', self.posit_n6e2_cinf_bits, False, 6, 2) 312 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>=', self.posit_n6e2_3o2_bits, False, 6, 2) 313 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>=', self.posit_n6e2_m3o16_bits, True, 6, 2) 314 | 315 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>=', self.posit_n6e2_m1o16_bits, True, 6, 2) 316 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>=', self.posit_n6e2_3_bits, False, 6, 2) 317 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>=', self.posit_n6e2_1o2_bits, True, 6, 2) 318 | self.run_posit_cmp_op(self.posit_n6e2_3o2_bits, '>=', self.posit_n6e2_m3o4_bits, True, 6, 2) 319 | 320 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>=', self.posit_n6e2_m1o16_bits, False, 6, 2) 321 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>=', self.posit_n6e2_3_bits, False, 6, 2) 322 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>=', self.posit_n6e2_1o2_bits, False, 6, 2) 323 | self.run_posit_cmp_op(self.posit_n6e2_m3o16_bits, '>=', self.posit_n6e2_m3o4_bits, True, 6, 2) 324 | 325 | 326 | @unittest.skip("Not implemented.") 327 | def test_str(self): 328 | raise NotImplementedError 329 | 330 | 331 | if __name__ == '__main__': 332 | unittest.main() 333 | --------------------------------------------------------------------------------