2013-11-14 9 views
2

Тип данных Python float действительно использует с двойной точностью (64 бит). Тем не менее, для моей конкретной реализации (которая передает значения с типом значений через OSC), я хотел бы различать значения, которые могут быть представлены как (32-битные) одинарные прецизионные поплавки и (64-битные) поплавки с двойной точностью.Дифференциация между одинарной и двойной точностью

Точнее, я хотел бы сделать что-то вроде этого:

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

есть ли возможный путь для достижения этой цели?

+0

Вы можете использовать NumPy 'float32' и' float64' типы. Нет никакого простого способа, AFAIK, проверить, может ли 64-битный float быть преобразован в 32 бита без потери точности. –

+0

Как вы определяете сохранение значения двойной точности как значения одной точности? Вы заботитесь о потере точности? Так же, как и многие реальные числа округлены до того же значения двойной точности, так и многие значения двойной точности округлены до одного и того же значения точности. – chepner

ответ

1

Я предлагаю просто попробовать его с помощью поплавка и если это не удается (из-за переполнения диапазона) используйте двойную версию:

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

диапазон является единственным аспектом, в котором ваш вопрос имеет смысл.

Если речь идет о точности, ваш вопрос теряет смысл, потому что, как вы говорите, Python всегда использует двойников внутренне, и даже простой 3.3 это, упаковывают и распакованы, как поплавок, только 3.299999952316284 потом:

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

Практически нет двойной может быть представлен как поплавок.(Как правило, ни один из них не является int или иным образом выходит из поплавка изначально.)

Вы можете, однако, проверить, является ли упакованная неупакованная версия вашего номера равным оригиналу, и если это так, используйте версия поплавка:

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) 
+3

Либо «Так что буквально ни один двойник не может быть представлен как поплавок» - это одно из этих новых применений «буквально», о котором я все время слышу, или вы совершенно ошибаетесь. Есть буквально 2^32 удвоения, которые могут быть представлены как float (некоторые из которых можно утверждать, что они представляют одно и то же значение). –

+1

Не переводите меня на слово «буквально» (возможно, вы правы в этом). Но из всех возможных двойных значений те, которые представлены как поплавки без отклонений, крайне редко, и что я хотел показать с помощью примера 3.3, даже те, которые мы могли бы ожидать быть представимыми, - нет. Вероятно, вы достаточно хорошо знаете о представлении с плавающей запятой, чтобы понять, почему 3.3 не так прост, как кажется, но я понял, что OP ожидал иначе. – Alfe

+0

Только около 1 из 4 миллиардов удваивается в виде поплавков. «Буквально нет» - это преувеличение, но «практически нет» верно, если OP заботится о сохранении точности. Я предполагаю, что он это делает, иначе почему бы просто не сохранить все значения как одну точность? – chepner

4

Вы можете проверить диапазон, если вы не против потери немного точности (см Alfe's answer):

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

или инвертировать, чтобы проверить для одинарной точности:

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

Эти не позволит повысить исключение OverflowError, альтернативой является просто поймать это.

Обратите внимание, что float('-0'), float('+0'), float('inf'), float('-inf') и float('nan') испытает в два раза с этими испытаниями; если вы хотите, чтобы они хранились в 4 байтах, а не в 8, проверьте их явно.

+0

Ваш тест '1.18e-38 <= abs (value) <= 3.4e38' делает его похожим на +0.0 и -0.0 не может быть представлен как float. –

+0

@PascalCuoqs: они могут быть, но этот тест заставит их закодировать как двойные. –

-1

одинарной точности

Стандарт IEEE одинарной точности с плавающей точкой стандартное представление требует 32 битового слова, которые могут быть представлены в виде пронумерованных от 0 до 31, слева направо.

Первый бит знаковый бит, S, следующие восемь битов показатель степени биты, «E» и последние 23 бита фракция «F»:


двойной точности

Стандартное представление с плавающей точкой двойной точности IEEE требует 64-битного слова, которое может быть представлено как пронумерованное от 0 до 63, слева направо.

Первый бит знаковый бит, S, следующие одиннадцать битов показатель степени биты, «E» и последние 52 бита фракция «F»:

+0

, так как я знаю, является ли 'значение', удовлетворяющее' type (value) == float', тому или другому? –

+3

Определения для котировок - это * не * помощь OP здесь. Проблема заключается не в понимании разницы, но в том, как определить, может ли Python 'float' значение (которое всегда вписывается в double) может быть закодировано до 4 байтов. –

0

Вы можете проверить, является ли двойной х точно представим в виде поплавка путем преобразования поплавка обратно в два раз, и сравнивая результат х.

Все поплавки точно представляют собой двойные, поэтому обратное преобразование не требует округления. Результат будет равен исходному двойному, если и только если float равен этому двойнику.