Переменная точность с плавающей запятой / двойные значения - PullRequest
2 голосов
/ 02 февраля 2012

У меня есть объект, который я сериализирую, который содержит много двойных и структур двойных чисел, которые я посылаю по сети с protobuf-net. Проблема в том, что мне не нужна вся эта точность.

Например, у меня есть что-то вроде этого, когда внешняя библиотека возвращает double.

double Volts = Sampler.GetValue(); //Volts is a value like 4.35(...)

Но мне действительно нужны только две десятичные точки точности. Кодирование по проводам в двойном формате занимает 64 бита. Кодирование его в виде строки с двумя цифрами десятичной точности («4.35») на самом деле может занимать меньше места. Но тогда у меня есть проблемы с конверсией, которые нужно решить с обеих сторон.

Я искал варианты v2, и я не видел такой возможности. Я вижу, как можно сэкономить тонну пространства, если бы вы могли кодировать значения с плавающей запятой с переменной длиной точности.

Я думал о том, чтобы умножить на целое число, отправив его, а затем преобразовать обратно на дальний конец, но, насколько я могу судить, это потребовало бы от меня значительных изменений в объектах базового класса (и я используя параметр слияния во время десериализации).

Какие-нибудь идеи или умные обходные пути?

Кстати, protobuf-Net потрясающий с тоннами конфигурируемости. Спасибо за создание такой замечательной программы.

Ответы [ 2 ]

2 голосов
/ 02 февраля 2012

Продолжая обсуждение «возможно, отправьте их как float», вы можете сделать это довольно легко, на самом деле; например, если у вас есть:

[ProtoMember(4)]
public double Value {get;set;}

Вы можете изменить это на:

public double Value {get;set;} // this won't be serialized directly

[Protomember(4)] // but we'll use this private property for the serialization
private float ValueSingle {
    get { return (float)Value; }
    set { Value = value; }
}

и он подойдет для вас на заднем плане. Это конкретное изменение также должно быть совместимо с существующими данными (хотя технически оно меняет схему .proto, protobuf-net довольно простителен). Это займет 4 байта. Также обратите внимание, что IEEE754 применяется, как всегда, поэтому полностью не связан с protobuf-net , и нет гарантии, что какое-либо конкретное значение (например, 4.35) может быть сохранено точно .

Другой вариант, если вы хотите фиксированную точность, это использовать кратное число. Например:

public double Value {get;set;}

[ProtoMember(4)]
public int ValueInt32 {
    get { return (int)Math.Round(100 * Value); }
    set { Value = value/100.0; }
}

Вам нужно проверить, совместимо ли это со старыми данными ... это большее изменение. Здесь, 4.35 будет отправлено как 435, что занимает 2 байта как "varint".

2 голосов
/ 02 февраля 2012

Сериализация ваших данных в виде строк звучит как плохая идея.

Двойные значения уже имеют только 64-битное значение (см. Кодировка буферов протокола , тип провода 1), текст передается как UTF-8, поэтому даже в вашем упрощенном примере 4.35 вам потребуется 32-битнаяперевести, не говоря уже об усилиях по преобразованию его обратно в двойное число при десериализации и о кошмаре общего обслуживания, когда кто-то смотрит на этот код.

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

...