Skip to content

Commit 0fd3830

Browse files
committed
utils: add support for double-precision to ieee functions
1 parent 0aa251b commit 0fd3830

File tree

3 files changed

+40
-19
lines changed

3 files changed

+40
-19
lines changed

CHANGES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ Revision history for pyModbusTCP
22

33
0.x.x Next release
44

5+
- encode_ieee and decode_ieee, now support double-precision format with opt double.
56
- add shortcut alias for functions with long names in utils.
67
- rewrite of some functions in utils.
78
- improve test_utils readability.

pyModbusTCP/utils.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,30 +36,42 @@ def get_bits_from_int(val_int, val_size=16):
3636
#########################
3737
# floating-point function
3838
#########################
39-
def decode_ieee(val_int):
40-
"""Decode Python int (32 bits integer) as an IEEE single precision format
39+
def decode_ieee(val_int, double=False):
40+
"""Decode Python int (32 bits integer) as an IEEE single or double precision format
4141
4242
Support NaN.
4343
44-
:param val_int: a 32 bit integer as an int Python value
44+
:param val_int: a 32 or 64 bits integer as an int Python value
4545
:type val_int: int
46+
:param double: set to decode as a 64 bits double precision,
47+
default is 32 bits single (optional)
48+
:type double: bool
4649
:returns: float result
4750
:rtype: float
4851
"""
49-
return struct.unpack("f", struct.pack("I", val_int))[0]
52+
if double:
53+
return struct.unpack("d", struct.pack("Q", val_int))[0]
54+
else:
55+
return struct.unpack("f", struct.pack("I", val_int))[0]
5056

5157

52-
def encode_ieee(val_float):
53-
"""Encode Python float to int (32 bits integer) as an IEEE single precision
58+
def encode_ieee(val_float, double=False):
59+
"""Encode Python float to int (32 bits integer) as an IEEE single or double precision format
5460
5561
Support NaN.
5662
5763
:param val_float: float value to convert
5864
:type val_float: float
65+
:param double: set to encode as a 64 bits double precision,
66+
default is 32 bits single (optional)
67+
:type double: bool
5968
:returns: IEEE 32 bits (single precision) as Python int
6069
:rtype: int
6170
"""
62-
return struct.unpack("I", struct.pack("f", val_float))[0]
71+
if double:
72+
return struct.unpack("Q", struct.pack("d", val_float))[0]
73+
else:
74+
return struct.unpack("I", struct.pack("f", val_float))[0]
6375

6476

6577
################################

tests/test_utils.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,30 @@ def test_get_bits_from_int(self):
2323
self.assertEqual(int2bits(0xf007), [True]*3 + [False]*9 + [True]*4)
2424
self.assertEqual(int2bits(6, 4), [False, True, True, False])
2525

26-
def test_decode_ieee(self):
26+
def test_ieee(self):
2727
# test IEEE NaN
28-
self.assertTrue(math.isnan(decode_ieee(0x7fffffff)))
28+
self.assertTrue(math.isnan(decode_ieee(0x7fc00000)))
29+
self.assertEqual(encode_ieee(float('nan')), 0x7fc00000)
2930
# test +/- infinity
3031
self.assertTrue(math.isinf(decode_ieee(0xff800000)))
3132
self.assertTrue(math.isinf(decode_ieee(0x7f800000)))
32-
# test some values
33-
self.assertAlmostEqual(decode_ieee(0x3e99999a), 0.3)
34-
self.assertAlmostEqual(decode_ieee(0xbe99999a), -0.3)
35-
36-
def test_encode_ieee(self):
37-
# test IEEE NaN
38-
self.assertEqual(encode_ieee(float('nan')), 2143289344)
39-
# test some values
40-
self.assertAlmostEqual(encode_ieee(0.3), 0x3e99999a)
41-
self.assertAlmostEqual(encode_ieee(-0.3), 0xbe99999a)
33+
# test big and small values
34+
avogad = 6.022140857e+23
35+
avo_32 = 0x66ff0c2f
36+
avo_64 = 0x44dfe185d2f54b67
37+
planck = 6.62606957e-34
38+
pla_32 = 0x085c305e
39+
pla_64 = 0x390b860bb596a559
40+
# IEEE single or double precision format -> float
41+
self.assertAlmostEqual(decode_ieee(avo_32), avogad, delta=avogad*1e-7)
42+
self.assertAlmostEqual(decode_ieee(avo_64, double=True), avogad)
43+
self.assertAlmostEqual(decode_ieee(pla_32), planck)
44+
self.assertAlmostEqual(decode_ieee(pla_64, double=True), planck)
45+
# float -> IEEE single or double precision format
46+
self.assertAlmostEqual(encode_ieee(avogad), avo_32)
47+
self.assertAlmostEqual(encode_ieee(avogad, double=True), avo_64)
48+
self.assertAlmostEqual(encode_ieee(planck), pla_32)
49+
self.assertAlmostEqual(encode_ieee(planck, double=True), pla_64)
4250

4351
def test_word_list_to_long(self):
4452
# test word_list_to_long() and short alias words2longs()

0 commit comments

Comments
 (0)