Robert Withrow <bigbaaad...@gmail.com> added the comment:

Martin: in C I have the luxury of using 32 bit floats; not an option in Python. 
 Simple code doing the moral equivalent of NTOHL(HTONL()) works in this case 
for C but wouldn't help for Python.

Mark: I understand about the precision truncation issue and how Python does 
floating point arithmetic.  This C code clearly demonstrates what is going on:

#include <stdio.h>

int main(int argc, char *argv[])
{
  double d1 = 6.21;
  float f = 6.21;
  double d2 = f;
  
  printf("double: %.15f\n", d1);
  printf("float: %.15f\n", f);
  printf("double converted from float: %15.15f\n", d2);
}

The point here is about the contract of struct, NOT how Python does floating 
point arithmetic.  The contract is: what pack packs, unpack will unpack 
resulting in the original value.  At least, that is what the documentation 
leads you to believe.

For the 'f' format character, this contract is broken because of a basic 
implementation detail of Python and there is nothing in the documentation for 
struct that *directly* lets you know this will happen.  After all, the mentions 
in the documentation about 32 bit versus 64 bit talk about C not Python!

Even worse, there is no straightforward way (that I'm aware of) to write 
portable tests for code using the 'f' format character.  In my case I'm writing 
a tool that creates message codecs in multiple languages and the most basic 
unit test goes something like this:

m1 = example.message()
m1.f1 = 6.21
b = m.encode() # uses struct pack
m2 = example.message(b) # uses struct unpack
if m1 != m2:  # rich comparison
  print('fail')

This test will fail when you use the 'f' format code.

I suggest two things could be done to improve the situation:

1) Add a note to the documentation for struct that tells you that unpack(pack) 
using the 'f' format code will not generally give you the results you probably 
expect because <insert pointer to discussion of pythons use of C double versus 
C float here>.

2) Create a way in Python to write portable code related to 32 bit floats.  For 
example, if I had a way in Python to cause the precision truncation 
programmatically:

m1 = example.message()
m1.f1 = 6.21.as_32_bit_float() # Does the precision truncation upfront
b = m.encode() # uses struct pack
m2 = example.message(b) # uses struct unpack
if m1 != m2:  # rich comparison
  print('fail')

I'd expect this test to pass.

Hope this long-winded note helps.

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue4114>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to