При расчёте PCR в MPEG-TS пакетах столкнулся с проблемой недостаточной точности переменной типа double.
ulong bytes = 0x35BF1E56FF22;
ulong a = (bytes >> 15)*300; // 90Khz component, first 33 bit of value
Debug.WriteLine($"{a.ToString("X")}");
ulong b = (bytes & 0x1ff); // 27Mhz component, last 9 bit of value
Debug.WriteLine($"{b.ToString("X")}");
double tmp = a + b;
tmp /= 27000000;
TimeSpan timeSpan = TimeSpan.FromSeconds(tmp);
Console.WriteLine($"result {timeSpan.ToString(@"hh\:mm\:ss\.ffffff")}");
В выводе получаю значение result 05:33:58.169000
тут значение должно быть 5:33:58.168688
Проблема в том, что точность double не достаточна. нужно использовать decimal.
Как перевести decimal в TimeSpan c нужной мне точностью?
Для максимальной точности можно использовать TimeSpan.FromTicks
:
double t = (a+b) / 2.7;
TimeSpan timeSpan = TimeSpan.FromTicks((long) t);
//result 05:33:58.168688
Console.WriteLine($"result {timeSpan.ToString(@"hh\:mm\:ss\.ffffff")}");
т.к. делитель меньше, то и точности double скорее всего хватит, но можно использовать и decimal, либо вообще обойтись целочисленными типами:
ulong t = (a+b)*10/27;
timeSpan = TimeSpan.FromTicks((long) t);
Решение "влоб". Пропорция. В таких случаях использовании пропорции очень помогает. У вас 27000000 - делимое. Значит остаток на еденицу меньше. После точки у вас какое макс значение (какая у вас основа)? Пишите пропорцию, и по-пропорции получите правильное число. Например если у вас макс число после точки 999999 то пимем (tmp%27000000)/27000000=x/1000000 выводим и считаем х. Слева tmp%27000000 будет принимать значения от 0 до 26999999 (т.е. это остаток), а справа х будет принимать значения от 0 до 999999 согласно пропорции. Я могу ошибится и вместо 1000000 возможно у вас основание 600000. Согласно пропорции - расчёты будут целочисленные, на выходе будет целочисленное число с достаточно хорошей точностью. Т.е. x=(tmp%27000000*основа)/27000000. Подобным образом можно привести число под любое основание.
ulong bytes = 0x35BF1E56FF22;
Считаю ваше tmp у меня вышло 541030554590.
Дописываю long x = tmp%27000000*1000000 /27000000;
Получаем x=168688
P.S. Путём "небольших преобразований", а именно, сокращения дробей, мы прийдем к ответу похожему на другой ответ в этом вопросе (по крайней мере к числу 2.7).
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Есть условная таблица payment типа DataTable, допустим, в ней есть три поля: "AccNum" (номер счета), "Payment" (платеж), "Comission" (комиссия)Задача: при помощи LINQ выбрать...
Подскажите, как можно заменить класс без использования зависимостей Visual Basic ит