Question

Python's float data type really uses double precision (64bit). However, for my specific implementation (that transmits typetagged values via OSC) I would to like differentiate between values that can be represented as (32bit) single precision floats and (64bit) double precision floats.

More precisely, I'd like to do something like this:

 if isdouble(value):
    binary=struct.pack('>d', value)
 else:
    binary=struct.pack('>f', value)

Is there any feasible way to achieve this?

Was it helpful?

Solution 2

I propose to just try it using float and if that fails (due to range overflow) use the double version:

try:
  binary = struct.pack('>f', value)
except OverflowError:
  binary = struct.pack('>d', value)

The range is the only aspect in which your question makes perfect sense.

If it comes to precision, your question loses to make sense because, as you say, Python always uses doubles internally, and even a simple 3.3 is, packed and unpacked as float, only 3.299999952316284 afterwards:

struct.unpack('>f', struct.pack('>f', 3.3))
(3.299999952316284,)

So virtually no double can be represented as a float. (Typically none that isn't an int or otherwise coming out of a float originally.)

You could, however, make a check whether the packed-unpacked version of your number equals the original, and if it does, use the float version:

try:
  binary = struct.pack('>f', value)
  if struct.unpack('>f', binary)[0] != value:
    binary = struct.pack('>d', value)
except OverflowError:
  binary = struct.pack('>d', value)

OTHER TIPS

You could test the range, if you don't mind the loss of a little precision (see Alfe's answer):

def isdouble(value):
    return not (1.18e-38 <= abs(value) <= 3.4e38)

or invert to test for single precision:

def issingle(value):
    return 1.18e-38 <= abs(value) <= 3.4e38:

These would prevent raising an OverflowError exception, the alternative is to just catch that.

Do note that float('-0'), float('+0'), float('inf'), float('-inf') and float('nan') will test as double with these tests; if you want these to be stored in 4 bytes rather than 8, test for these explicitly.

You can check whether a double x is exactly representable as a float by converting the float back to double and comparing the result to x.

All floats are exactly representable in double, so the back conversion involves no rounding. The result will be equal to the original double if, and only if, the float is equal to that double.

Single Precision

The IEEE single precision floating point standard representation requires a 32 bit word, which may be represented as numbered from 0 to 31, left to right.

The first bit is the sign bit, S, the next eight bits are the exponent bits, 'E', and the final 23 bits are the fraction 'F':


Double Precision

The IEEE double precision floating point standard representation requires a 64 bit word, which may be represented as numbered from 0 to 63, left to right.

The first bit is the sign bit, S, the next eleven bits are the exponent bits, 'E', and the final 52 bits are the fraction 'F':

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top