Поскольку вы заявляете, что вам нужна точность где-то между 'float' и 'double': вы можете обнулить любое количество младших разрядов в числах с одинарной и двойной точностью.Числа с плавающей точкой IEEE-754 представлены в двоичном виде примерно как seeefffffffff
, который представляет значение
sign * 1.fffffff * 2 ^ (eee).
Вы можете обнулить наименее значимоедробь (е) бит.Для плавающих с одинарной точностью (32-битных) имеется 23 дробных бита, из которых можно обнулить до 22. Для двойной точности (64-битных) это 52 и до 51. (Если вы обнуляете все биты, тогда специальные значения NaN и +/- inf будут потеряны).
Особенно, если данные представляют десятичные значения, такие как 1,2345, это поможет в сжатии данных.Это связано с тем, что 1.2345 нельзя представить точно как двоичное значение с плавающей запятой, а скорее как 0x3ff3c083126e978d
, что не подходит для сжатия данных.Отрезание младших значащих 24 битов приведет к 0x3ff3c08312000000
, что по-прежнему с точностью до 9 десятичных цифр (в этом примере разница составляет 1,6e-9).
Если вы сделаете это с необработанными данными, а затем сохраните различия между последовательными числами, будет еще более удобно сжатие (посредством gzip), если необработанные данные изменяются медленно.
Здесьпример в C:
#include <inttypes.h>
double double_trunc(double x, int zerobits)
{
// mask is e.g. 0xffffffffffff0000 for zerobits==16
uint64_t mask = -(1LL << zerobits);
uint64_t floatbits = (*((uint64_t*)(&x)));
floatbits &= mask;
x = * ((double*) (&floatbits));
return x;
}
и один в python / numpy:
import numpy as np
def float_trunc(a, zerobits):
"""Set the least significant <zerobits> bits to zero in a numpy float32 or float64 array.
Do this in-place. Also return the updated array.
Maximum values of 'nzero': 51 for float64; 22 for float32.
"""
at = a.dtype
assert at == np.float64 or at == np.float32 or at == np.complex128 or at == np.complex64
if at == np.float64 or at == np.complex128:
assert nzero <= 51
mask = 0xffffffffffffffff - (1 << nzero) + 1
bits = a.view(np.uint64)
bits &= mask
elif at == np.float32 or at == np.complex64:
assert nzero <= 22
mask = 0xffffffff - (1 << nzero) + 1
bits = a.view(np.uint32)
bits &= mask
return a