точность конвертации в timespan

87
28 марта 2022, 17:00

При расчёте 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 нужной мне точностью?

Answer 1

Для максимальной точности можно использовать 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);
Answer 2

Решение "влоб". Пропорция. В таких случаях использовании пропорции очень помогает. У вас 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).

READ ALSO
Выборка из DataTable при помощи LINQ c суммированием

Выборка из DataTable при помощи LINQ c суммированием

Есть условная таблица payment типа DataTable, допустим, в ней есть три поля: "AccNum" (номер счета), "Payment" (платеж), "Comission" (комиссия)Задача: при помощи LINQ выбрать...

207
Разбор Json Unity C#

Разбор Json Unity C#

Работаю в UnityНужна помощь в разборе json

204
Как заменить класс без использования зависимостей от Vb.Net?

Как заменить класс без использования зависимостей от Vb.Net?

Подскажите, как можно заменить класс без использования зависимостей Visual Basic ит

238