2016-09-01 1 views
2

У меня есть ограничение с некоторыми аппаратными средствами, с которыми я работаю, в которых я могу только передавать (без проводов) 26 символов.Можно ли уменьшить длину DateTime.Now.Ticks.ToString ("X") и сохранить уникальность?

Чтобы преодолеть это ограничение, первая передача передает временную метку, преобразованную в шестнадцатеричную (DateTime.Now.Ticks.ToString("X")), вместе с длиной передаваемого сообщения (также как шестнадцатеричная строка).

Тесты Принимающего программного обеспечения для сообщений заголовка, и когда он подтверждает, что он получает один, сохраняет метку времени (заново преобразованная в long) в словаре:

/************************************************************************* 
* _pendingMessages.Add(DateTime.Now.Ticks, Tuple.Create(MessageLength, string.Empty)); 
* T.Item1 = Message Length 
* T.Item2 = Message (when Message.Length == Length, Pop Message) 
*************************************************************************/ 
private static Dictionary<long, Tuple<long, string>> _pendingMessages; 

К сожалению, штамп времени должен быть каждый раз, и это ... более половины отведенной длины символа (сейчас у 15 символов).

Так я думал, что, вместо того, передать всю метку времени, что я мог бы быть в состоянии уменьшить его путем суммирования стоимости символов в шестнадцатеричной строки:

Для примера:

DateTime.Now.Ticks.ToSTring("X").Sum(C => C).ToString("X"); 

К сожалению, быстрый тест подорвал эту идею прочь довольно бесцеремонно

(дублирующие клавиши довольно быстро):

Dictionary<string, long> _dctTest = new Dictionary<string, long>(); 
while (true){ 
    long dtNow = DateTime.Now.Ticks; 
    string strKey = dtNow.ToString("X").Sum(C => C).ToStrings("X"); 
    _dctTest.Add(strKey, dtNow); //<=====Explodes after less than a second. 
} 

Итак, мой вопрос: есть ли способ для меня надежно уменьшить длину моего «ключа», хотя и по-прежнему (разумно), гарантируя уникальность?

+0

Выезд «G» здесь: HTTP://stackoverflow.com/questions/15072552/use-scientific-notation-only-if-needed. Вы также можете сохранить хеш http://stackoverflow.com/questions/3404715/c-sharp-hashcode-for-array-of-ints, обрабатывая каждую цифру как член массива int, например, 1234 становится int [] {1, 2,3,4}; –

+0

Какую точность вы действительно требуете? Клещи также не гарантированы быть уникальными, если вы не сделаете что-то [подобное этому] (http://stackoverflow.com/a/14369695/74757). –

+0

@ Cᴏʀʏ Да; Я видел этот пост, пока смотрел. Есть разумная задержка между передачами сообщений, так что это не так, как будто я запускаю космические челноки или что-то там, где миллисекунда означает, что вы заканчиваете курс триллионов километров или что-то в этом роде. – Will

ответ

5

Вот что-то, чтобы начать несколько ответов. Я не утверждаю, что это оптимальное решение, но я могу получить вам миллисекундную точность только с 11 символов 8 символов 7 символов кодированных данных.

Предполагая, что точность в миллисекундах достаточно хороша, мы можем уменьшить точность нашего алгоритма с самого начала. Тик представляет собой 100 наносекунд. В миллисекундах насчитывается 10 000 тиков. Вот алгоритм:

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

long centuryBegin = new DateTime(2001, 1, 1).Ticks; 
// 631139040000000000 

Теперь сделать снимок текущей метки времени:

long currentDate = DateTime.Now.Ticks; 
// 636083231371736598 

Возьмите разницу, и уменьшить точность до миллисекунды уровня:

long shortTicks = (currentDate - centuryBegin)/10000L; 
// 494419137173 

Теперь мы просто base64 закодировать строка:

string base64Ticks = Convert.ToBase64String(BitConverter.GetBytes(shortTicks)); 
// lVKtHXMAAAA= 

Однако, не вдаваясь в подробности о том, почему конечный «AAAA =» будет присутствовать на любом закодированном числе этого количества байтов, мы можем его удалить!

base64Ticks = base64Ticks.Substring(0, 7); 
// lVKtHXM 

Теперь у вас есть строка 7-символьный lVKtHXM для передачи. С другой стороны:

// Decode the base64-encoded string back into bytes 
// Note we need to add on the "AAAA=" that we stripped off  
byte[] data = new byte[8]; 
Convert.FromBase64String(base64Ticks + "AAAA=").CopyTo(data, 0); 

// From the bytes, convert back to a long, multiply by 10,000, and then 
// add on the known century begin number of ticks 
long originalTicks = (BitConverter.ToInt64(data, 0) * 10000L) + centuryBegin; 
// 636083231371730000 

Давайте посмотрим разницу между ними:

636083231371736598 (original ticks) 
-636083231371730000 (decoded ticks) 
=================== 
       6598 (difference) 

И вы можете увидеть это получает вас в 6,598 клещи, или 0.6598 миллисекунд исходной временной метки. Разница всегда будет < = 1 мс.

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

Чтобы закруглить этот пост, вот некоторые вспомогательные методы вы могли бы использовать:

public static string EncodeTransmissionTimestamp(DateTime date) 
{ 
    long shortTicks = (date.Ticks - 631139040000000000L)/10000L; 
    return Convert.ToBase64String(BitConverter.GetBytes(shortTicks)).Substring(0, 7); 
} 

public static DateTime DecodeTransmissionTimestamp(string encodedTimestamp) 
{ 
    byte[] data = new byte[8]; 
    Convert.FromBase64String(encodedTimestamp + "AAAA=").CopyTo(data, 0); 
    return new DateTime((BitConverter.ToInt64(data, 0) * 10000L) + 631139040000000000L); 
} 

Некоторые из этих работ был вдохновлен этой должности: Compress large Integers into smallest possible string

Смежные вопросы